diff options
Diffstat (limited to 'drivers/usb/serial')
77 files changed, 12563 insertions, 13954 deletions
diff --git a/drivers/usb/serial/ChangeLog.history b/drivers/usb/serial/ChangeLog.history deleted file mode 100644 index f13fd488ebe..00000000000 --- a/drivers/usb/serial/ChangeLog.history +++ /dev/null @@ -1,730 +0,0 @@ -This is the contents of some of the drivers/usb/serial/ files that had old -changelog comments. They were quite old, and out of date, and we don't keep -them anymore, so I've put them here, away from the source files, in case -people still care to see them. - -- Greg Kroah-Hartman <greg@kroah.com> October 20, 2005 - ------------------------------------------------------------------------ -usb-serial.h Change Log comments: - - (03/26/2002) gkh - removed the port->tty check from port_paranoia_check() due to serial - consoles not having a tty device assigned to them. - - (12/03/2001) gkh - removed active from the port structure. - added documentation to the usb_serial_device_type structure - - (10/10/2001) gkh - added vendor and product to serial structure. Needed to determine device - owner when the device is disconnected. - - (05/30/2001) gkh - added sem to port structure and removed port_lock - - (10/05/2000) gkh - Added interrupt_in_endpointAddress and bulk_in_endpointAddress to help - fix bug with urb->dev not being set properly, now that the usb core - needs it. - - (09/11/2000) gkh - Added usb_serial_debug_data function to help get rid of #DEBUG in the - drivers. - - (08/28/2000) gkh - Added port_lock to port structure. - - (08/08/2000) gkh - Added open_count to port structure. - - (07/23/2000) gkh - Added bulk_out_endpointAddress to port structure. - - (07/19/2000) gkh, pberger, and borchers - Modifications to allow usb-serial drivers to be modules. - ------------------------------------------------------------------------ -usb-serial.c Change Log comments: - - (12/10/2002) gkh - Split the ports off into their own struct device, and added a - usb-serial bus driver. - - (11/19/2002) gkh - removed a few #ifdefs for the generic code and cleaned up the failure - logic in initialization. - - (10/02/2002) gkh - moved the console code to console.c and out of this file. - - (06/05/2002) gkh - moved location of startup() call in serial_probe() until after all - of the port information and endpoints are initialized. This makes - things easier for some drivers. - - (04/10/2002) gkh - added serial_read_proc function which creates a - /proc/tty/driver/usb-serial file. - - (03/27/2002) gkh - Got USB serial console code working properly and merged into the main - version of the tree. Thanks to Randy Dunlap for the initial version - of this code, and for pushing me to finish it up. - The USB serial console works with any usb serial driver device. - - (03/21/2002) gkh - Moved all manipulation of port->open_count into the core. Now the - individual driver's open and close functions are called only when the - first open() and last close() is called. Making the drivers a bit - smaller and simpler. - Fixed a bug if a driver didn't have the owner field set. - - (02/26/2002) gkh - Moved all locking into the main serial_* functions, instead of having - the individual drivers have to grab the port semaphore. This should - reduce races. - Reworked the MOD_INC logic a bit to always increment and decrement, even - if the generic driver is being used. - - (10/10/2001) gkh - usb_serial_disconnect() now sets the serial->dev pointer is to NULL to - help prevent child drivers from accessing the device since it is now - gone. - - (09/13/2001) gkh - Moved generic driver initialize after we have registered with the USB - core. Thanks to Randy Dunlap for pointing this problem out. - - (07/03/2001) gkh - Fixed module paramater size. Thanks to John Brockmeyer for the pointer. - Fixed vendor and product getting defined through the MODULE_PARM macro - if the Generic driver wasn't compiled in. - Fixed problem with generic_shutdown() not being called for drivers that - don't have a shutdown() function. - - (06/06/2001) gkh - added evil hack that is needed for the prolific pl2303 device due to the - crazy way its endpoints are set up. - - (05/30/2001) gkh - switched from using spinlock to a semaphore, which fixes lots of problems. - - (04/08/2001) gb - Identify version on module load. - - 2001_02_05 gkh - Fixed buffer overflows bug with the generic serial driver. Thanks to - Todd Squires <squirest@ct0.com> for fixing this. - - (01/10/2001) gkh - Fixed bug where the generic serial adaptor grabbed _any_ device that was - offered to it. - - (12/12/2000) gkh - Removed MOD_INC and MOD_DEC from poll and disconnect functions, and - moved them to the serial_open and serial_close functions. - Also fixed bug with there not being a MOD_DEC for the generic driver - (thanks to Gary Brubaker for finding this.) - - (11/29/2000) gkh - Small NULL pointer initialization cleanup which saves a bit of disk image - - (11/01/2000) Adam J. Richter - instead of using idVendor/idProduct pairs, usb serial drivers - now identify their hardware interest with usb_device_id tables, - which they usually have anyhow for use with MODULE_DEVICE_TABLE. - - (10/05/2000) gkh - Fixed bug with urb->dev not being set properly, now that the usb - core needs it. - - (09/11/2000) gkh - Removed DEBUG #ifdefs with call to usb_serial_debug_data - - (08/28/2000) gkh - Added port_lock to port structure. - Added locks for SMP safeness to generic driver - Fixed the ability to open a generic device's port more than once. - - (07/23/2000) gkh - Added bulk_out_endpointAddress to port structure. - - (07/19/2000) gkh, pberger, and borchers - Modifications to allow usb-serial drivers to be modules. - - (07/03/2000) gkh - Added more debugging to serial_ioctl call - - (06/25/2000) gkh - Changed generic_write_bulk_callback to not call wake_up_interruptible - directly, but to have port_softint do it at a safer time. - - (06/23/2000) gkh - Cleaned up debugging statements in a quest to find UHCI timeout bug. - - (05/22/2000) gkh - Changed the makefile, enabling the big CONFIG_USB_SERIAL_SOMTHING to be - removed from the individual device source files. - - (05/03/2000) gkh - Added the Digi Acceleport driver from Al Borchers and Peter Berger. - - (05/02/2000) gkh - Changed devfs and tty register code to work properly now. This was based on - the ACM driver changes by Vojtech Pavlik. - - (04/27/2000) Ryan VanderBijl - Put calls to *_paranoia_checks into one function. - - (04/23/2000) gkh - Fixed bug that Randy Dunlap found for Generic devices with no bulk out ports. - Moved when the startup code printed out the devices that are supported. - - (04/19/2000) gkh - Added driver for ZyXEL omni.net lcd plus ISDN TA - Made startup info message specify which drivers were compiled in. - - (04/03/2000) gkh - Changed the probe process to remove the module unload races. - Changed where the tty layer gets initialized to have devfs work nicer. - Added initial devfs support. - - (03/26/2000) gkh - Split driver up into device specific pieces. - - (03/19/2000) gkh - Fixed oops that could happen when device was removed while a program - was talking to the device. - Removed the static urbs and now all urbs are created and destroyed - dynamically. - Reworked the internal interface. Now everything is based on the - usb_serial_port structure instead of the larger usb_serial structure. - This fixes the bug that a multiport device could not have more than - one port open at one time. - - (03/17/2000) gkh - Added config option for debugging messages. - Added patch for keyspan pda from Brian Warner. - - (03/06/2000) gkh - Added the keyspan pda code from Brian Warner <warner@lothar.com> - Moved a bunch of the port specific stuff into its own structure. This - is in anticipation of the true multiport devices (there's a bug if you - try to access more than one port of any multiport device right now) - - (02/21/2000) gkh - Made it so that any serial devices only have to specify which functions - they want to overload from the generic function calls (great, - inheritance in C, in a driver, just what I wanted...) - Added support for set_termios and ioctl function calls. No drivers take - advantage of this yet. - Removed the #ifdef MODULE, now there is no module specific code. - Cleaned up a few comments in usb-serial.h that were wrong (thanks again - to Miles Lott). - Small fix to get_free_serial. - - (02/14/2000) gkh - Removed the Belkin and Peracom functionality from the driver due to - the lack of support from the vendor, and me not wanting people to - accidenatly buy the device, expecting it to work with Linux. - Added read_bulk_callback and write_bulk_callback to the type structure - for the needs of the FTDI and WhiteHEAT driver. - Changed all reverences to FTDI to FTDI_SIO at the request of Bill - Ryder. - Changed the output urb size back to the max endpoint size to make - the ftdi_sio driver have it easier, and due to the fact that it didn't - really increase the speed any. - - (02/11/2000) gkh - Added VISOR_FUNCTION_CONSOLE to the visor startup function. This was a - patch from Miles Lott (milos@insync.net). - Fixed bug with not restoring the minor range that a device grabs, if - the startup function fails (thanks Miles for finding this). - - (02/05/2000) gkh - Added initial framework for the Keyspan PDA serial converter so that - Brian Warner has a place to put his code. - Made the ezusb specific functions generic enough that different - devices can use them (whiteheat and keyspan_pda both need them). - Split out a whole bunch of structure and other stuff to a separate - usb-serial.h file. - Made the Visor connection messages a little more understandable, now - that Miles Lott (milos@insync.net) has gotten the Generic channel to - work. Also made them always show up in the log file. - - (01/25/2000) gkh - Added initial framework for FTDI serial converter so that Bill Ryder - has a place to put his code. - Added the vendor specific info from Handspring. Now we can print out - informational debug messages as well as understand what is happening. - - (01/23/2000) gkh - Fixed problem of crash when trying to open a port that didn't have a - device assigned to it. Made the minor node finding a little smarter, - now it looks to find a continuous space for the new device. - - (01/21/2000) gkh - Fixed bug in visor_startup with patch from Miles Lott (milos@insync.net) - Fixed get_serial_by_minor which was all messed up for multi port - devices. Fixed multi port problem for generic devices. Now the number - of ports is determined by the number of bulk out endpoints for the - generic device. - - (01/19/2000) gkh - Removed lots of cruft that was around from the old (pre urb) driver - interface. - Made the serial_table dynamic. This should save lots of memory when - the number of minor nodes goes up to 256. - Added initial support for devices that have more than one port. - Added more debugging comments for the Visor, and added a needed - set_configuration call. - - (01/17/2000) gkh - Fixed the WhiteHEAT firmware (my processing tool had a bug) - and added new debug loader firmware for it. - Removed the put_char function as it isn't really needed. - Added visor startup commands as found by the Win98 dump. - - (01/13/2000) gkh - Fixed the vendor id for the generic driver to the one I meant it to be. - - (01/12/2000) gkh - Forget the version numbering...that's pretty useless... - Made the driver able to be compiled so that the user can select which - converter they want to use. This allows people who only want the Visor - support to not pay the memory size price of the WhiteHEAT. - Fixed bug where the generic driver (idVendor=0000 and idProduct=0000) - grabbed the root hub. Not good. - - version 0.4.0 (01/10/2000) gkh - Added whiteheat.h containing the firmware for the ConnectTech WhiteHEAT - device. Added startup function to allow firmware to be downloaded to - a device if it needs to be. - Added firmware download logic to the WhiteHEAT device. - Started to add #defines to split up the different drivers for potential - configuration option. - - version 0.3.1 (12/30/99) gkh - Fixed problems with urb for bulk out. - Added initial support for multiple sets of endpoints. This enables - the Handspring Visor to be attached successfully. Only the first - bulk in / bulk out endpoint pair is being used right now. - - version 0.3.0 (12/27/99) gkh - Added initial support for the Handspring Visor based on a patch from - Miles Lott (milos@sneety.insync.net) - Cleaned up the code a bunch and converted over to using urbs only. - - version 0.2.3 (12/21/99) gkh - Added initial support for the Connect Tech WhiteHEAT converter. - Incremented the number of ports in expectation of getting the - WhiteHEAT to work properly (4 ports per connection). - Added notification on insertion and removal of what port the - device is/was connected to (and what kind of device it was). - - version 0.2.2 (12/16/99) gkh - Changed major number to the new allocated number. We're legal now! - - version 0.2.1 (12/14/99) gkh - Fixed bug that happens when device node is opened when there isn't a - device attached to it. Thanks to marek@webdesign.no for noticing this. - - version 0.2.0 (11/10/99) gkh - Split up internals to make it easier to add different types of serial - converters to the code. - Added a "generic" driver that gets it's vendor and product id - from when the module is loaded. Thanks to David E. Nelson (dnelson@jump.net) - for the idea and sample code (from the usb scanner driver.) - Cleared up any licensing questions by releasing it under the GNU GPL. - - version 0.1.2 (10/25/99) gkh - Fixed bug in detecting device. - - version 0.1.1 (10/05/99) gkh - Changed the major number to not conflict with anything else. - - version 0.1 (09/28/99) gkh - Can recognize the two different devices and start up a read from - device when asked to. Writes also work. No control signals yet, this - all is vendor specific data (i.e. no spec), also no control for - different baud rates or other bit settings. - Currently we are using the same devid as the acm driver. This needs - to change. - ------------------------------------------------------------------------ -visor.c Change Log comments: - - (06/03/2003) Judd Montgomery <judd at jpilot.org> - Added support for module parameter options for untested/unknown - devices. - - (03/09/2003) gkh - Added support for the Sony Clie NZ90V device. Thanks to Martin Brachtl - <brachtl@redgrep.cz> for the information. - - (03/05/2003) gkh - Think Treo support is now working. - - (04/03/2002) gkh - Added support for the Sony OS 4.1 devices. Thanks to Hiroyuki ARAKI - <hiro@zob.ne.jp> for the information. - - (03/27/2002) gkh - Removed assumptions that port->tty was always valid (is not true - for usb serial console devices.) - - (03/23/2002) gkh - Added support for the Palm i705 device, thanks to Thomas Riemer - <tom@netmech.com> for the information. - - (03/21/2002) gkh - Added support for the Palm m130 device, thanks to Udo Eisenbarth - <udo.eisenbarth@web.de> for the information. - - (02/27/2002) gkh - Reworked the urb handling logic. We have no more pool, but dynamically - allocate the urb and the transfer buffer on the fly. In testing this - does not incure any measurable overhead. This also relies on the fact - that we have proper reference counting logic for urbs. - - (02/21/2002) SilaS - Added initial support for the Palm m515 devices. - - (02/14/2002) gkh - Added support for the Clie S-360 device. - - (12/18/2001) gkh - Added better Clie support for 3.5 devices. Thanks to Geoffrey Levand - for the patch. - - (11/11/2001) gkh - Added support for the m125 devices, and added check to prevent oopses - for CliĆ© devices that lie about the number of ports they have. - - (08/30/2001) gkh - Added support for the Clie devices, both the 3.5 and 4.0 os versions. - Many thanks to Daniel Burke, and Bryan Payne for helping with this. - - (08/23/2001) gkh - fixed a few potential bugs pointed out by Oliver Neukum. - - (05/30/2001) gkh - switched from using spinlock to a semaphore, which fixes lots of problems. - - (05/28/2000) gkh - Added initial support for the Palm m500 and Palm m505 devices. - - (04/08/2001) gb - Identify version on module load. - - (01/21/2000) gkh - Added write_room and chars_in_buffer, as they were previously using the - generic driver versions which is all wrong now that we are using an urb - pool. Thanks to Wolfgang Grandegger for pointing this out to me. - Removed count assignment in the write function, which was not needed anymore - either. Thanks to Al Borchers for pointing this out. - - (12/12/2000) gkh - Moved MOD_DEC to end of visor_close to be nicer, as the final write - message can sleep. - - (11/12/2000) gkh - Fixed bug with data being dropped on the floor by forcing tty->low_latency - to be on. Hopefully this fixes the OHCI issue! - - (11/01/2000) Adam J. Richter - usb_device_id table support - - (10/05/2000) gkh - Fixed bug with urb->dev not being set properly, now that the usb - core needs it. - - (09/11/2000) gkh - Got rid of always calling kmalloc for every urb we wrote out to the - device. - Added visor_read_callback so we can keep track of bytes in and out for - those people who like to know the speed of their device. - Removed DEBUG #ifdefs with call to usb_serial_debug_data - - (09/06/2000) gkh - Fixed oops in visor_exit. Need to uncomment usb_unlink_urb call _after_ - the host controller drivers set urb->dev = NULL when the urb is finished. - - (08/28/2000) gkh - Added locks for SMP safeness. - - (08/08/2000) gkh - Fixed endian problem in visor_startup. - Fixed MOD_INC and MOD_DEC logic and the ability to open a port more - than once. - - (07/23/2000) gkh - Added pool of write urbs to speed up transfers to the visor. - - (07/19/2000) gkh - Added module_init and module_exit functions to handle the fact that this - driver is a loadable module now. - - (07/03/2000) gkh - Added visor_set_ioctl and visor_set_termios functions (they don't do much - of anything, but are good for debugging.) - - (06/25/2000) gkh - Fixed bug in visor_unthrottle that should help with the disconnect in PPP - bug that people have been reporting. - - (06/23/2000) gkh - Cleaned up debugging statements in a quest to find UHCI timeout bug. - - (04/27/2000) Ryan VanderBijl - Fixed memory leak in visor_close - - (03/26/2000) gkh - Split driver up into device specific pieces. - ------------------------------------------------------------------------ -pl2303.c Change Log comments: - - 2002_Mar_26 gkh - allowed driver to work properly if there is no tty assigned to a port - (this happens for serial console devices.) - - 2001_Oct_06 gkh - Added RTS and DTR line control. Thanks to joe@bndlg.de for parts of it. - - 2001_Sep_19 gkh - Added break support. - - 2001_Aug_30 gkh - fixed oops in write_bulk_callback. - - 2001_Aug_28 gkh - reworked buffer logic to be like other usb-serial drivers. Hopefully - removing some reported problems. - - 2001_Jun_06 gkh - finished porting to 2.4 format. - - ------------------------------------------------------------------------ -io_edgeport.c Change Log comments: - - 2003_04_03 al borchers - - fixed a bug (that shows up with dosemu) where the tty struct is - used in a callback after it has been freed - - 2.3 2002_03_08 greg kroah-hartman - - fixed bug when multiple devices were attached at the same time. - - 2.2 2001_11_14 greg kroah-hartman - - fixed bug in edge_close that kept the port from being used more - than once. - - fixed memory leak on device removal. - - fixed potential double free of memory when command urb submitting - failed. - - other small cleanups when the device is removed - - 2.1 2001_07_09 greg kroah-hartman - - added support for TIOCMBIS and TIOCMBIC. - - (04/08/2001) gb - - Identify version on module load. - - 2.0 2001_03_05 greg kroah-hartman - - reworked entire driver to fit properly in with the other usb-serial - drivers. Occasional oopses still happen, but it's a good start. - - 1.2.3 (02/23/2001) greg kroah-hartman - - changed device table to work properly for 2.4.x final format. - - fixed problem with dropping data at high data rates. - - 1.2.2 (11/27/2000) greg kroah-hartman - - cleaned up more NTisms. - - Added device table for 2.4.0-test11 - - 1.2.1 (11/08/2000) greg kroah-hartman - - Started to clean up NTisms. - - Fixed problem with dev field of urb for kernels >= 2.4.0-test9 - - 1.2 (10/17/2000) David Iacovelli - Remove all EPIC code and GPL source - Fix RELEVANT_IFLAG macro to include flow control - changes port configuration changes. - Fix redefinition of SERIAL_MAGIC - Change all timeout values to 5 seconds - Tried to fix the UHCI multiple urb submission, but failed miserably. - it seems to work fine with OHCI. - ( Greg take a look at the #if 0 at end of WriteCmdUsb() we must - find a way to work arount this UHCI bug ) - - 1.1 (10/11/2000) David Iacovelli - Fix XON/XOFF flow control to support both IXON and IXOFF - - 0.9.27 (06/30/2000) David Iacovelli - Added transmit queue and now allocate urb for command writes. - - 0.9.26 (06/29/2000) David Iacovelli - Add support for 80251 based edgeport - - 0.9.25 (06/27/2000) David Iacovelli - Do not close the port if it has multiple opens. - - 0.9.24 (05/26/2000) David Iacovelli - Add IOCTLs to support RXTX and JAVA POS - and first cut at running BlackBox Demo - - 0.9.23 (05/24/2000) David Iacovelli - Add IOCTLs to support RXTX and JAVA POS - - 0.9.22 (05/23/2000) David Iacovelli - fixed bug in enumeration. If epconfig turns on mapping by - path after a device is already plugged in, we now update - the mapping correctly - - 0.9.21 (05/16/2000) David Iacovelli - Added BlockUntilChaseResp() to also wait for txcredits - Updated the way we allocate and handle write URBs - Add debug code to dump buffers - - 0.9.20 (05/01/2000) David Iacovelli - change driver to use usb/tts/ - - 0.9.19 (05/01/2000) David Iacovelli - Update code to compile if DEBUG is off - - 0.9.18 (04/28/2000) David Iacovelli - cleanup and test tty_register with devfs - - 0.9.17 (04/27/2000) greg kroah-hartman - changed tty_register around to be like the way it - was before, but now it works properly with devfs. - - 0.9.16 (04/26/2000) david iacovelli - Fixed bug in GetProductInfo() - - 0.9.15 (04/25/2000) david iacovelli - Updated enumeration - - 0.9.14 (04/24/2000) david iacovelli - Removed all config/status IOCTLS and - converted to using /proc/edgeport - still playing with devfs - - 0.9.13 (04/24/2000) david iacovelli - Removed configuration based on ttyUSB0 - Added support for configuration using /prod/edgeport - first attempt at using devfs (not working yet!) - Added IOCTL to GetProductInfo() - Added support for custom baud rates - Add support for random port numbers - - 0.9.12 (04/18/2000) david iacovelli - added additional configuration IOCTLs - use ttyUSB0 for configuration - - 0.9.11 (04/17/2000) greg kroah-hartman - fixed module initialization race conditions. - made all urbs dynamically allocated. - made driver devfs compatible. now it only registers the tty device - when the device is actually plugged in. - - 0.9.10 (04/13/2000) greg kroah-hartman - added proc interface framework. - - 0.9.9 (04/13/2000) david iacovelli - added enumeration code and ioctls to configure the device - - 0.9.8 (04/12/2000) david iacovelli - Change interrupt read start when device is plugged in - and stop when device is removed - process interrupt reads when all ports are closed - (keep value of rxBytesAvail consistent with the edgeport) - set the USB_BULK_QUEUE flag so that we can shove a bunch - of urbs at once down the pipe - - 0.9.7 (04/10/2000) david iacovelli - start to add enumeration code. - generate serial number for epic devices - add support for kdb - - 0.9.6 (03/30/2000) david iacovelli - add IOCTL to get string, manufacture, and boot descriptors - - 0.9.5 (03/14/2000) greg kroah-hartman - more error checking added to SerialOpen to try to fix UHCI open problem - - 0.9.4 (03/09/2000) greg kroah-hartman - added more error checking to handle oops when data is hanging - around and tty is abruptly closed. - - 0.9.3 (03/09/2000) david iacovelli - Add epic support for xon/xoff chars - play with performance - - 0.9.2 (03/08/2000) greg kroah-hartman - changed most "info" calls to "dbg" - implemented flow control properly in the termios call - - 0.9.1 (03/08/2000) david iacovelli - added EPIC support - enabled bootloader update - - 0.9 (03/08/2000) greg kroah-hartman - Release to IO networks. - Integrated changes that David made - made getting urbs for writing SMP safe - - 0.8 (03/07/2000) greg kroah-hartman - Release to IO networks. - Fixed problems that were seen in code by David. - Now both Edgeport/4 and Edgeport/2 works properly. - Changed most of the functions to use port instead of serial. - - 0.7 (02/27/2000) greg kroah-hartman - Milestone 3 release. - Release to IO Networks - ioctl for waiting on line change implemented. - ioctl for getting statistics implemented. - multiport support working. - lsr and msr registers are now handled properly. - change break now hooked up and working. - support for all known Edgeport devices. - - 0.6 (02/22/2000) greg kroah-hartman - Release to IO networks. - CHASE is implemented correctly when port is closed. - SerialOpen now blocks correctly until port is fully opened. - - 0.5 (02/20/2000) greg kroah-hartman - Release to IO networks. - Known problems: - modem status register changes are not sent on to the user - CHASE is not implemented when the port is closed. - - 0.4 (02/16/2000) greg kroah-hartman - Second cut at the CeBit demo. - Doesn't leak memory on every write to the port - Still small leaks on startup. - Added support for Edgeport/2 and Edgeport/8 - - 0.3 (02/15/2000) greg kroah-hartman - CeBit demo release. - Force the line settings to 4800, 8, 1, e for the demo. - Warning! This version leaks memory like crazy! - - 0.2 (01/30/2000) greg kroah-hartman - Milestone 1 release. - Device is found by USB subsystem, enumerated, firmware is downloaded - and the descriptors are printed to the debug log, config is set, and - green light starts to blink. Open port works, and data can be sent - and received at the default settings of the UART. Loopback connector - and debug log confirms this. - - 0.1 (01/23/2000) greg kroah-hartman - Initial release to help IO Networks try to set up their test system. - Edgeport4 is recognized, firmware is downloaded, config is set so - device blinks green light every 3 sec. Port is bound, but opening, - closing, and sending data do not work properly. - - diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index c2b29761fa9..3ce5c74b29e 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig @@ -4,7 +4,7 @@ menuconfig USB_SERIAL tristate "USB Serial Converter support" - depends on USB + depends on TTY ---help--- Say Y here if you have a USB device that provides normal serial ports, or acts like a serial device, and you want to connect it to @@ -42,11 +42,6 @@ config USB_SERIAL_CONSOLE If unsure, say N. -config USB_EZUSB - bool "Functions for loading firmware on EZUSB chips" - help - Say Y here if you need EZUSB device support. - config USB_SERIAL_GENERIC bool "USB Generic Serial Driver" help @@ -56,6 +51,24 @@ config USB_SERIAL_GENERIC support" be compiled as a module for this driver to be used properly. +config USB_SERIAL_SIMPLE + tristate "USB Serial Simple Driver" + help + Say Y here to use the USB serial "simple" driver. This driver + handles a wide range of very simple devices, all in one + driver. Specifically, it supports: + - Suunto ANT+ USB device. + - Fundamental Software dongle. + - HP4x calculators + - a number of Motorola phones + - Siemens USB/MPI adapter. + - ViVOtech ViVOpay USB device. + - Infineon Modem Flashloader USB interface + - ZIO Motherboard USB serial interface + + To compile this driver as a module, choose M here: the module + will be called usb-serial-simple. + config USB_SERIAL_AIRCABLE tristate "USB AIRcable Bluetooth Dongle Driver" help @@ -94,7 +107,7 @@ config USB_SERIAL_CH341 config USB_SERIAL_WHITEHEAT tristate "USB ConnectTech WhiteHEAT Serial Driver" - select USB_EZUSB + select USB_EZUSB_FX2 help Say Y here if you want to use a ConnectTech WhiteHEAT 4 port USB to serial converter device. @@ -163,14 +176,6 @@ config USB_SERIAL_FTDI_SIO To compile this driver as a module, choose M here: the module will be called ftdi_sio. -config USB_SERIAL_FUNSOFT - tristate "USB Fundamental Software Dongle Driver" - ---help--- - Say Y here if you want to use the Fundamental Software dongle. - - To compile this driver as a module, choose M here: the - module will be called funsoft. - config USB_SERIAL_VISOR tristate "USB Handspring Visor / Palm m50x / Sony Clie Driver" help @@ -238,6 +243,15 @@ config USB_SERIAL_EDGEPORT_TI To compile this driver as a module, choose M here: the module will be called io_ti. +config USB_SERIAL_F81232 + tristate "USB Fintek F81232 Single Port Serial Driver" + help + Say Y here if you want to use the Fintek F81232 single + port usb to serial adapter. + + To compile this driver as a module, choose M here: the + module will be called f81232. + config USB_SERIAL_GARMIN tristate "USB Garmin GPS driver" help @@ -252,6 +266,7 @@ config USB_SERIAL_GARMIN config USB_SERIAL_IPW tristate "USB IPWireless (3G UMTS TDD) Driver" + select USB_SERIAL_WWAN help Say Y here if you want to use a IPWireless USB modem such as the ones supplied by Axity3G/Sentech South Africa. @@ -271,7 +286,7 @@ config USB_SERIAL_IUU config USB_SERIAL_KEYSPAN_PDA tristate "USB Keyspan PDA Single Port Serial Driver" - select USB_EZUSB + select USB_EZUSB_FX2 help Say Y here if you want to use a Keyspan PDA single port USB to serial converter device. This driver makes use of firmware @@ -282,7 +297,7 @@ config USB_SERIAL_KEYSPAN_PDA config USB_SERIAL_KEYSPAN tristate "USB Keyspan USA-xxx Serial Driver" - select USB_EZUSB + select USB_EZUSB_FX2 ---help--- Say Y here if you want to use Keyspan USB to serial converter devices. This driver makes use of Keyspan's official firmware @@ -416,6 +431,14 @@ config USB_SERIAL_MCT_U232 To compile this driver as a module, choose M here: the module will be called mct_u232. +config USB_SERIAL_METRO + tristate "USB Metrologic Instruments USB-POS Barcode Scanner Driver" + ---help--- + Say Y here if you want to use a USB POS Metrologic barcode scanner. + + To compile this driver as a module, choose M here: the + module will be called metro-usb. + config USB_SERIAL_MOS7720 tristate "USB Moschip 7720 Serial Driver" ---help--- @@ -449,14 +472,34 @@ config USB_SERIAL_MOS7840 To compile this driver as a module, choose M here: the module will be called mos7840. If unsure, choose N. -config USB_SERIAL_MOTOROLA - tristate "USB Motorola Phone modem driver" +config USB_SERIAL_MXUPORT + tristate "USB Moxa UPORT Serial Driver" ---help--- - Say Y here if you want to use a Motorola phone with a USB - connector as a modem link. + Say Y here if you want to use a MOXA UPort Serial hub. + + This driver supports: + + [2 Port] + - UPort 1250 : 2 Port RS-232/422/485 USB to Serial Hub + - UPort 1250I : 2 Port RS-232/422/485 USB to Serial Hub with + Isolation + + [4 Port] + - UPort 1410 : 4 Port RS-232 USB to Serial Hub + - UPort 1450 : 4 Port RS-232/422/485 USB to Serial Hub + - UPort 1450I : 4 Port RS-232/422/485 USB to Serial Hub with + Isolation + + [8 Port] + - UPort 1610-8 : 8 Port RS-232 USB to Serial Hub + - UPort 1650-8 : 8 Port RS-232/422/485 USB to Serial Hub + + [16 Port] + - UPort 1610-16 : 16 Port RS-232 USB to Serial Hub + - UPort 1650-16 : 16 Port RS-232/422/485 USB to Serial Hub To compile this driver as a module, choose M here: the - module will be called moto_modem. If unsure, choose N. + module will be called mxuport. config USB_SERIAL_NAVMAN tristate "USB Navman GPS device" @@ -512,14 +555,6 @@ config USB_SERIAL_SPCP8X5 To compile this driver as a module, choose M here: the module will be called spcp8x5. -config USB_SERIAL_HP4X - tristate "USB HP4x Calculators support" - help - Say Y here if you want to use an Hewlett-Packard 4x Calculator. - - To compile this driver as a module, choose M here: the - module will be called hp4x. - config USB_SERIAL_SAFE tristate "USB Safe Serial (Encapsulated) Driver" @@ -527,23 +562,6 @@ config USB_SERIAL_SAFE_PADDED bool "USB Secure Encapsulated Driver - Padded" depends on USB_SERIAL_SAFE -config USB_SERIAL_SAMBA - tristate "USB Atmel SAM Boot Assistant (SAM-BA) driver" - help - Say Y here if you want to access the SAM-BA boot application of an - Atmel AT91SAM device. - - To compile this driver as a module, choose M here: the - module will be called sam-ba. - -config USB_SERIAL_SIEMENS_MPI - tristate "USB Siemens MPI driver" - help - Say M here if you want to use a Siemens USB/MPI adapter. - - To compile this driver as a module, choose M here: the - module will be called siemens_mpi. - config USB_SERIAL_SIERRAWIRELESS tristate "USB Sierra Wireless Driver" help @@ -587,7 +605,7 @@ config USB_SERIAL_CYBERJACK config USB_SERIAL_XIRCOM tristate "USB Xircom / Entregra Single Port Serial Driver" - select USB_EZUSB + select USB_EZUSB_FX2 help Say Y here if you want to use a Xircom or Entregra single port USB to serial converter device. This driver makes use of firmware @@ -635,21 +653,42 @@ config USB_SERIAL_OPTICON To compile this driver as a module, choose M here: the module will be called opticon. -config USB_SERIAL_VIVOPAY_SERIAL - tristate "USB ViVOpay serial interface driver" - help - Say Y here if you want to use a ViVOtech ViVOpay USB device. +config USB_SERIAL_XSENS_MT + tristate "Xsens motion tracker serial interface driver" + help + Say Y here if you want to use Xsens motion trackers. - To compile this driver as a module, choose M here: the - module will be called vivopay-serial. + This driver supports the new generation of motion trackers + by Xsens. Older devices can be accessed using the FTDI_SIO + driver. -config USB_SERIAL_ZIO - tristate "ZIO Motherboard USB serial interface driver" + To compile this driver as a module, choose M here: the + module will be called xsens_mt. + +config USB_SERIAL_WISHBONE + tristate "USB-Wishbone adapter interface driver" + help + Say Y here if you want to use a USB attached Wishbone bus. + + Wishbone is an open hardware SoC bus commonly used in FPGA + designs. Bus access can be serialized using the Etherbone + protocol <http://www.ohwr.org/projects/etherbone-core>. + + This driver is intended to be used with devices which attach + their internal Wishbone bus to a USB serial interface using + the Etherbone protocol. A userspace library is required to + speak the protocol made available by this driver as ttyUSBx. + + To compile this driver as a module, choose M here: the + module will be called wishbone-serial. + +config USB_SERIAL_ZTE + tristate "ZTE USB serial driver" help - Say Y here if you want to use ZIO Motherboard. + Say Y here if you want to use a ZTE USB to serial device. To compile this driver as a module, choose M here: the - module will be called zio. + module will be called zte. config USB_SERIAL_SSU100 tristate "USB Quatech SSU-100 Single Port Serial Driver" @@ -660,6 +699,15 @@ config USB_SERIAL_SSU100 To compile this driver as a module, choose M here: the module will be called ssu100. +config USB_SERIAL_QT2 + tristate "USB Quatech Serial Driver for USB 2 devices" + help + Say Y here if you want to use the Quatech USB 2 + serial adapters. + + To compile this driver as a module, choose M here: the + module will be called quatech-serial. + config USB_SERIAL_DEBUG tristate "USB Debugging Device" help diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile index 9a2117f2b06..bfdafd34944 100644 --- a/drivers/usb/serial/Makefile +++ b/drivers/usb/serial/Makefile @@ -9,7 +9,6 @@ obj-$(CONFIG_USB_SERIAL) += usbserial.o usbserial-y := usb-serial.o generic.o bus.o usbserial-$(CONFIG_USB_SERIAL_CONSOLE) += console.o -usbserial-$(CONFIG_USB_EZUSB) += ezusb.o obj-$(CONFIG_USB_SERIAL_AIRCABLE) += aircable.o obj-$(CONFIG_USB_SERIAL_ARK3116) += ark3116.o @@ -23,10 +22,9 @@ obj-$(CONFIG_USB_SERIAL_DIGI_ACCELEPORT) += digi_acceleport.o obj-$(CONFIG_USB_SERIAL_EDGEPORT) += io_edgeport.o obj-$(CONFIG_USB_SERIAL_EDGEPORT_TI) += io_ti.o obj-$(CONFIG_USB_SERIAL_EMPEG) += empeg.o +obj-$(CONFIG_USB_SERIAL_F81232) += f81232.o obj-$(CONFIG_USB_SERIAL_FTDI_SIO) += ftdi_sio.o -obj-$(CONFIG_USB_SERIAL_FUNSOFT) += funsoft.o obj-$(CONFIG_USB_SERIAL_GARMIN) += garmin_gps.o -obj-$(CONFIG_USB_SERIAL_HP4X) += hp4x.o obj-$(CONFIG_USB_SERIAL_IPAQ) += ipaq.o obj-$(CONFIG_USB_SERIAL_IPW) += ipw.o obj-$(CONFIG_USB_SERIAL_IR) += ir-usb.o @@ -36,9 +34,10 @@ obj-$(CONFIG_USB_SERIAL_KEYSPAN_PDA) += keyspan_pda.o obj-$(CONFIG_USB_SERIAL_KLSI) += kl5kusb105.o obj-$(CONFIG_USB_SERIAL_KOBIL_SCT) += kobil_sct.o obj-$(CONFIG_USB_SERIAL_MCT_U232) += mct_u232.o +obj-$(CONFIG_USB_SERIAL_METRO) += metro-usb.o obj-$(CONFIG_USB_SERIAL_MOS7720) += mos7720.o obj-$(CONFIG_USB_SERIAL_MOS7840) += mos7840.o -obj-$(CONFIG_USB_SERIAL_MOTOROLA) += moto_modem.o +obj-$(CONFIG_USB_SERIAL_MXUPORT) += mxuport.o obj-$(CONFIG_USB_SERIAL_NAVMAN) += navman.o obj-$(CONFIG_USB_SERIAL_OMNINET) += omninet.o obj-$(CONFIG_USB_SERIAL_OPTICON) += opticon.o @@ -47,17 +46,18 @@ obj-$(CONFIG_USB_SERIAL_OTI6858) += oti6858.o obj-$(CONFIG_USB_SERIAL_PL2303) += pl2303.o obj-$(CONFIG_USB_SERIAL_QCAUX) += qcaux.o obj-$(CONFIG_USB_SERIAL_QUALCOMM) += qcserial.o +obj-$(CONFIG_USB_SERIAL_QT2) += quatech2.o obj-$(CONFIG_USB_SERIAL_SAFE) += safe_serial.o -obj-$(CONFIG_USB_SERIAL_SAMBA) += sam-ba.o -obj-$(CONFIG_USB_SERIAL_SIEMENS_MPI) += siemens_mpi.o obj-$(CONFIG_USB_SERIAL_SIERRAWIRELESS) += sierra.o +obj-$(CONFIG_USB_SERIAL_SIMPLE) += usb-serial-simple.o obj-$(CONFIG_USB_SERIAL_SPCP8X5) += spcp8x5.o obj-$(CONFIG_USB_SERIAL_SSU100) += ssu100.o obj-$(CONFIG_USB_SERIAL_SYMBOL) += symbolserial.o obj-$(CONFIG_USB_SERIAL_WWAN) += usb_wwan.o obj-$(CONFIG_USB_SERIAL_TI) += ti_usb_3410_5052.o obj-$(CONFIG_USB_SERIAL_VISOR) += visor.o +obj-$(CONFIG_USB_SERIAL_WISHBONE) += wishbone-serial.o obj-$(CONFIG_USB_SERIAL_WHITEHEAT) += whiteheat.o obj-$(CONFIG_USB_SERIAL_XIRCOM) += keyspan_pda.o -obj-$(CONFIG_USB_SERIAL_VIVOPAY_SERIAL) += vivopay-serial.o -obj-$(CONFIG_USB_SERIAL_ZIO) += zio.o +obj-$(CONFIG_USB_SERIAL_XSENS_MT) += xsens_mt.o +obj-$(CONFIG_USB_SERIAL_ZTE) += zte_ev.o diff --git a/drivers/usb/serial/aircable.c b/drivers/usb/serial/aircable.c index 0db6ace16f7..80a9845cd93 100644 --- a/drivers/usb/serial/aircable.c +++ b/drivers/usb/serial/aircable.c @@ -10,13 +10,13 @@ * * The device works as an standard CDC device, it has 2 interfaces, the first * one is for firmware access and the second is the serial one. - * The protocol is very simply, there are two posibilities reading or writing. + * The protocol is very simply, there are two possibilities reading or writing. * When writing the first urb must have a Header that starts with 0x20 0x29 the - * next two bytes must say how much data will be sended. + * next two bytes must say how much data will be sent. * When reading the process is almost equal except that the header starts with * 0x00 0x20. * - * The device simply need some stuff to understand data comming from the usb + * The device simply need some stuff to understand data coming from the usb * buffer: The First and Second byte is used for a Header, the Third and Fourth * tells the device the amount of information the package holds. * Packages are 60 bytes long Header Stuff. @@ -30,16 +30,16 @@ * one. * * The driver registers himself with the USB-serial core and the USB Core. I had - * to implement a probe function agains USB-serial, because other way, the - * driver was attaching himself to both interfaces. I have tryed with different + * to implement a probe function against USB-serial, because other way, the + * driver was attaching himself to both interfaces. I have tried with different * configurations of usb_serial_driver with out exit, only the probe function * could handle this correctly. * * I have taken some info from a Greg Kroah-Hartman article: * http://www.linuxjournal.com/article/6573 * And from Linux Device Driver Kit CD, which is a great work, the authors taken - * the work to recompile lots of information an knowladge in drivers development - * and made it all avaible inside a cd. + * the work to recompile lots of information an knowledge in drivers development + * and made it all available inside a cd. * URL: http://kernel.org/pub/linux/kernel/people/gregkh/ddk/ * */ @@ -47,12 +47,11 @@ #include <asm/unaligned.h> #include <linux/tty.h> #include <linux/slab.h> +#include <linux/module.h> #include <linux/tty_flip.h> #include <linux/usb.h> #include <linux/usb/serial.h> -static int debug; - /* Vendor and Product ID */ #define AIRCABLE_VID 0x16CA #define AIRCABLE_USB_PID 0x1502 @@ -69,10 +68,6 @@ static int debug; #define THROTTLED 0x01 #define ACTUALLY_THROTTLED 0x02 -/* - * Version Information - */ -#define DRIVER_VERSION "v2.0" #define DRIVER_AUTHOR "Naranjo, Manuel Francisco <naranjo.manuel@gmail.com>, Johan Hovold <jhovold@gmail.com>" #define DRIVER_DESC "AIRcable USB Driver" @@ -110,33 +105,33 @@ static int aircable_probe(struct usb_serial *serial, for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) { endpoint = &iface_desc->endpoint[i].desc; if (usb_endpoint_is_bulk_out(endpoint)) { - dbg("found bulk out on endpoint %d", i); + dev_dbg(&serial->dev->dev, + "found bulk out on endpoint %d\n", i); ++num_bulk_out; } } if (num_bulk_out == 0) { - dbg("Invalid interface, discarding"); + dev_dbg(&serial->dev->dev, "Invalid interface, discarding\n"); return -ENODEV; } return 0; } -static int aircable_process_packet(struct tty_struct *tty, - struct usb_serial_port *port, int has_headers, - char *packet, int len) +static int aircable_process_packet(struct usb_serial_port *port, + int has_headers, char *packet, int len) { if (has_headers) { len -= HCI_HEADER_LENGTH; packet += HCI_HEADER_LENGTH; } if (len <= 0) { - dbg("%s - malformed packet", __func__); + dev_dbg(&port->dev, "%s - malformed packet\n", __func__); return 0; } - tty_insert_flip_string(tty, packet, len); + tty_insert_flip_string(&port->port, packet, len); return len; } @@ -145,44 +140,29 @@ static void aircable_process_read_urb(struct urb *urb) { struct usb_serial_port *port = urb->context; char *data = (char *)urb->transfer_buffer; - struct tty_struct *tty; int has_headers; int count; int len; int i; - tty = tty_port_tty_get(&port->port); - if (!tty) - return; - has_headers = (urb->actual_length > 2 && data[0] == RX_HEADER_0); count = 0; for (i = 0; i < urb->actual_length; i += HCI_COMPLETE_FRAME) { len = min_t(int, urb->actual_length - i, HCI_COMPLETE_FRAME); - count += aircable_process_packet(tty, port, has_headers, + count += aircable_process_packet(port, has_headers, &data[i], len); } if (count) - tty_flip_buffer_push(tty); - tty_kref_put(tty); + tty_flip_buffer_push(&port->port); } -static struct usb_driver aircable_driver = { - .name = "aircable", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, - .no_dynamic_id = 1, -}; - static struct usb_serial_driver aircable_device = { .driver = { .owner = THIS_MODULE, .name = "aircable", }, - .usb_driver = &aircable_driver, .id_table = id_table, .num_ports = 1, .bulk_out_size = HCI_COMPLETE_FRAME, @@ -193,36 +173,12 @@ static struct usb_serial_driver aircable_device = { .unthrottle = usb_serial_generic_unthrottle, }; -static int __init aircable_init(void) -{ - int retval; - retval = usb_serial_register(&aircable_device); - if (retval) - goto failed_serial_register; - retval = usb_register(&aircable_driver); - if (retval) - goto failed_usb_register; - return 0; +static struct usb_serial_driver * const serial_drivers[] = { + &aircable_device, NULL +}; -failed_usb_register: - usb_serial_deregister(&aircable_device); -failed_serial_register: - return retval; -} - -static void __exit aircable_exit(void) -{ - usb_deregister(&aircable_driver); - usb_serial_deregister(&aircable_device); -} +module_usb_serial_driver(serial_drivers, id_table); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_VERSION(DRIVER_VERSION); MODULE_LICENSE("GPL"); - -module_init(aircable_init); -module_exit(aircable_exit); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c index 8f1d4fb19d2..1532cde8a43 100644 --- a/drivers/usb/serial/ark3116.c +++ b/drivers/usb/serial/ark3116.c @@ -23,7 +23,6 @@ */ #include <linux/kernel.h> -#include <linux/init.h> #include <linux/ioctl.h> #include <linux/tty.h> #include <linux/slab.h> @@ -37,19 +36,13 @@ #include <linux/mutex.h> #include <linux/spinlock.h> -static int debug; -/* - * Version information - */ - -#define DRIVER_VERSION "v0.6" #define DRIVER_AUTHOR "Bart Hartgers <bart.hartgers+ark3116@gmail.com>" #define DRIVER_DESC "USB ARK3116 serial/IrDA driver" #define DRIVER_DEV_DESC "ARK3116 RS232/IrDA" #define DRIVER_NAME "ark3116" /* usb timeout of 1 second */ -#define ARK_TIMEOUT (1*HZ) +#define ARK_TIMEOUT 1000 static const struct usb_device_id id_table[] = { { USB_DEVICE(0x6547, 0x0232) }, @@ -68,8 +61,6 @@ static int is_irda(struct usb_serial *serial) } struct ark3116_private { - wait_queue_head_t delta_msr_wait; - struct async_icount icount; int irda; /* 1 for irda device */ /* protects hw register updates */ @@ -79,7 +70,7 @@ struct ark3116_private { __u32 lcr; /* line control register value */ __u32 hcr; /* handshake control register (0x8) * value */ - __u32 mcr; /* modem contol register value */ + __u32 mcr; /* modem control register value */ /* protects the status values below */ spinlock_t status_lock; @@ -126,9 +117,6 @@ static inline int calc_divisor(int bps) static int ark3116_attach(struct usb_serial *serial) { - struct usb_serial_port *port = serial->port[0]; - struct ark3116_private *priv; - /* make sure we have our end-points */ if ((serial->num_bulk_in == 0) || (serial->num_bulk_out == 0) || @@ -143,12 +131,18 @@ static int ark3116_attach(struct usb_serial *serial) return -EINVAL; } - priv = kzalloc(sizeof(struct ark3116_private), - GFP_KERNEL); + return 0; +} + +static int ark3116_port_probe(struct usb_serial_port *port) +{ + struct usb_serial *serial = port->serial; + struct ark3116_private *priv; + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; - init_waitqueue_head(&priv->delta_msr_wait); mutex_init(&priv->hw_lock); spin_lock_init(&priv->status_lock); @@ -199,23 +193,20 @@ static int ark3116_attach(struct usb_serial *serial) return 0; } -static void ark3116_release(struct usb_serial *serial) +static int ark3116_port_remove(struct usb_serial_port *port) { - struct usb_serial_port *port = serial->port[0]; struct ark3116_private *priv = usb_get_serial_port_data(port); /* device is closed, so URBs and DMA should be down */ - - usb_set_serial_port_data(port, NULL); - mutex_destroy(&priv->hw_lock); - kfree(priv); + + return 0; } static void ark3116_init_termios(struct tty_struct *tty) { - struct ktermios *termios = tty->termios; + struct ktermios *termios = &tty->termios; *termios = tty_std_termios; termios->c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; @@ -229,7 +220,7 @@ static void ark3116_set_termios(struct tty_struct *tty, { struct usb_serial *serial = port->serial; struct ark3116_private *priv = usb_get_serial_port_data(port); - struct ktermios *termios = tty->termios; + struct ktermios *termios = &tty->termios; unsigned int cflag = termios->c_cflag; int bps = tty_get_baud_rate(tty); int quot; @@ -265,7 +256,7 @@ static void ark3116_set_termios(struct tty_struct *tty, hcr = (cflag & CRTSCTS) ? 0x03 : 0x00; /* calc baudrate */ - dbg("%s - setting bps to %d", __func__, bps); + dev_dbg(&port->dev, "%s - setting bps to %d\n", __func__, bps); eval = 0; switch (bps) { case 0: @@ -292,8 +283,8 @@ static void ark3116_set_termios(struct tty_struct *tty, /* keep old LCR_SBC bit */ lcr |= (priv->lcr & UART_LCR_SBC); - dbg("%s - setting hcr:0x%02x,lcr:0x%02x,quot:%d", - __func__, hcr, lcr, quot); + dev_dbg(&port->dev, "%s - setting hcr:0x%02x,lcr:0x%02x,quot:%d\n", + __func__, hcr, lcr, quot); /* handshake control */ if (priv->hcr != hcr) { @@ -348,18 +339,15 @@ static void ark3116_close(struct usb_serial_port *port) { struct usb_serial *serial = port->serial; - if (serial->dev) { - /* disable DMA */ - ark3116_write_reg(serial, UART_FCR, 0); - - /* deactivate interrupts */ - ark3116_write_reg(serial, UART_IER, 0); + /* disable DMA */ + ark3116_write_reg(serial, UART_FCR, 0); - usb_serial_generic_close(port); - if (serial->num_interrupt_in) - usb_kill_urb(port->interrupt_in_urb); - } + /* deactivate interrupts */ + ark3116_write_reg(serial, UART_IER, 0); + usb_serial_generic_close(port); + if (serial->num_interrupt_in) + usb_kill_urb(port->interrupt_in_urb); } static int ark3116_open(struct tty_struct *tty, struct usb_serial_port *port) @@ -375,15 +363,12 @@ static int ark3116_open(struct tty_struct *tty, struct usb_serial_port *port) result = usb_serial_generic_open(tty, port); if (result) { - dbg("%s - usb_serial_generic_open failed: %d", - __func__, result); + dev_dbg(&port->dev, + "%s - usb_serial_generic_open failed: %d\n", + __func__, result); goto err_out; } - /* setup termios */ - if (tty) - ark3116_set_termios(tty, port, NULL); - /* remove any data still left: also clears error state */ ark3116_read_reg(serial, UART_RX, buf); @@ -406,36 +391,19 @@ static int ark3116_open(struct tty_struct *tty, struct usb_serial_port *port) /* enable DMA */ ark3116_write_reg(port->serial, UART_FCR, UART_FCR_DMA_SELECT); + /* setup termios */ + if (tty) + ark3116_set_termios(tty, port, NULL); + err_out: kfree(buf); return result; } -static int ark3116_get_icount(struct tty_struct *tty, - struct serial_icounter_struct *icount) -{ - struct usb_serial_port *port = tty->driver_data; - struct ark3116_private *priv = usb_get_serial_port_data(port); - struct async_icount cnow = priv->icount; - icount->cts = cnow.cts; - icount->dsr = cnow.dsr; - icount->rng = cnow.rng; - icount->dcd = cnow.dcd; - icount->rx = cnow.rx; - icount->tx = cnow.tx; - icount->frame = cnow.frame; - icount->overrun = cnow.overrun; - icount->parity = cnow.parity; - icount->brk = cnow.brk; - icount->buf_overrun = cnow.buf_overrun; - return 0; -} - -static int ark3116_ioctl(struct tty_struct *tty, struct file *file, +static int ark3116_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { struct usb_serial_port *port = tty->driver_data; - struct ark3116_private *priv = usb_get_serial_port_data(port); struct serial_struct serstruct; void __user *user_arg = (void __user *)arg; @@ -444,8 +412,8 @@ static int ark3116_ioctl(struct tty_struct *tty, struct file *file, /* XXX: Some of these values are probably wrong. */ memset(&serstruct, 0, sizeof(serstruct)); serstruct.type = PORT_16654; - serstruct.line = port->serial->minor; - serstruct.port = port->number; + serstruct.line = port->minor; + serstruct.port = port->port_number; serstruct.custom_divisor = 0; serstruct.baud_base = 460800; @@ -457,35 +425,12 @@ static int ark3116_ioctl(struct tty_struct *tty, struct file *file, if (copy_from_user(&serstruct, user_arg, sizeof(serstruct))) return -EFAULT; return 0; - case TIOCMIWAIT: - for (;;) { - struct async_icount prev = priv->icount; - interruptible_sleep_on(&priv->delta_msr_wait); - /* see if a signal did it */ - if (signal_pending(current)) - return -ERESTARTSYS; - if ((prev.rng == priv->icount.rng) && - (prev.dsr == priv->icount.dsr) && - (prev.dcd == priv->icount.dcd) && - (prev.cts == priv->icount.cts)) - return -EIO; - if ((arg & TIOCM_RNG && - (prev.rng != priv->icount.rng)) || - (arg & TIOCM_DSR && - (prev.dsr != priv->icount.dsr)) || - (arg & TIOCM_CD && - (prev.dcd != priv->icount.dcd)) || - (arg & TIOCM_CTS && - (prev.cts != priv->icount.cts))) - return 0; - } - break; } return -ENOIOCTLCMD; } -static int ark3116_tiocmget(struct tty_struct *tty, struct file *file) +static int ark3116_tiocmget(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; struct ark3116_private *priv = usb_get_serial_port_data(port); @@ -511,7 +456,7 @@ static int ark3116_tiocmget(struct tty_struct *tty, struct file *file) (ctrl & UART_MCR_OUT2 ? TIOCM_OUT2 : 0); } -static int ark3116_tiocmset(struct tty_struct *tty, struct file *file, +static int ark3116_tiocmset(struct tty_struct *tty, unsigned set, unsigned clr) { struct usb_serial_port *port = tty->driver_data; @@ -577,14 +522,14 @@ static void ark3116_update_msr(struct usb_serial_port *port, __u8 msr) if (msr & UART_MSR_ANY_DELTA) { /* update input line counters */ if (msr & UART_MSR_DCTS) - priv->icount.cts++; + port->icount.cts++; if (msr & UART_MSR_DDSR) - priv->icount.dsr++; + port->icount.dsr++; if (msr & UART_MSR_DDCD) - priv->icount.dcd++; + port->icount.dcd++; if (msr & UART_MSR_TERI) - priv->icount.rng++; - wake_up_interruptible(&priv->delta_msr_wait); + port->icount.rng++; + wake_up_interruptible(&port->port.delta_msr_wait); } } @@ -600,13 +545,13 @@ static void ark3116_update_lsr(struct usb_serial_port *port, __u8 lsr) if (lsr&UART_LSR_BRK_ERROR_BITS) { if (lsr & UART_LSR_BI) - priv->icount.brk++; + port->icount.brk++; if (lsr & UART_LSR_FE) - priv->icount.frame++; + port->icount.frame++; if (lsr & UART_LSR_PE) - priv->icount.parity++; + port->icount.parity++; if (lsr & UART_LSR_OE) - priv->icount.overrun++; + port->icount.overrun++; } } @@ -622,24 +567,26 @@ static void ark3116_read_int_callback(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", - __func__, status); + dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n", + __func__, status); return; default: - dbg("%s - nonzero urb status received: %d", - __func__, status); + dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n", + __func__, status); break; case 0: /* success */ /* discovered this by trail and error... */ if ((urb->actual_length == 4) && (data[0] == 0xe8)) { const __u8 id = data[1]&UART_IIR_ID; - dbg("%s: iir=%02x", __func__, data[1]); + dev_dbg(&port->dev, "%s: iir=%02x\n", __func__, data[1]); if (id == UART_IIR_MSI) { - dbg("%s: msr=%02x", __func__, data[3]); + dev_dbg(&port->dev, "%s: msr=%02x\n", + __func__, data[3]); ark3116_update_msr(port, data[3]); break; } else if (id == UART_IIR_RLSI) { - dbg("%s: lsr=%02x", __func__, data[2]); + dev_dbg(&port->dev, "%s: lsr=%02x\n", + __func__, data[2]); ark3116_update_lsr(port, data[2]); break; } @@ -647,8 +594,7 @@ static void ark3116_read_int_callback(struct urb *urb) /* * Not sure what this data meant... */ - usb_serial_debug_data(debug, &port->dev, - __func__, + usb_serial_debug_data(&port->dev, __func__, urb->actual_length, urb->transfer_buffer); break; @@ -662,7 +608,7 @@ static void ark3116_read_int_callback(struct urb *urb) } -/* Data comes in via the bulk (data) URB, erors/interrupts via the int URB. +/* Data comes in via the bulk (data) URB, errors/interrupts via the int URB. * This means that we cannot be sure which data byte has an associated error * condition, so we report an error for all data in the next bulk read. * @@ -677,7 +623,6 @@ static void ark3116_process_read_urb(struct urb *urb) { struct usb_serial_port *port = urb->context; struct ark3116_private *priv = usb_get_serial_port_data(port); - struct tty_struct *tty; unsigned char *data = urb->transfer_buffer; char tty_flag = TTY_NORMAL; unsigned long flags; @@ -692,10 +637,6 @@ static void ark3116_process_read_urb(struct urb *urb) if (!urb->actual_length) return; - tty = tty_port_tty_get(&port->port); - if (!tty) - return; - if (lsr & UART_LSR_BRK_ERROR_BITS) { if (lsr & UART_LSR_BI) tty_flag = TTY_BREAK; @@ -706,38 +647,30 @@ static void ark3116_process_read_urb(struct urb *urb) /* overrun is special, not associated with a char */ if (lsr & UART_LSR_OE) - tty_insert_flip_char(tty, 0, TTY_OVERRUN); + tty_insert_flip_char(&port->port, 0, TTY_OVERRUN); } - tty_insert_flip_string_fixed_flag(tty, data, tty_flag, + tty_insert_flip_string_fixed_flag(&port->port, data, tty_flag, urb->actual_length); - tty_flip_buffer_push(tty); - tty_kref_put(tty); + tty_flip_buffer_push(&port->port); } -static struct usb_driver ark3116_driver = { - .name = "ark3116", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, - .no_dynamic_id = 1, -}; - static struct usb_serial_driver ark3116_device = { .driver = { .owner = THIS_MODULE, .name = "ark3116", }, .id_table = id_table, - .usb_driver = &ark3116_driver, .num_ports = 1, .attach = ark3116_attach, - .release = ark3116_release, + .port_probe = ark3116_port_probe, + .port_remove = ark3116_port_remove, .set_termios = ark3116_set_termios, .init_termios = ark3116_init_termios, .ioctl = ark3116_ioctl, .tiocmget = ark3116_tiocmget, .tiocmset = ark3116_tiocmset, - .get_icount = ark3116_get_icount, + .tiocmiwait = usb_serial_generic_tiocmiwait, + .get_icount = usb_serial_generic_get_icount, .open = ark3116_open, .close = ark3116_close, .break_ctl = ark3116_break_ctl, @@ -745,40 +678,17 @@ static struct usb_serial_driver ark3116_device = { .process_read_urb = ark3116_process_read_urb, }; -static int __init ark3116_init(void) -{ - int retval; - - retval = usb_serial_register(&ark3116_device); - if (retval) - return retval; - retval = usb_register(&ark3116_driver); - if (retval == 0) { - printk(KERN_INFO "%s:" - DRIVER_VERSION ":" - DRIVER_DESC "\n", - KBUILD_MODNAME); - } else - usb_serial_deregister(&ark3116_device); - return retval; -} +static struct usb_serial_driver * const serial_drivers[] = { + &ark3116_device, NULL +}; -static void __exit ark3116_exit(void) -{ - usb_deregister(&ark3116_driver); - usb_serial_deregister(&ark3116_device); -} +module_usb_serial_driver(serial_drivers, id_table); -module_init(ark3116_init); -module_exit(ark3116_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Enable debug"); - /* * The following describes what I learned from studying the old * ark3116.c driver, disassembling the windows driver, and some lucky diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c index 36df35295db..15bc71853db 100644 --- a/drivers/usb/serial/belkin_sa.c +++ b/drivers/usb/serial/belkin_sa.c @@ -2,73 +2,29 @@ * Belkin USB Serial Adapter Driver * * Copyright (C) 2000 William Greathouse (wgreathouse@smva.com) - * Copyright (C) 2000-2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (C) 2000-2001 Greg Kroah-Hartman (greg@kroah.com) * Copyright (C) 2010 Johan Hovold (jhovold@gmail.com) * * This program is largely derived from work by the linux-usb group * and associated source files. Please see the usb/serial files for * individual credits and copyrights. * - * 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 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. * * See Documentation/usb/usb-serial.txt for more information on using this * driver * * TODO: - * -- Add true modem contol line query capability. Currently we track the + * -- Add true modem control line query capability. Currently we track the * states reported by the interrupt and the states we request. - * -- Add error reporting back to application for UART error conditions. - * Just point me at how to implement this and I'll do it. I've put the - * framework in, but haven't analyzed the "tty_flip" interface yet. * -- Add support for flush commands - * -- Add everything that is missing :) - * - * 27-Nov-2001 gkh - * compressed all the differnent device entries into 1. - * - * 30-May-2001 gkh - * switched from using spinlock to a semaphore, which fixes lots of - * problems. - * - * 08-Apr-2001 gb - * - Identify version on module load. - * - * 12-Mar-2001 gkh - * - Added support for the GoHubs GO-COM232 device which is the same as the - * Peracom device. - * - * 06-Nov-2000 gkh - * - Added support for the old Belkin and Peracom devices. - * - Made the port able to be opened multiple times. - * - Added some defaults incase the line settings are things these devices - * can't support. - * - * 18-Oct-2000 William Greathouse - * Released into the wild (linux-usb-devel) - * - * 17-Oct-2000 William Greathouse - * Add code to recognize firmware version and set hardware flow control - * appropriately. Belkin states that firmware prior to 3.05 does not - * operate correctly in hardware handshake mode. I have verified this - * on firmware 2.05 -- for both RTS and DTR input flow control, the control - * line is not reset. The test performed by the Belkin Win* driver is - * to enable hardware flow control for firmware 2.06 or greater and - * for 1.00 or prior. I am only enabling for 2.06 or greater. - * - * 12-Oct-2000 William Greathouse - * First cut at supporting Belkin USB Serial Adapter F5U103 - * I did not have a copy of the original work to support this - * adapter, so pardon any stupid mistakes. All of the information - * I am using to write this driver was acquired by using a modified - * UsbSnoop on Windows2000 and from examining the other USB drivers. */ #include <linux/kernel.h> #include <linux/errno.h> -#include <linux/init.h> #include <linux/slab.h> #include <linux/tty.h> #include <linux/tty_driver.h> @@ -80,18 +36,12 @@ #include <linux/usb/serial.h> #include "belkin_sa.h" -static int debug; - -/* - * Version Information - */ -#define DRIVER_VERSION "v1.3" #define DRIVER_AUTHOR "William Greathouse <wgreathouse@smva.com>" #define DRIVER_DESC "USB Belkin Serial converter driver" /* function prototypes for a Belkin USB Serial Adapter F5U103 */ -static int belkin_sa_startup(struct usb_serial *serial); -static void belkin_sa_release(struct usb_serial *serial); +static int belkin_sa_port_probe(struct usb_serial_port *port); +static int belkin_sa_port_remove(struct usb_serial_port *port); static int belkin_sa_open(struct tty_struct *tty, struct usb_serial_port *port); static void belkin_sa_close(struct usb_serial_port *port); @@ -100,12 +50,12 @@ static void belkin_sa_process_read_urb(struct urb *urb); static void belkin_sa_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios * old); static void belkin_sa_break_ctl(struct tty_struct *tty, int break_state); -static int belkin_sa_tiocmget(struct tty_struct *tty, struct file *file); -static int belkin_sa_tiocmset(struct tty_struct *tty, struct file *file, +static int belkin_sa_tiocmget(struct tty_struct *tty); +static int belkin_sa_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear); -static const struct usb_device_id id_table_combined[] = { +static const struct usb_device_id id_table[] = { { USB_DEVICE(BELKIN_SA_VID, BELKIN_SA_PID) }, { USB_DEVICE(BELKIN_OLD_VID, BELKIN_OLD_PID) }, { USB_DEVICE(PERACOM_VID, PERACOM_PID) }, @@ -114,15 +64,7 @@ static const struct usb_device_id id_table_combined[] = { { USB_DEVICE(BELKIN_DOCKSTATION_VID, BELKIN_DOCKSTATION_PID) }, { } /* Terminating entry */ }; -MODULE_DEVICE_TABLE(usb, id_table_combined); - -static struct usb_driver belkin_driver = { - .name = "belkin", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table_combined, - .no_dynamic_id = 1, -}; +MODULE_DEVICE_TABLE(usb, id_table); /* All of the device info needed for the serial converters */ static struct usb_serial_driver belkin_device = { @@ -131,8 +73,7 @@ static struct usb_serial_driver belkin_device = { .name = "belkin", }, .description = "Belkin / Peracom / GoHubs USB Serial Adapter", - .usb_driver = &belkin_driver, - .id_table = id_table_combined, + .id_table = id_table, .num_ports = 1, .open = belkin_sa_open, .close = belkin_sa_close, @@ -142,8 +83,12 @@ static struct usb_serial_driver belkin_device = { .break_ctl = belkin_sa_break_ctl, .tiocmget = belkin_sa_tiocmget, .tiocmset = belkin_sa_tiocmset, - .attach = belkin_sa_startup, - .release = belkin_sa_release, + .port_probe = belkin_sa_port_probe, + .port_remove = belkin_sa_port_remove, +}; + +static struct usb_serial_driver * const serial_drivers[] = { + &belkin_device, NULL }; struct belkin_sa_private { @@ -168,17 +113,15 @@ struct belkin_sa_private { (c), BELKIN_SA_SET_REQUEST_TYPE, \ (v), 0, NULL, 0, WDR_TIMEOUT) -/* do some startup allocations not currently performed by usb_serial_probe() */ -static int belkin_sa_startup(struct usb_serial *serial) +static int belkin_sa_port_probe(struct usb_serial_port *port) { - struct usb_device *dev = serial->dev; + struct usb_device *dev = port->serial->dev; struct belkin_sa_private *priv; - /* allocate the private data structure */ priv = kmalloc(sizeof(struct belkin_sa_private), GFP_KERNEL); if (!priv) - return -1; /* error */ - /* set initial values for control structures */ + return -ENOMEM; + spin_lock_init(&priv->lock); priv->control_state = 0; priv->last_lsr = 0; @@ -190,20 +133,19 @@ static int belkin_sa_startup(struct usb_serial *serial) le16_to_cpu(dev->descriptor.bcdDevice), priv->bad_flow_control); - init_waitqueue_head(&serial->port[0]->write_wait); - usb_set_serial_port_data(serial->port[0], priv); + usb_set_serial_port_data(port, priv); return 0; } -static void belkin_sa_release(struct usb_serial *serial) +static int belkin_sa_port_remove(struct usb_serial_port *port) { - int i; + struct belkin_sa_private *priv; - dbg("%s", __func__); + priv = usb_get_serial_port_data(port); + kfree(priv); - for (i = 0; i < serial->num_ports; ++i) - kfree(usb_get_serial_port_data(serial->port[i])); + return 0; } static int belkin_sa_open(struct tty_struct *tty, @@ -211,8 +153,6 @@ static int belkin_sa_open(struct tty_struct *tty, { int retval; - dbg("%s port %d", __func__, port->number); - retval = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); if (retval) { dev_err(&port->dev, "usb_submit_urb(read int) failed\n"); @@ -228,8 +168,6 @@ static int belkin_sa_open(struct tty_struct *tty, static void belkin_sa_close(struct usb_serial_port *port) { - dbg("%s port %d", __func__, port->number); - usb_serial_generic_close(port); usb_kill_urb(port->interrupt_in_urb); } @@ -251,17 +189,16 @@ static void belkin_sa_read_int_callback(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", - __func__, status); + dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n", + __func__, status); return; default: - dbg("%s - nonzero urb status received: %d", - __func__, status); + dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n", + __func__, status); goto exit; } - usb_serial_debug_data(debug, &port->dev, __func__, - urb->actual_length, data); + usb_serial_debug_data(&port->dev, __func__, urb->actual_length, data); /* Handle known interrupt data */ /* ignore data[0] and data[1] */ @@ -304,7 +241,6 @@ static void belkin_sa_process_read_urb(struct urb *urb) { struct usb_serial_port *port = urb->context; struct belkin_sa_private *priv = usb_get_serial_port_data(port); - struct tty_struct *tty; unsigned char *data = urb->transfer_buffer; unsigned long flags; unsigned char status; @@ -321,10 +257,6 @@ static void belkin_sa_process_read_urb(struct urb *urb) if (!urb->actual_length) return; - tty = tty_port_tty_get(&port->port); - if (!tty) - return; - if (status & BELKIN_SA_LSR_ERR) { /* Break takes precedence over parity, which takes precedence * over framing errors. */ @@ -338,13 +270,12 @@ static void belkin_sa_process_read_urb(struct urb *urb) /* Overrun is special, not associated with a char. */ if (status & BELKIN_SA_LSR_OE) - tty_insert_flip_char(tty, 0, TTY_OVERRUN); + tty_insert_flip_char(&port->port, 0, TTY_OVERRUN); } - tty_insert_flip_string_fixed_flag(tty, data, tty_flag, + tty_insert_flip_string_fixed_flag(&port->port, data, tty_flag, urb->actual_length); - tty_flip_buffer_push(tty); - tty_kref_put(tty); + tty_flip_buffer_push(&port->port); } static void belkin_sa_set_termios(struct tty_struct *tty, @@ -361,7 +292,7 @@ static void belkin_sa_set_termios(struct tty_struct *tty, unsigned long control_state; int bad_flow_control; speed_t baud; - struct ktermios *termios = tty->termios; + struct ktermios *termios = &tty->termios; iflag = termios->c_iflag; cflag = termios->c_cflag; @@ -444,7 +375,9 @@ static void belkin_sa_set_termios(struct tty_struct *tty, case CS8: urb_value = BELKIN_SA_DATA_BITS(8); break; - default: dbg("CSIZE was not CS5-CS8, using default of 8"); + default: + dev_dbg(&port->dev, + "CSIZE was not CS5-CS8, using default of 8\n"); urb_value = BELKIN_SA_DATA_BITS(8); break; } @@ -497,15 +430,13 @@ static void belkin_sa_break_ctl(struct tty_struct *tty, int break_state) dev_err(&port->dev, "Set break_ctl %d\n", break_state); } -static int belkin_sa_tiocmget(struct tty_struct *tty, struct file *file) +static int belkin_sa_tiocmget(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; struct belkin_sa_private *priv = usb_get_serial_port_data(port); unsigned long control_state; unsigned long flags; - dbg("%s", __func__); - spin_lock_irqsave(&priv->lock, flags); control_state = priv->control_state; spin_unlock_irqrestore(&priv->lock, flags); @@ -513,7 +444,7 @@ static int belkin_sa_tiocmget(struct tty_struct *tty, struct file *file) return control_state; } -static int belkin_sa_tiocmset(struct tty_struct *tty, struct file *file, +static int belkin_sa_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) { struct usb_serial_port *port = tty->driver_data; @@ -525,8 +456,6 @@ static int belkin_sa_tiocmset(struct tty_struct *tty, struct file *file, int rts = 0; int dtr = 0; - dbg("%s", __func__); - spin_lock_irqsave(&priv->lock, flags); control_state = priv->control_state; @@ -565,39 +494,8 @@ exit: return retval; } - -static int __init belkin_sa_init(void) -{ - int retval; - retval = usb_serial_register(&belkin_device); - if (retval) - goto failed_usb_serial_register; - retval = usb_register(&belkin_driver); - if (retval) - goto failed_usb_register; - printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" - DRIVER_DESC "\n"); - return 0; -failed_usb_register: - usb_serial_deregister(&belkin_device); -failed_usb_serial_register: - return retval; -} - -static void __exit belkin_sa_exit (void) -{ - usb_deregister(&belkin_driver); - usb_serial_deregister(&belkin_device); -} - - -module_init(belkin_sa_init); -module_exit(belkin_sa_exit); +module_usb_serial_driver(serial_drivers, id_table); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_VERSION(DRIVER_VERSION); MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c index 7f547dc3a59..9374bd2aba2 100644 --- a/drivers/usb/serial/bus.c +++ b/drivers/usb/serial/bus.c @@ -38,15 +38,14 @@ static int usb_serial_device_match(struct device *dev, return 0; } -static ssize_t show_port_number(struct device *dev, +static ssize_t port_number_show(struct device *dev, struct device_attribute *attr, char *buf) { struct usb_serial_port *port = to_usb_serial_port(dev); - return sprintf(buf, "%d\n", port->number - port->serial->minor); + return sprintf(buf, "%d\n", port->port_number); } - -static DEVICE_ATTR(port_number, S_IRUGO, show_port_number, NULL); +static DEVICE_ATTR_RO(port_number); static int usb_serial_device_probe(struct device *dev) { @@ -60,29 +59,34 @@ static int usb_serial_device_probe(struct device *dev) retval = -ENODEV; goto exit; } - if (port->dev_state != PORT_REGISTERING) + + /* make sure suspend/resume doesn't race against port_probe */ + retval = usb_autopm_get_interface(port->serial->interface); + if (retval) goto exit; driver = port->serial->type; if (driver->port_probe) { retval = driver->port_probe(port); if (retval) - goto exit; + goto exit_with_autopm; } retval = device_create_file(dev, &dev_attr_port_number); if (retval) { if (driver->port_remove) retval = driver->port_remove(port); - goto exit; + goto exit_with_autopm; } - minor = port->number; + minor = port->minor; tty_register_device(usb_serial_tty_driver, minor, dev); dev_info(&port->serial->dev->dev, "%s converter now attached to ttyUSB%d\n", driver->description, minor); +exit_with_autopm: + usb_autopm_put_interface(port->serial->interface); exit: return retval; } @@ -93,13 +97,22 @@ static int usb_serial_device_remove(struct device *dev) struct usb_serial_port *port; int retval = 0; int minor; + int autopm_err; port = to_usb_serial_port(dev); if (!port) return -ENODEV; - if (port->dev_state != PORT_UNREGISTERING) - return retval; + /* + * Make sure suspend/resume doesn't race against port_remove. + * + * Note that no further runtime PM callbacks will be made if + * autopm_get fails. + */ + autopm_err = usb_autopm_get_interface(port->serial->interface); + + minor = port->minor; + tty_unregister_device(usb_serial_tty_driver, minor); device_remove_file(&port->dev, &dev_attr_port_number); @@ -107,32 +120,43 @@ static int usb_serial_device_remove(struct device *dev) if (driver->port_remove) retval = driver->port_remove(port); - minor = port->number; - tty_unregister_device(usb_serial_tty_driver, minor); dev_info(dev, "%s converter now disconnected from ttyUSB%d\n", driver->description, minor); + if (!autopm_err) + usb_autopm_put_interface(port->serial->interface); + return retval; } -#ifdef CONFIG_HOTPLUG -static ssize_t store_new_id(struct device_driver *driver, +static ssize_t new_id_store(struct device_driver *driver, const char *buf, size_t count) { struct usb_serial_driver *usb_drv = to_usb_serial_driver(driver); - ssize_t retval = usb_store_new_id(&usb_drv->dynids, driver, buf, count); + ssize_t retval = usb_store_new_id(&usb_drv->dynids, usb_drv->id_table, + driver, buf, count); if (retval >= 0 && usb_drv->usb_driver != NULL) retval = usb_store_new_id(&usb_drv->usb_driver->dynids, + usb_drv->usb_driver->id_table, &usb_drv->usb_driver->drvwrap.driver, buf, count); return retval; } -static struct driver_attribute drv_attrs[] = { - __ATTR(new_id, S_IWUSR, NULL, store_new_id), - __ATTR_NULL, +static ssize_t new_id_show(struct device_driver *driver, char *buf) +{ + struct usb_serial_driver *usb_drv = to_usb_serial_driver(driver); + + return usb_show_dynids(&usb_drv->dynids, buf); +} +static DRIVER_ATTR_RW(new_id); + +static struct attribute *usb_serial_drv_attrs[] = { + &driver_attr_new_id.attr, + NULL, }; +ATTRIBUTE_GROUPS(usb_serial_drv); static void free_dynids(struct usb_serial_driver *drv) { @@ -146,21 +170,12 @@ static void free_dynids(struct usb_serial_driver *drv) spin_unlock(&drv->dynids.lock); } -#else -static struct driver_attribute drv_attrs[] = { - __ATTR_NULL, -}; -static inline void free_dynids(struct usb_serial_driver *drv) -{ -} -#endif - struct bus_type usb_serial_bus_type = { .name = "usb-serial", .match = usb_serial_device_match, .probe = usb_serial_device_probe, .remove = usb_serial_device_remove, - .drv_attrs = drv_attrs, + .drv_groups = usb_serial_drv_groups, }; int usb_serial_bus_register(struct usb_serial_driver *driver) diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c index 63f7cc45bca..2d72aa3564a 100644 --- a/drivers/usb/serial/ch341.c +++ b/drivers/usb/serial/ch341.c @@ -16,7 +16,6 @@ */ #include <linux/kernel.h> -#include <linux/init.h> #include <linux/tty.h> #include <linux/module.h> #include <linux/slab.h> @@ -70,30 +69,28 @@ #define CH341_NBREAK_BITS_REG2 0x40 -static int debug; - static const struct usb_device_id id_table[] = { { USB_DEVICE(0x4348, 0x5523) }, { USB_DEVICE(0x1a86, 0x7523) }, + { USB_DEVICE(0x1a86, 0x5523) }, { }, }; MODULE_DEVICE_TABLE(usb, id_table); struct ch341_private { spinlock_t lock; /* access lock */ - wait_queue_head_t delta_msr_wait; /* wait queue for modem status */ unsigned baud_rate; /* set baud rate */ u8 line_control; /* set line control value RTS/DTR */ u8 line_status; /* active status of modem control inputs */ - u8 multi_status_change; /* status changed multiple since last call */ }; static int ch341_control_out(struct usb_device *dev, u8 request, u16 value, u16 index) { int r; - dbg("ch341_control_out(%02x,%02x,%04x,%04x)", USB_DIR_OUT|0x40, - (int)request, (int)value, (int)index); + + dev_dbg(&dev->dev, "ch341_control_out(%02x,%02x,%04x,%04x)\n", + USB_DIR_OUT|0x40, (int)request, (int)value, (int)index); r = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), request, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, @@ -107,8 +104,10 @@ static int ch341_control_in(struct usb_device *dev, char *buf, unsigned bufsize) { int r; - dbg("ch341_control_in(%02x,%02x,%04x,%04x,%p,%u)", USB_DIR_IN|0x40, - (int)request, (int)value, (int)index, buf, (int)bufsize); + + dev_dbg(&dev->dev, "ch341_control_in(%02x,%02x,%04x,%04x,%p,%u)\n", + USB_DIR_IN|0x40, (int)request, (int)value, (int)index, buf, + (int)bufsize); r = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), request, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, @@ -124,8 +123,6 @@ static int ch341_set_baudrate(struct usb_device *dev, unsigned long factor; short divisor; - dbg("ch341_set_baudrate(%d)", priv->baud_rate); - if (!priv->baud_rate) return -EINVAL; factor = (CH341_BAUDBASE_FACTOR / priv->baud_rate); @@ -152,7 +149,6 @@ static int ch341_set_baudrate(struct usb_device *dev, static int ch341_set_handshake(struct usb_device *dev, u8 control) { - dbg("ch341_set_handshake(0x%02x)", control); return ch341_control_out(dev, 0xa4, ~control, 0); } @@ -163,8 +159,6 @@ static int ch341_get_status(struct usb_device *dev, struct ch341_private *priv) const unsigned size = 8; unsigned long flags; - dbg("ch341_get_status()"); - buffer = kmalloc(size, GFP_KERNEL); if (!buffer) return -ENOMEM; @@ -178,7 +172,6 @@ static int ch341_get_status(struct usb_device *dev, struct ch341_private *priv) r = 0; spin_lock_irqsave(&priv->lock, flags); priv->line_status = (~(*buffer)) & CH341_BITS_MODEM_STAT; - priv->multi_status_change = 0; spin_unlock_irqrestore(&priv->lock, flags); } else r = -EPROTO; @@ -195,8 +188,6 @@ static int ch341_configure(struct usb_device *dev, struct ch341_private *priv) int r; const unsigned size = 8; - dbg("ch341_configure()"); - buffer = kmalloc(size, GFP_KERNEL); if (!buffer) return -ENOMEM; @@ -247,35 +238,40 @@ out: kfree(buffer); return r; } -/* allocate private data */ -static int ch341_attach(struct usb_serial *serial) +static int ch341_port_probe(struct usb_serial_port *port) { struct ch341_private *priv; int r; - dbg("ch341_attach()"); - - /* private data */ priv = kzalloc(sizeof(struct ch341_private), GFP_KERNEL); if (!priv) return -ENOMEM; spin_lock_init(&priv->lock); - init_waitqueue_head(&priv->delta_msr_wait); priv->baud_rate = DEFAULT_BAUD_RATE; priv->line_control = CH341_BIT_RTS | CH341_BIT_DTR; - r = ch341_configure(serial->dev, priv); + r = ch341_configure(port->serial->dev, priv); if (r < 0) goto error; - usb_set_serial_port_data(serial->port[0], priv); + usb_set_serial_port_data(port, priv); return 0; error: kfree(priv); return r; } +static int ch341_port_remove(struct usb_serial_port *port) +{ + struct ch341_private *priv; + + priv = usb_get_serial_port_data(port); + kfree(priv); + + return 0; +} + static int ch341_carrier_raised(struct usb_serial_port *port) { struct ch341_private *priv = usb_get_serial_port_data(port); @@ -289,7 +285,6 @@ static void ch341_dtr_rts(struct usb_serial_port *port, int on) struct ch341_private *priv = usb_get_serial_port_data(port); unsigned long flags; - dbg("%s - port %d", __func__, port->number); /* drop DTR and RTS */ spin_lock_irqsave(&priv->lock, flags); if (on) @@ -298,13 +293,10 @@ static void ch341_dtr_rts(struct usb_serial_port *port, int on) priv->line_control &= ~(CH341_BIT_RTS | CH341_BIT_DTR); spin_unlock_irqrestore(&priv->lock, flags); ch341_set_handshake(port->serial->dev, priv->line_control); - wake_up_interruptible(&priv->delta_msr_wait); } static void ch341_close(struct usb_serial_port *port) { - dbg("%s - port %d", __func__, port->number); - usb_serial_generic_close(port); usb_kill_urb(port->interrupt_in_urb); } @@ -314,11 +306,9 @@ static void ch341_close(struct usb_serial_port *port) static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port) { struct usb_serial *serial = port->serial; - struct ch341_private *priv = usb_get_serial_port_data(serial->port[0]); + struct ch341_private *priv = usb_get_serial_port_data(port); int r; - dbg("ch341_open()"); - priv->baud_rate = DEFAULT_BAUD_RATE; r = ch341_configure(serial->dev, priv); @@ -333,14 +323,13 @@ static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port) if (r) goto out; - dbg("%s - submitting interrupt urb", __func__); - port->interrupt_in_urb->dev = serial->dev; + dev_dbg(&port->dev, "%s - submitting interrupt urb\n", __func__); r = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); if (r) { - dev_err(&port->dev, "%s - failed submitting interrupt urb," - " error %d\n", __func__, r); + dev_err(&port->dev, "%s - failed to submit interrupt urb: %d\n", + __func__, r); ch341_close(port); - return -EPROTO; + goto out; } r = usb_serial_generic_open(tty, port); @@ -358,8 +347,6 @@ static void ch341_set_termios(struct tty_struct *tty, unsigned baud_rate; unsigned long flags; - dbg("ch341_set_termios()"); - baud_rate = tty_get_baud_rate(tty); priv->baud_rate = baud_rate; @@ -393,13 +380,9 @@ static void ch341_break_ctl(struct tty_struct *tty, int break_state) uint16_t reg_contents; uint8_t *break_reg; - dbg("%s()", __func__); - break_reg = kmalloc(2, GFP_KERNEL); - if (!break_reg) { - dev_err(&port->dev, "%s - kmalloc failed\n", __func__); + if (!break_reg) return; - } r = ch341_control_in(port->serial->dev, CH341_REQ_READ_REG, ch341_break_reg, 0, break_reg, 2); @@ -408,19 +391,19 @@ static void ch341_break_ctl(struct tty_struct *tty, int break_state) __func__, r); goto out; } - dbg("%s - initial ch341 break register contents - reg1: %x, reg2: %x", - __func__, break_reg[0], break_reg[1]); + dev_dbg(&port->dev, "%s - initial ch341 break register contents - reg1: %x, reg2: %x\n", + __func__, break_reg[0], break_reg[1]); if (break_state != 0) { - dbg("%s - Enter break state requested", __func__); + dev_dbg(&port->dev, "%s - Enter break state requested\n", __func__); break_reg[0] &= ~CH341_NBREAK_BITS_REG1; break_reg[1] &= ~CH341_NBREAK_BITS_REG2; } else { - dbg("%s - Leave break state requested", __func__); + dev_dbg(&port->dev, "%s - Leave break state requested\n", __func__); break_reg[0] |= CH341_NBREAK_BITS_REG1; break_reg[1] |= CH341_NBREAK_BITS_REG2; } - dbg("%s - New ch341 break register contents - reg1: %x, reg2: %x", - __func__, break_reg[0], break_reg[1]); + dev_dbg(&port->dev, "%s - New ch341 break register contents - reg1: %x, reg2: %x\n", + __func__, break_reg[0], break_reg[1]); reg_contents = get_unaligned_le16(break_reg); r = ch341_control_out(port->serial->dev, CH341_REQ_WRITE_REG, ch341_break_reg, reg_contents); @@ -431,7 +414,7 @@ out: kfree(break_reg); } -static int ch341_tiocmset(struct tty_struct *tty, struct file *file, +static int ch341_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) { struct usb_serial_port *port = tty->driver_data; @@ -454,15 +437,57 @@ static int ch341_tiocmset(struct tty_struct *tty, struct file *file, return ch341_set_handshake(port->serial->dev, control); } +static void ch341_update_line_status(struct usb_serial_port *port, + unsigned char *data, size_t len) +{ + struct ch341_private *priv = usb_get_serial_port_data(port); + struct tty_struct *tty; + unsigned long flags; + u8 status; + u8 delta; + + if (len < 4) + return; + + status = ~data[2] & CH341_BITS_MODEM_STAT; + + spin_lock_irqsave(&priv->lock, flags); + delta = status ^ priv->line_status; + priv->line_status = status; + spin_unlock_irqrestore(&priv->lock, flags); + + if (data[1] & CH341_MULT_STAT) + dev_dbg(&port->dev, "%s - multiple status change\n", __func__); + + if (!delta) + return; + + if (delta & CH341_BIT_CTS) + port->icount.cts++; + if (delta & CH341_BIT_DSR) + port->icount.dsr++; + if (delta & CH341_BIT_RI) + port->icount.rng++; + if (delta & CH341_BIT_DCD) { + port->icount.dcd++; + tty = tty_port_tty_get(&port->port); + if (tty) { + usb_serial_handle_dcd_change(port, tty, + status & CH341_BIT_DCD); + tty_kref_put(tty); + } + } + + wake_up_interruptible(&port->port.delta_msr_wait); +} + static void ch341_read_int_callback(struct urb *urb) { - struct usb_serial_port *port = (struct usb_serial_port *) urb->context; + struct usb_serial_port *port = urb->context; unsigned char *data = urb->transfer_buffer; - unsigned int actual_length = urb->actual_length; + unsigned int len = urb->actual_length; int status; - dbg("%s (%d)", __func__, port->number); - switch (urb->status) { case 0: /* success */ @@ -471,98 +496,26 @@ static void ch341_read_int_callback(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", __func__, - urb->status); + dev_dbg(&urb->dev->dev, "%s - urb shutting down: %d\n", + __func__, urb->status); return; default: - dbg("%s - nonzero urb status received: %d", __func__, - urb->status); + dev_dbg(&urb->dev->dev, "%s - nonzero urb status: %d\n", + __func__, urb->status); goto exit; } - usb_serial_debug_data(debug, &port->dev, __func__, - urb->actual_length, urb->transfer_buffer); - - if (actual_length >= 4) { - struct ch341_private *priv = usb_get_serial_port_data(port); - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - priv->line_status = (~(data[2])) & CH341_BITS_MODEM_STAT; - if ((data[1] & CH341_MULT_STAT)) - priv->multi_status_change = 1; - spin_unlock_irqrestore(&priv->lock, flags); - wake_up_interruptible(&priv->delta_msr_wait); - } - + usb_serial_debug_data(&port->dev, __func__, len, data); + ch341_update_line_status(port, data, len); exit: status = usb_submit_urb(urb, GFP_ATOMIC); - if (status) - dev_err(&urb->dev->dev, - "%s - usb_submit_urb failed with result %d\n", + if (status) { + dev_err(&urb->dev->dev, "%s - usb_submit_urb failed: %d\n", __func__, status); -} - -static int wait_modem_info(struct usb_serial_port *port, unsigned int arg) -{ - struct ch341_private *priv = usb_get_serial_port_data(port); - unsigned long flags; - u8 prevstatus; - u8 status; - u8 changed; - u8 multi_change = 0; - - spin_lock_irqsave(&priv->lock, flags); - prevstatus = priv->line_status; - priv->multi_status_change = 0; - spin_unlock_irqrestore(&priv->lock, flags); - - while (!multi_change) { - interruptible_sleep_on(&priv->delta_msr_wait); - /* see if a signal did it */ - if (signal_pending(current)) - return -ERESTARTSYS; - - spin_lock_irqsave(&priv->lock, flags); - status = priv->line_status; - multi_change = priv->multi_status_change; - spin_unlock_irqrestore(&priv->lock, flags); - - changed = prevstatus ^ status; - - if (((arg & TIOCM_RNG) && (changed & CH341_BIT_RI)) || - ((arg & TIOCM_DSR) && (changed & CH341_BIT_DSR)) || - ((arg & TIOCM_CD) && (changed & CH341_BIT_DCD)) || - ((arg & TIOCM_CTS) && (changed & CH341_BIT_CTS))) { - return 0; - } - prevstatus = status; - } - - return 0; -} - -/*static int ch341_ioctl(struct usb_serial_port *port, struct file *file,*/ -static int ch341_ioctl(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct usb_serial_port *port = tty->driver_data; - dbg("%s (%d) cmd = 0x%04x", __func__, port->number, cmd); - - switch (cmd) { - case TIOCMIWAIT: - dbg("%s (%d) TIOCMIWAIT", __func__, port->number); - return wait_modem_info(port, arg); - - default: - dbg("%s not supported = 0x%04x", __func__, cmd); - break; } - - return -ENOIOCTLCMD; } -static int ch341_tiocmget(struct tty_struct *tty, struct file *file) +static int ch341_tiocmget(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; struct ch341_private *priv = usb_get_serial_port_data(port); @@ -571,8 +524,6 @@ static int ch341_tiocmget(struct tty_struct *tty, struct file *file) u8 status; unsigned int result; - dbg("%s (%d)", __func__, port->number); - spin_lock_irqsave(&priv->lock, flags); mcr = priv->line_control; status = priv->line_status; @@ -585,86 +536,49 @@ static int ch341_tiocmget(struct tty_struct *tty, struct file *file) | ((status & CH341_BIT_RI) ? TIOCM_RI : 0) | ((status & CH341_BIT_DCD) ? TIOCM_CD : 0); - dbg("%s - result = %x", __func__, result); + dev_dbg(&port->dev, "%s - result = %x\n", __func__, result); return result; } - -static int ch341_reset_resume(struct usb_interface *intf) +static int ch341_reset_resume(struct usb_serial *serial) { - struct usb_device *dev = interface_to_usbdev(intf); - struct usb_serial *serial = NULL; struct ch341_private *priv; - serial = usb_get_intfdata(intf); priv = usb_get_serial_port_data(serial->port[0]); - /*reconfigure ch341 serial port after bus-reset*/ - ch341_configure(dev, priv); - - usb_serial_resume(intf); + /* reconfigure ch341 serial port after bus-reset */ + ch341_configure(serial->dev, priv); return 0; } -static struct usb_driver ch341_driver = { - .name = "ch341", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .suspend = usb_serial_suspend, - .resume = usb_serial_resume, - .reset_resume = ch341_reset_resume, - .id_table = id_table, - .no_dynamic_id = 1, - .supports_autosuspend = 1, -}; - static struct usb_serial_driver ch341_device = { .driver = { .owner = THIS_MODULE, .name = "ch341-uart", }, .id_table = id_table, - .usb_driver = &ch341_driver, .num_ports = 1, .open = ch341_open, .dtr_rts = ch341_dtr_rts, .carrier_raised = ch341_carrier_raised, .close = ch341_close, - .ioctl = ch341_ioctl, .set_termios = ch341_set_termios, .break_ctl = ch341_break_ctl, .tiocmget = ch341_tiocmget, .tiocmset = ch341_tiocmset, + .tiocmiwait = usb_serial_generic_tiocmiwait, .read_int_callback = ch341_read_int_callback, - .attach = ch341_attach, + .port_probe = ch341_port_probe, + .port_remove = ch341_port_remove, + .reset_resume = ch341_reset_resume, }; -static int __init ch341_init(void) -{ - int retval; - - retval = usb_serial_register(&ch341_device); - if (retval) - return retval; - retval = usb_register(&ch341_driver); - if (retval) - usb_serial_deregister(&ch341_device); - return retval; -} +static struct usb_serial_driver * const serial_drivers[] = { + &ch341_device, NULL +}; -static void __exit ch341_exit(void) -{ - usb_deregister(&ch341_driver); - usb_serial_deregister(&ch341_device); -} +module_usb_serial_driver(serial_drivers, id_table); -module_init(ch341_init); -module_exit(ch341_exit); MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); - -/* EOF ch341.c */ diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c index 1ee6b2ab0f8..8d7fc48b1f3 100644 --- a/drivers/usb/serial/console.c +++ b/drivers/usb/serial/console.c @@ -11,8 +11,9 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/kernel.h> -#include <linux/init.h> #include <linux/slab.h> #include <linux/tty.h> #include <linux/console.h> @@ -20,8 +21,6 @@ #include <linux/usb.h> #include <linux/usb/serial.h> -static int debug; - struct usbcons_info { int magic; int break_flag; @@ -68,8 +67,6 @@ static int usb_console_setup(struct console *co, char *options) struct tty_struct *tty = NULL; struct ktermios dummy; - dbg("%s", __func__); - if (options) { baud = simple_strtoul(options, NULL, 10); s = options; @@ -110,18 +107,18 @@ static int usb_console_setup(struct console *co, char *options) * no need to check the index here: if the index is wrong, console * code won't call us */ - serial = usb_serial_get_by_index(co->index); - if (serial == NULL) { + port = usb_serial_port_get_by_minor(co->index); + if (port == NULL) { /* no device is connected yet, sorry :( */ - err("No USB device connected to ttyUSB%i", co->index); + pr_err("No USB device connected to ttyUSB%i\n", co->index); return -ENODEV; } + serial = port->serial; retval = usb_autopm_get_interface(serial->interface); if (retval) goto error_get_interface; - port = serial->port[co->index - serial->minor]; tty_port_tty_set(&port->port, NULL); info->port = port; @@ -137,7 +134,6 @@ static int usb_console_setup(struct console *co, char *options) tty = kzalloc(sizeof(*tty), GFP_KERNEL); if (!tty) { retval = -ENOMEM; - err("no more memory"); goto reset_open_count; } kref_init(&tty->kref); @@ -146,26 +142,21 @@ static int usb_console_setup(struct console *co, char *options) tty->index = co->index; if (tty_init_termios(tty)) { retval = -ENOMEM; - err("no more memory"); goto free_tty; } } /* only call the device specific open if this * is the first time the port is opened */ - if (serial->type->open) - retval = serial->type->open(NULL, port); - else - retval = usb_serial_generic_open(NULL, port); - + retval = serial->type->open(NULL, port); if (retval) { - err("could not open USB console port"); + dev_err(&port->dev, "could not open USB console port\n"); goto fail; } if (serial->type->set_termios) { - tty->termios->c_cflag = cflag; - tty_termios_encode_baud_rate(tty->termios, baud, baud); + tty->termios.c_cflag = cflag; + tty_termios_encode_baud_rate(&tty->termios, baud, baud); memset(&dummy, 0, sizeof(struct ktermios)); serial->type->set_termios(tty, port, &dummy); @@ -212,10 +203,10 @@ static void usb_console_write(struct console *co, if (count == 0) return; - dbg("%s - port %d, %d byte(s)", __func__, port->number, count); + dev_dbg(&port->dev, "%s - %d byte(s)\n", __func__, count); if (!port->port.console) { - dbg("%s - port not opened", __func__); + dev_dbg(&port->dev, "%s - port not opened\n", __func__); return; } @@ -232,21 +223,14 @@ static void usb_console_write(struct console *co, } /* pass on to the driver specific version of this function if it is available */ - if (serial->type->write) - retval = serial->type->write(NULL, port, buf, i); - else - retval = usb_serial_generic_write(NULL, port, buf, i); - dbg("%s - return value : %d", __func__, retval); + retval = serial->type->write(NULL, port, buf, i); + dev_dbg(&port->dev, "%s - write: %d\n", __func__, retval); if (lf) { /* append CR after LF */ unsigned char cr = 13; - if (serial->type->write) - retval = serial->type->write(NULL, - port, &cr, 1); - else - retval = usb_serial_generic_write(NULL, - port, &cr, 1); - dbg("%s - return value : %d", __func__, retval); + retval = serial->type->write(NULL, port, &cr, 1); + dev_dbg(&port->dev, "%s - write cr: %d\n", + __func__, retval); } buf += i; count -= i; @@ -283,10 +267,8 @@ void usb_serial_console_disconnect(struct usb_serial *serial) } } -void usb_serial_console_init(int serial_debug, int minor) +void usb_serial_console_init(int minor) { - debug = serial_debug; - if (minor == 0) { /* * Call register_console() if this is the first device plugged @@ -301,7 +283,7 @@ void usb_serial_console_init(int serial_debug, int minor) * register_console). console_write() is called immediately * from register_console iff CON_PRINTBUFFER is set in flags. */ - dbg("registering the USB serial console."); + pr_debug("registering the USB serial console.\n"); register_console(&usbcons); } } diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index 8d7731dbf47..330df5ce435 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -24,10 +24,6 @@ #include <linux/uaccess.h> #include <linux/usb/serial.h> -/* - * Version Information - */ -#define DRIVER_VERSION "v0.09" #define DRIVER_DESC "Silicon Labs CP210x RS232 serial adaptor driver" /* @@ -35,23 +31,21 @@ */ static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *); static void cp210x_close(struct usb_serial_port *); -static void cp210x_get_termios(struct tty_struct *, - struct usb_serial_port *port); +static void cp210x_get_termios(struct tty_struct *, struct usb_serial_port *); static void cp210x_get_termios_port(struct usb_serial_port *port, unsigned int *cflagp, unsigned int *baudp); +static void cp210x_change_speed(struct tty_struct *, struct usb_serial_port *, + struct ktermios *); static void cp210x_set_termios(struct tty_struct *, struct usb_serial_port *, struct ktermios*); -static int cp210x_tiocmget(struct tty_struct *, struct file *); -static int cp210x_tiocmset(struct tty_struct *, struct file *, - unsigned int, unsigned int); -static int cp210x_tiocmset_port(struct usb_serial_port *port, struct file *, +static int cp210x_tiocmget(struct tty_struct *); +static int cp210x_tiocmset(struct tty_struct *, unsigned int, unsigned int); +static int cp210x_tiocmset_port(struct usb_serial_port *port, unsigned int, unsigned int); static void cp210x_break_ctl(struct tty_struct *, int); static int cp210x_startup(struct usb_serial *); +static void cp210x_release(struct usb_serial *); static void cp210x_dtr_rts(struct usb_serial_port *p, int on); -static int cp210x_carrier_raised(struct usb_serial_port *p); - -static int debug; static const struct usb_device_id id_table[] = { { USB_DEVICE(0x045B, 0x0053) }, /* Renesas RX610 RX-Stick */ @@ -59,6 +53,7 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x0489, 0xE000) }, /* Pirelli Broadband S.p.A, DP-L10 SIP/GSM Mobile */ { USB_DEVICE(0x0489, 0xE003) }, /* Pirelli Broadband S.p.A, DP-L10 SIP/GSM Mobile */ { USB_DEVICE(0x0745, 0x1000) }, /* CipherLab USB CCD Barcode Scanner 1000 */ + { USB_DEVICE(0x0846, 0x1100) }, /* NetGear Managed Switch M4100 series, M5300 series, M7100 series */ { USB_DEVICE(0x08e6, 0x5501) }, /* Gemalto Prox-PU/CU contactless smartcard reader */ { USB_DEVICE(0x08FD, 0x000A) }, /* Digianswer A/S , ZigBee/802.15.4 MAC Device */ { USB_DEVICE(0x0BED, 0x1100) }, /* MEI (TM) Cashflow-SC Bill/Voucher Acceptor */ @@ -66,6 +61,7 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x0FCF, 0x1003) }, /* Dynastream ANT development board */ { USB_DEVICE(0x0FCF, 0x1004) }, /* Dynastream ANT2USB */ { USB_DEVICE(0x0FCF, 0x1006) }, /* Dynastream ANT development board */ + { USB_DEVICE(0x0FDE, 0xCA05) }, /* OWL Wireless Electricity Monitor CM-160 */ { USB_DEVICE(0x10A6, 0xAA26) }, /* Knock-off DCU-11 cable */ { USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */ { USB_DEVICE(0x10B5, 0xAC70) }, /* Nokia CA-42 USB */ @@ -81,20 +77,23 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x10C4, 0x8066) }, /* Argussoft In-System Programmer */ { USB_DEVICE(0x10C4, 0x806F) }, /* IMS USB to RS422 Converter Cable */ { USB_DEVICE(0x10C4, 0x807A) }, /* Crumb128 board */ + { USB_DEVICE(0x10C4, 0x80C4) }, /* Cygnal Integrated Products, Inc., Optris infrared thermometer */ { USB_DEVICE(0x10C4, 0x80CA) }, /* Degree Controls Inc */ { USB_DEVICE(0x10C4, 0x80DD) }, /* Tracient RFID */ { USB_DEVICE(0x10C4, 0x80F6) }, /* Suunto sports instrument */ { USB_DEVICE(0x10C4, 0x8115) }, /* Arygon NFC/Mifare Reader */ { USB_DEVICE(0x10C4, 0x813D) }, /* Burnside Telecom Deskmobile */ { USB_DEVICE(0x10C4, 0x813F) }, /* Tams Master Easy Control */ - { USB_DEVICE(0x10C4, 0x8149) }, /* West Mountain Radio Computerized Battery Analyzer */ { USB_DEVICE(0x10C4, 0x814A) }, /* West Mountain Radio RIGblaster P&P */ { USB_DEVICE(0x10C4, 0x814B) }, /* West Mountain Radio RIGtalk */ + { USB_DEVICE(0x2405, 0x0003) }, /* West Mountain Radio RIGblaster Advantage */ { USB_DEVICE(0x10C4, 0x8156) }, /* B&G H3000 link cable */ { USB_DEVICE(0x10C4, 0x815E) }, /* Helicomm IP-Link 1220-DVM */ + { USB_DEVICE(0x10C4, 0x815F) }, /* Timewave HamLinkUSB */ { USB_DEVICE(0x10C4, 0x818B) }, /* AVIT Research USB to TTL */ { USB_DEVICE(0x10C4, 0x819F) }, /* MJS USB Toslink Switcher */ { USB_DEVICE(0x10C4, 0x81A6) }, /* ThinkOptics WavIt */ + { USB_DEVICE(0x10C4, 0x81A9) }, /* Multiplex RC Interface */ { USB_DEVICE(0x10C4, 0x81AC) }, /* MSD Dash Hawk */ { USB_DEVICE(0x10C4, 0x81AD) }, /* INSYS USB Modem */ { USB_DEVICE(0x10C4, 0x81C8) }, /* Lipowsky Industrie Elektronik GmbH, Baby-JTAG */ @@ -104,17 +103,29 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x10C4, 0x81F2) }, /* C1007 HF band RFID controller */ { USB_DEVICE(0x10C4, 0x8218) }, /* Lipowsky Industrie Elektronik GmbH, HARP-1 */ { USB_DEVICE(0x10C4, 0x822B) }, /* Modem EDGE(GSM) Comander 2 */ - { USB_DEVICE(0x10C4, 0x826B) }, /* Cygnal Integrated Products, Inc., Fasttrax GPS demostration module */ - { USB_DEVICE(0x10C4, 0x8293) }, /* Telegesys ETRX2USB */ + { USB_DEVICE(0x10C4, 0x826B) }, /* Cygnal Integrated Products, Inc., Fasttrax GPS demonstration module */ + { USB_DEVICE(0x10C4, 0x8281) }, /* Nanotec Plug & Drive */ + { USB_DEVICE(0x10C4, 0x8293) }, /* Telegesis ETRX2USB */ { USB_DEVICE(0x10C4, 0x82F9) }, /* Procyon AVS */ { USB_DEVICE(0x10C4, 0x8341) }, /* Siemens MC35PU GPRS Modem */ { USB_DEVICE(0x10C4, 0x8382) }, /* Cygnal Integrated Products, Inc. */ { USB_DEVICE(0x10C4, 0x83A8) }, /* Amber Wireless AMB2560 */ + { USB_DEVICE(0x10C4, 0x83D8) }, /* DekTec DTA Plus VHF/UHF Booster/Attenuator */ { USB_DEVICE(0x10C4, 0x8411) }, /* Kyocera GPS Module */ + { USB_DEVICE(0x10C4, 0x8418) }, /* IRZ Automation Teleport SG-10 GSM/GPRS Modem */ { USB_DEVICE(0x10C4, 0x846E) }, /* BEI USB Sensor Interface (VCP) */ { USB_DEVICE(0x10C4, 0x8477) }, /* Balluff RFID */ + { USB_DEVICE(0x10C4, 0x85EA) }, /* AC-Services IBUS-IF */ + { USB_DEVICE(0x10C4, 0x85EB) }, /* AC-Services CIS-IBUS */ + { USB_DEVICE(0x10C4, 0x85F8) }, /* Virtenio Preon32 */ + { USB_DEVICE(0x10C4, 0x8664) }, /* AC-Services CAN-IF */ + { USB_DEVICE(0x10C4, 0x8665) }, /* AC-Services OBD-IF */ + { USB_DEVICE(0x10C4, 0x88A4) }, /* MMB Networks ZigBee USB Device */ + { USB_DEVICE(0x10C4, 0x88A5) }, /* Planet Innovation Ingeni ZigBee USB Device */ { USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */ { USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */ + { USB_DEVICE(0x10C4, 0xEA70) }, /* Silicon Labs factory default */ + { USB_DEVICE(0x10C4, 0xEA80) }, /* Silicon Labs factory default */ { USB_DEVICE(0x10C4, 0xEA71) }, /* Infinity GPS-MIC-1 Radio Monophone */ { USB_DEVICE(0x10C4, 0xF001) }, /* Elan Digital Systems USBscope50 */ { USB_DEVICE(0x10C4, 0xF002) }, /* Elan Digital Systems USBwave12 */ @@ -124,36 +135,65 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x10CE, 0xEA6A) }, /* Silicon Labs MobiData GPRS USB Modem 100EU */ { USB_DEVICE(0x13AD, 0x9999) }, /* Baltech card reader */ { USB_DEVICE(0x1555, 0x0004) }, /* Owen AC4 USB-RS485 Converter */ + { USB_DEVICE(0x166A, 0x0201) }, /* Clipsal 5500PACA C-Bus Pascal Automation Controller */ + { USB_DEVICE(0x166A, 0x0301) }, /* Clipsal 5800PC C-Bus Wireless PC Interface */ { USB_DEVICE(0x166A, 0x0303) }, /* Clipsal 5500PCU C-Bus USB interface */ + { USB_DEVICE(0x166A, 0x0304) }, /* Clipsal 5000CT2 C-Bus Black and White Touchscreen */ + { USB_DEVICE(0x166A, 0x0305) }, /* Clipsal C-5000CT2 C-Bus Spectrum Colour Touchscreen */ + { USB_DEVICE(0x166A, 0x0401) }, /* Clipsal L51xx C-Bus Architectural Dimmer */ + { USB_DEVICE(0x166A, 0x0101) }, /* Clipsal 5560884 C-Bus Multi-room Audio Matrix Switcher */ { USB_DEVICE(0x16D6, 0x0001) }, /* Jablotron serial interface */ { USB_DEVICE(0x16DC, 0x0010) }, /* W-IE-NE-R Plein & Baus GmbH PL512 Power Supply */ { USB_DEVICE(0x16DC, 0x0011) }, /* W-IE-NE-R Plein & Baus GmbH RCM Remote Control for MARATON Power Supply */ { USB_DEVICE(0x16DC, 0x0012) }, /* W-IE-NE-R Plein & Baus GmbH MPOD Multi Channel Power Supply */ { USB_DEVICE(0x16DC, 0x0015) }, /* W-IE-NE-R Plein & Baus GmbH CML Control, Monitoring and Data Logger */ + { USB_DEVICE(0x17A8, 0x0001) }, /* Kamstrup Optical Eye/3-wire */ + { USB_DEVICE(0x17A8, 0x0005) }, /* Kamstrup M-Bus Master MultiPort 250D */ { USB_DEVICE(0x17F4, 0xAAAA) }, /* Wavesense Jazz blood glucose meter */ { USB_DEVICE(0x1843, 0x0200) }, /* Vaisala USB Instrument Cable */ { USB_DEVICE(0x18EF, 0xE00F) }, /* ELV USB-I2C-Interface */ + { USB_DEVICE(0x1ADB, 0x0001) }, /* Schweitzer Engineering C662 Cable */ + { USB_DEVICE(0x1B1C, 0x1C00) }, /* Corsair USB Dongle */ { USB_DEVICE(0x1BE3, 0x07A6) }, /* WAGO 750-923 USB Service Cable */ + { USB_DEVICE(0x1E29, 0x0102) }, /* Festo CPX-USB */ + { USB_DEVICE(0x1E29, 0x0501) }, /* Festo CMSP */ + { USB_DEVICE(0x1FB9, 0x0100) }, /* Lake Shore Model 121 Current Source */ + { USB_DEVICE(0x1FB9, 0x0200) }, /* Lake Shore Model 218A Temperature Monitor */ + { USB_DEVICE(0x1FB9, 0x0201) }, /* Lake Shore Model 219 Temperature Monitor */ + { USB_DEVICE(0x1FB9, 0x0202) }, /* Lake Shore Model 233 Temperature Transmitter */ + { USB_DEVICE(0x1FB9, 0x0203) }, /* Lake Shore Model 235 Temperature Transmitter */ + { USB_DEVICE(0x1FB9, 0x0300) }, /* Lake Shore Model 335 Temperature Controller */ + { USB_DEVICE(0x1FB9, 0x0301) }, /* Lake Shore Model 336 Temperature Controller */ + { USB_DEVICE(0x1FB9, 0x0302) }, /* Lake Shore Model 350 Temperature Controller */ + { USB_DEVICE(0x1FB9, 0x0303) }, /* Lake Shore Model 371 AC Bridge */ + { USB_DEVICE(0x1FB9, 0x0400) }, /* Lake Shore Model 411 Handheld Gaussmeter */ + { USB_DEVICE(0x1FB9, 0x0401) }, /* Lake Shore Model 425 Gaussmeter */ + { USB_DEVICE(0x1FB9, 0x0402) }, /* Lake Shore Model 455A Gaussmeter */ + { USB_DEVICE(0x1FB9, 0x0403) }, /* Lake Shore Model 475A Gaussmeter */ + { USB_DEVICE(0x1FB9, 0x0404) }, /* Lake Shore Model 465 Three Axis Gaussmeter */ + { USB_DEVICE(0x1FB9, 0x0600) }, /* Lake Shore Model 625A Superconducting MPS */ + { USB_DEVICE(0x1FB9, 0x0601) }, /* Lake Shore Model 642A Magnet Power Supply */ + { USB_DEVICE(0x1FB9, 0x0602) }, /* Lake Shore Model 648 Magnet Power Supply */ + { USB_DEVICE(0x1FB9, 0x0700) }, /* Lake Shore Model 737 VSM Controller */ + { USB_DEVICE(0x1FB9, 0x0701) }, /* Lake Shore Model 776 Hall Matrix */ + { USB_DEVICE(0x3195, 0xF190) }, /* Link Instruments MSO-19 */ + { USB_DEVICE(0x3195, 0xF280) }, /* Link Instruments MSO-28 */ + { USB_DEVICE(0x3195, 0xF281) }, /* Link Instruments MSO-28 */ { USB_DEVICE(0x413C, 0x9500) }, /* DW700 GPS USB interface */ { } /* Terminating Entry */ }; MODULE_DEVICE_TABLE(usb, id_table); -static struct usb_driver cp210x_driver = { - .name = "cp210x", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, - .no_dynamic_id = 1, +struct cp210x_serial_private { + __u8 bInterfaceNumber; }; static struct usb_serial_driver cp210x_device = { .driver = { .owner = THIS_MODULE, - .name = "cp210x", + .name = "cp210x", }, - .usb_driver = &cp210x_driver, .id_table = id_table, .num_ports = 1, .bulk_in_size = 256, @@ -162,16 +202,22 @@ static struct usb_serial_driver cp210x_device = { .close = cp210x_close, .break_ctl = cp210x_break_ctl, .set_termios = cp210x_set_termios, - .tiocmget = cp210x_tiocmget, + .tiocmget = cp210x_tiocmget, .tiocmset = cp210x_tiocmset, .attach = cp210x_startup, - .dtr_rts = cp210x_dtr_rts, - .carrier_raised = cp210x_carrier_raised + .release = cp210x_release, + .dtr_rts = cp210x_dtr_rts +}; + +static struct usb_serial_driver * const serial_drivers[] = { + &cp210x_device, NULL }; /* Config request types */ -#define REQTYPE_HOST_TO_DEVICE 0x41 -#define REQTYPE_DEVICE_TO_HOST 0xc1 +#define REQTYPE_HOST_TO_INTERFACE 0x41 +#define REQTYPE_INTERFACE_TO_HOST 0xc1 +#define REQTYPE_HOST_TO_DEVICE 0x40 +#define REQTYPE_DEVICE_TO_HOST 0xc0 /* Config request codes */ #define CP210X_IFC_ENABLE 0x00 @@ -198,6 +244,8 @@ static struct usb_serial_driver cp210x_device = { #define CP210X_EMBED_EVENTS 0x15 #define CP210X_GET_EVENTSTATE 0x16 #define CP210X_SET_CHARS 0x19 +#define CP210X_GET_BAUDRATE 0x1D +#define CP210X_SET_BAUDRATE 0x1E /* CP210X_IFC_ENABLE */ #define UART_ENABLE 0x0001 @@ -251,22 +299,22 @@ static int cp210x_get_config(struct usb_serial_port *port, u8 request, unsigned int *data, int size) { struct usb_serial *serial = port->serial; + struct cp210x_serial_private *spriv = usb_get_serial_data(serial); __le32 *buf; int result, i, length; /* Number of integers required to contain the array */ - length = (((size - 1) | 3) + 1)/4; + length = (((size - 1) | 3) + 1) / 4; buf = kcalloc(length, sizeof(__le32), GFP_KERNEL); - if (!buf) { - dev_err(&port->dev, "%s - out of memory.\n", __func__); + if (!buf) return -ENOMEM; - } /* Issue the request, attempting to read 'size' bytes */ result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), - request, REQTYPE_DEVICE_TO_HOST, 0x0000, - 0, buf, size, 300); + request, REQTYPE_INTERFACE_TO_HOST, 0x0000, + spriv->bInterfaceNumber, buf, size, + USB_CTRL_GET_TIMEOUT); /* Convert data into an array of integers */ for (i = 0; i < length; i++) @@ -275,10 +323,12 @@ static int cp210x_get_config(struct usb_serial_port *port, u8 request, kfree(buf); if (result != size) { - dbg("%s - Unable to send config request, " - "request=0x%x size=%d result=%d\n", - __func__, request, size, result); - return -EPROTO; + dev_dbg(&port->dev, "%s - Unable to send config request, request=0x%x size=%d result=%d\n", + __func__, request, size, result); + if (result > 0) + result = -EPROTO; + + return result; } return 0; @@ -294,18 +344,16 @@ static int cp210x_set_config(struct usb_serial_port *port, u8 request, unsigned int *data, int size) { struct usb_serial *serial = port->serial; + struct cp210x_serial_private *spriv = usb_get_serial_data(serial); __le32 *buf; int result, i, length; /* Number of integers required to contain the array */ - length = (((size - 1) | 3) + 1)/4; + length = (((size - 1) | 3) + 1) / 4; buf = kmalloc(length * sizeof(__le32), GFP_KERNEL); - if (!buf) { - dev_err(&port->dev, "%s - out of memory.\n", - __func__); + if (!buf) return -ENOMEM; - } /* Array of integers into bytes */ for (i = 0; i < length; i++) @@ -314,22 +362,26 @@ static int cp210x_set_config(struct usb_serial_port *port, u8 request, if (size > 2) { result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - request, REQTYPE_HOST_TO_DEVICE, 0x0000, - 0, buf, size, 300); + request, REQTYPE_HOST_TO_INTERFACE, 0x0000, + spriv->bInterfaceNumber, buf, size, + USB_CTRL_SET_TIMEOUT); } else { result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - request, REQTYPE_HOST_TO_DEVICE, data[0], - 0, NULL, 0, 300); + request, REQTYPE_HOST_TO_INTERFACE, data[0], + spriv->bInterfaceNumber, NULL, 0, + USB_CTRL_SET_TIMEOUT); } kfree(buf); if ((size > 2 && result != size) || result < 0) { - dbg("%s - Unable to send request, " - "request=0x%x size=%d result=%d\n", - __func__, request, size, result); - return -EPROTO; + dev_dbg(&port->dev, "%s - Unable to send request, request=0x%x size=%d result=%d\n", + __func__, request, size, result); + if (result > 0) + result = -EPROTO; + + return result; } return 0; @@ -350,9 +402,10 @@ static inline int cp210x_set_config_single(struct usb_serial_port *port, * cp210x_quantise_baudrate * Quantises the baud rate as per AN205 Table 1 */ -static unsigned int cp210x_quantise_baudrate(unsigned int baud) { - if (baud <= 56) baud = 0; - else if (baud <= 300) baud = 300; +static unsigned int cp210x_quantise_baudrate(unsigned int baud) +{ + if (baud <= 300) + baud = 300; else if (baud <= 600) baud = 600; else if (baud <= 1200) baud = 1200; else if (baud <= 1800) baud = 1800; @@ -380,10 +433,10 @@ static unsigned int cp210x_quantise_baudrate(unsigned int baud) { else if (baud <= 491520) baud = 460800; else if (baud <= 567138) baud = 500000; else if (baud <= 670254) baud = 576000; - else if (baud <= 1053257) baud = 921600; - else if (baud <= 1474560) baud = 1228800; - else if (baud <= 2457600) baud = 1843200; - else baud = 3686400; + else if (baud < 1000000) + baud = 921600; + else if (baud > 2000000) + baud = 2000000; return baud; } @@ -391,33 +444,27 @@ static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port) { int result; - dbg("%s - port %d", __func__, port->number); - - if (cp210x_set_config_single(port, CP210X_IFC_ENABLE, UART_ENABLE)) { - dev_err(&port->dev, "%s - Unable to enable UART\n", - __func__); - return -EPROTO; - } - - result = usb_serial_generic_open(tty, port); - if (result) + result = cp210x_set_config_single(port, CP210X_IFC_ENABLE, + UART_ENABLE); + if (result) { + dev_err(&port->dev, "%s - Unable to enable UART\n", __func__); return result; + } /* Configure the termios structure */ cp210x_get_termios(tty, port); - return 0; + + /* The baud rate must be initialised on cp2104 */ + if (tty) + cp210x_change_speed(tty, port, NULL); + + return usb_serial_generic_open(tty, port); } static void cp210x_close(struct usb_serial_port *port) { - dbg("%s - port %d", __func__, port->number); - usb_serial_generic_close(port); - - mutex_lock(&port->serial->disc_mutex); - if (!port->serial->disconnected) - cp210x_set_config_single(port, CP210X_IFC_ENABLE, UART_DISABLE); - mutex_unlock(&port->serial->disc_mutex); + cp210x_set_config_single(port, CP210X_IFC_ENABLE, UART_DISABLE); } /* @@ -433,11 +480,9 @@ static void cp210x_get_termios(struct tty_struct *tty, if (tty) { cp210x_get_termios_port(tty->driver_data, - &tty->termios->c_cflag, &baud); + &tty->termios.c_cflag, &baud); tty_encode_baud_rate(tty, baud, baud); - } - - else { + } else { unsigned int cflag; cflag = 0; cp210x_get_termios_port(port, &cflag, &baud); @@ -451,18 +496,14 @@ static void cp210x_get_termios(struct tty_struct *tty, static void cp210x_get_termios_port(struct usb_serial_port *port, unsigned int *cflagp, unsigned int *baudp) { + struct device *dev = &port->dev; unsigned int cflag, modem_ctl[4]; unsigned int baud; unsigned int bits; - dbg("%s - port %d", __func__, port->number); - - cp210x_get_config(port, CP210X_GET_BAUDDIV, &baud, 2); - /* Convert to baudrate */ - if (baud) - baud = cp210x_quantise_baudrate((BAUD_RATE_GEN_FREQ + baud/2)/ baud); + cp210x_get_config(port, CP210X_GET_BAUDRATE, &baud, 4); - dbg("%s - baud rate = %d", __func__, baud); + dev_dbg(dev, "%s - baud rate = %d\n", __func__, baud); *baudp = baud; cflag = *cflagp; @@ -471,31 +512,30 @@ static void cp210x_get_termios_port(struct usb_serial_port *port, cflag &= ~CSIZE; switch (bits & BITS_DATA_MASK) { case BITS_DATA_5: - dbg("%s - data bits = 5", __func__); + dev_dbg(dev, "%s - data bits = 5\n", __func__); cflag |= CS5; break; case BITS_DATA_6: - dbg("%s - data bits = 6", __func__); + dev_dbg(dev, "%s - data bits = 6\n", __func__); cflag |= CS6; break; case BITS_DATA_7: - dbg("%s - data bits = 7", __func__); + dev_dbg(dev, "%s - data bits = 7\n", __func__); cflag |= CS7; break; case BITS_DATA_8: - dbg("%s - data bits = 8", __func__); + dev_dbg(dev, "%s - data bits = 8\n", __func__); cflag |= CS8; break; case BITS_DATA_9: - dbg("%s - data bits = 9 (not supported, using 8 data bits)", - __func__); + dev_dbg(dev, "%s - data bits = 9 (not supported, using 8 data bits)\n", __func__); cflag |= CS8; bits &= ~BITS_DATA_MASK; bits |= BITS_DATA_8; cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2); break; default: - dbg("%s - Unknown number of data bits, using 8", __func__); + dev_dbg(dev, "%s - Unknown number of data bits, using 8\n", __func__); cflag |= CS8; bits &= ~BITS_DATA_MASK; bits |= BITS_DATA_8; @@ -505,34 +545,29 @@ static void cp210x_get_termios_port(struct usb_serial_port *port, switch (bits & BITS_PARITY_MASK) { case BITS_PARITY_NONE: - dbg("%s - parity = NONE", __func__); + dev_dbg(dev, "%s - parity = NONE\n", __func__); cflag &= ~PARENB; break; case BITS_PARITY_ODD: - dbg("%s - parity = ODD", __func__); + dev_dbg(dev, "%s - parity = ODD\n", __func__); cflag |= (PARENB|PARODD); break; case BITS_PARITY_EVEN: - dbg("%s - parity = EVEN", __func__); + dev_dbg(dev, "%s - parity = EVEN\n", __func__); cflag &= ~PARODD; cflag |= PARENB; break; case BITS_PARITY_MARK: - dbg("%s - parity = MARK (not supported, disabling parity)", - __func__); - cflag &= ~PARENB; - bits &= ~BITS_PARITY_MASK; - cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2); + dev_dbg(dev, "%s - parity = MARK\n", __func__); + cflag |= (PARENB|PARODD|CMSPAR); break; case BITS_PARITY_SPACE: - dbg("%s - parity = SPACE (not supported, disabling parity)", - __func__); - cflag &= ~PARENB; - bits &= ~BITS_PARITY_MASK; - cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2); + dev_dbg(dev, "%s - parity = SPACE\n", __func__); + cflag &= ~PARODD; + cflag |= (PARENB|CMSPAR); break; default: - dbg("%s - Unknown parity mode, disabling parity", __func__); + dev_dbg(dev, "%s - Unknown parity mode, disabling parity\n", __func__); cflag &= ~PARENB; bits &= ~BITS_PARITY_MASK; cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2); @@ -542,21 +577,19 @@ static void cp210x_get_termios_port(struct usb_serial_port *port, cflag &= ~CSTOPB; switch (bits & BITS_STOP_MASK) { case BITS_STOP_1: - dbg("%s - stop bits = 1", __func__); + dev_dbg(dev, "%s - stop bits = 1\n", __func__); break; case BITS_STOP_1_5: - dbg("%s - stop bits = 1.5 (not supported, using 1 stop bit)", - __func__); + dev_dbg(dev, "%s - stop bits = 1.5 (not supported, using 1 stop bit)\n", __func__); bits &= ~BITS_STOP_MASK; cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2); break; case BITS_STOP_2: - dbg("%s - stop bits = 2", __func__); + dev_dbg(dev, "%s - stop bits = 2\n", __func__); cflag |= CSTOPB; break; default: - dbg("%s - Unknown number of stop bits, using 1 stop bit", - __func__); + dev_dbg(dev, "%s - Unknown number of stop bits, using 1 stop bit\n", __func__); bits &= ~BITS_STOP_MASK; cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2); break; @@ -564,45 +597,82 @@ static void cp210x_get_termios_port(struct usb_serial_port *port, cp210x_get_config(port, CP210X_GET_FLOW, modem_ctl, 16); if (modem_ctl[0] & 0x0008) { - dbg("%s - flow control = CRTSCTS", __func__); + dev_dbg(dev, "%s - flow control = CRTSCTS\n", __func__); cflag |= CRTSCTS; } else { - dbg("%s - flow control = NONE", __func__); + dev_dbg(dev, "%s - flow control = NONE\n", __func__); cflag &= ~CRTSCTS; } *cflagp = cflag; } +/* + * CP2101 supports the following baud rates: + * + * 300, 600, 1200, 1800, 2400, 4800, 7200, 9600, 14400, 19200, 28800, + * 38400, 56000, 57600, 115200, 128000, 230400, 460800, 921600 + * + * CP2102 and CP2103 support the following additional rates: + * + * 4000, 16000, 51200, 64000, 76800, 153600, 250000, 256000, 500000, + * 576000 + * + * The device will map a requested rate to a supported one, but the result + * of requests for rates greater than 1053257 is undefined (see AN205). + * + * CP2104, CP2105 and CP2110 support most rates up to 2M, 921k and 1M baud, + * respectively, with an error less than 1%. The actual rates are determined + * by + * + * div = round(freq / (2 x prescale x request)) + * actual = freq / (2 x prescale x div) + * + * For CP2104 and CP2105 freq is 48Mhz and prescale is 4 for request <= 365bps + * or 1 otherwise. + * For CP2110 freq is 24Mhz and prescale is 4 for request <= 300bps or 1 + * otherwise. + */ +static void cp210x_change_speed(struct tty_struct *tty, + struct usb_serial_port *port, struct ktermios *old_termios) +{ + u32 baud; + + baud = tty->termios.c_ospeed; + + /* This maps the requested rate to a rate valid on cp2102 or cp2103, + * or to an arbitrary rate in [1M,2M]. + * + * NOTE: B0 is not implemented. + */ + baud = cp210x_quantise_baudrate(baud); + + dev_dbg(&port->dev, "%s - setting baud rate to %u\n", __func__, baud); + if (cp210x_set_config(port, CP210X_SET_BAUDRATE, &baud, + sizeof(baud))) { + dev_warn(&port->dev, "failed to set baud rate to %u\n", baud); + if (old_termios) + baud = old_termios->c_ospeed; + else + baud = 9600; + } + + tty_encode_baud_rate(tty, baud, baud); +} + static void cp210x_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios) { + struct device *dev = &port->dev; unsigned int cflag, old_cflag; - unsigned int baud = 0, bits; + unsigned int bits; unsigned int modem_ctl[4]; - dbg("%s - port %d", __func__, port->number); - - if (!tty) - return; - - tty->termios->c_cflag &= ~CMSPAR; - cflag = tty->termios->c_cflag; + cflag = tty->termios.c_cflag; old_cflag = old_termios->c_cflag; - baud = cp210x_quantise_baudrate(tty_get_baud_rate(tty)); - - /* If the baud rate is to be updated*/ - if (baud != tty_termios_baud_rate(old_termios) && baud != 0) { - dbg("%s - Setting baud rate to %d baud", __func__, - baud); - if (cp210x_set_config_single(port, CP210X_SET_BAUDDIV, - ((BAUD_RATE_GEN_FREQ + baud/2) / baud))) { - dbg("Baud rate requested not supported by device"); - baud = tty_termios_baud_rate(old_termios); - } - } - /* Report back the resulting baud rate */ - tty_encode_baud_rate(tty, baud, baud); + + if (tty->termios.c_ospeed != old_termios->c_ospeed) + cp210x_change_speed(tty, port, old_termios); /* If the number of data bits is to be updated */ if ((cflag & CSIZE) != (old_cflag & CSIZE)) { @@ -611,51 +681,58 @@ static void cp210x_set_termios(struct tty_struct *tty, switch (cflag & CSIZE) { case CS5: bits |= BITS_DATA_5; - dbg("%s - data bits = 5", __func__); + dev_dbg(dev, "%s - data bits = 5\n", __func__); break; case CS6: bits |= BITS_DATA_6; - dbg("%s - data bits = 6", __func__); + dev_dbg(dev, "%s - data bits = 6\n", __func__); break; case CS7: bits |= BITS_DATA_7; - dbg("%s - data bits = 7", __func__); + dev_dbg(dev, "%s - data bits = 7\n", __func__); break; case CS8: bits |= BITS_DATA_8; - dbg("%s - data bits = 8", __func__); + dev_dbg(dev, "%s - data bits = 8\n", __func__); break; /*case CS9: bits |= BITS_DATA_9; - dbg("%s - data bits = 9", __func__); + dev_dbg(dev, "%s - data bits = 9\n", __func__); break;*/ default: - dbg("cp210x driver does not " - "support the number of bits requested," - " using 8 bit mode\n"); - bits |= BITS_DATA_8; - break; + dev_dbg(dev, "cp210x driver does not support the number of bits requested, using 8 bit mode\n"); + bits |= BITS_DATA_8; + break; } if (cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2)) - dbg("Number of data bits requested " - "not supported by device\n"); + dev_dbg(dev, "Number of data bits requested not supported by device\n"); } - if ((cflag & (PARENB|PARODD)) != (old_cflag & (PARENB|PARODD))) { + if ((cflag & (PARENB|PARODD|CMSPAR)) != + (old_cflag & (PARENB|PARODD|CMSPAR))) { cp210x_get_config(port, CP210X_GET_LINE_CTL, &bits, 2); bits &= ~BITS_PARITY_MASK; if (cflag & PARENB) { - if (cflag & PARODD) { - bits |= BITS_PARITY_ODD; - dbg("%s - parity = ODD", __func__); + if (cflag & CMSPAR) { + if (cflag & PARODD) { + bits |= BITS_PARITY_MARK; + dev_dbg(dev, "%s - parity = MARK\n", __func__); + } else { + bits |= BITS_PARITY_SPACE; + dev_dbg(dev, "%s - parity = SPACE\n", __func__); + } } else { - bits |= BITS_PARITY_EVEN; - dbg("%s - parity = EVEN", __func__); + if (cflag & PARODD) { + bits |= BITS_PARITY_ODD; + dev_dbg(dev, "%s - parity = ODD\n", __func__); + } else { + bits |= BITS_PARITY_EVEN; + dev_dbg(dev, "%s - parity = EVEN\n", __func__); + } } } if (cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2)) - dbg("Parity mode not supported " - "by device\n"); + dev_dbg(dev, "Parity mode not supported by device\n"); } if ((cflag & CSTOPB) != (old_cflag & CSTOPB)) { @@ -663,56 +740,53 @@ static void cp210x_set_termios(struct tty_struct *tty, bits &= ~BITS_STOP_MASK; if (cflag & CSTOPB) { bits |= BITS_STOP_2; - dbg("%s - stop bits = 2", __func__); + dev_dbg(dev, "%s - stop bits = 2\n", __func__); } else { bits |= BITS_STOP_1; - dbg("%s - stop bits = 1", __func__); + dev_dbg(dev, "%s - stop bits = 1\n", __func__); } if (cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2)) - dbg("Number of stop bits requested " - "not supported by device\n"); + dev_dbg(dev, "Number of stop bits requested not supported by device\n"); } if ((cflag & CRTSCTS) != (old_cflag & CRTSCTS)) { cp210x_get_config(port, CP210X_GET_FLOW, modem_ctl, 16); - dbg("%s - read modem controls = 0x%.4x 0x%.4x 0x%.4x 0x%.4x", - __func__, modem_ctl[0], modem_ctl[1], - modem_ctl[2], modem_ctl[3]); + dev_dbg(dev, "%s - read modem controls = 0x%.4x 0x%.4x 0x%.4x 0x%.4x\n", + __func__, modem_ctl[0], modem_ctl[1], + modem_ctl[2], modem_ctl[3]); if (cflag & CRTSCTS) { modem_ctl[0] &= ~0x7B; modem_ctl[0] |= 0x09; modem_ctl[1] = 0x80; - dbg("%s - flow control = CRTSCTS", __func__); + dev_dbg(dev, "%s - flow control = CRTSCTS\n", __func__); } else { modem_ctl[0] &= ~0x7B; modem_ctl[0] |= 0x01; modem_ctl[1] |= 0x40; - dbg("%s - flow control = NONE", __func__); + dev_dbg(dev, "%s - flow control = NONE\n", __func__); } - dbg("%s - write modem controls = 0x%.4x 0x%.4x 0x%.4x 0x%.4x", - __func__, modem_ctl[0], modem_ctl[1], - modem_ctl[2], modem_ctl[3]); + dev_dbg(dev, "%s - write modem controls = 0x%.4x 0x%.4x 0x%.4x 0x%.4x\n", + __func__, modem_ctl[0], modem_ctl[1], + modem_ctl[2], modem_ctl[3]); cp210x_set_config(port, CP210X_SET_FLOW, modem_ctl, 16); } } -static int cp210x_tiocmset (struct tty_struct *tty, struct file *file, +static int cp210x_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) { struct usb_serial_port *port = tty->driver_data; - return cp210x_tiocmset_port(port, file, set, clear); + return cp210x_tiocmset_port(port, set, clear); } -static int cp210x_tiocmset_port(struct usb_serial_port *port, struct file *file, +static int cp210x_tiocmset_port(struct usb_serial_port *port, unsigned int set, unsigned int clear) { unsigned int control = 0; - dbg("%s - port %d", __func__, port->number); - if (set & TIOCM_RTS) { control |= CONTROL_RTS; control |= CONTROL_WRITE_RTS; @@ -730,7 +804,7 @@ static int cp210x_tiocmset_port(struct usb_serial_port *port, struct file *file, control |= CONTROL_WRITE_DTR; } - dbg("%s - control = 0x%.4x", __func__, control); + dev_dbg(&port->dev, "%s - control = 0x%.4x\n", __func__, control); return cp210x_set_config(port, CP210X_SET_MHS, &control, 2); } @@ -738,19 +812,17 @@ static int cp210x_tiocmset_port(struct usb_serial_port *port, struct file *file, static void cp210x_dtr_rts(struct usb_serial_port *p, int on) { if (on) - cp210x_tiocmset_port(p, NULL, TIOCM_DTR|TIOCM_RTS, 0); + cp210x_tiocmset_port(p, TIOCM_DTR|TIOCM_RTS, 0); else - cp210x_tiocmset_port(p, NULL, 0, TIOCM_DTR|TIOCM_RTS); + cp210x_tiocmset_port(p, 0, TIOCM_DTR|TIOCM_RTS); } -static int cp210x_tiocmget (struct tty_struct *tty, struct file *file) +static int cp210x_tiocmget(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; unsigned int control; int result; - dbg("%s - port %d", __func__, port->number); - cp210x_get_config(port, CP210X_GET_MDMSTS, &control, 1); result = ((control & CONTROL_DTR) ? TIOCM_DTR : 0) @@ -760,75 +832,54 @@ static int cp210x_tiocmget (struct tty_struct *tty, struct file *file) |((control & CONTROL_RING)? TIOCM_RI : 0) |((control & CONTROL_DCD) ? TIOCM_CD : 0); - dbg("%s - control = 0x%.2x", __func__, control); + dev_dbg(&port->dev, "%s - control = 0x%.2x\n", __func__, control); return result; } -static int cp210x_carrier_raised(struct usb_serial_port *p) -{ - unsigned int control; - cp210x_get_config(p, CP210X_GET_MDMSTS, &control, 1); - if (control & CONTROL_DCD) - return 1; - return 0; -} - -static void cp210x_break_ctl (struct tty_struct *tty, int break_state) +static void cp210x_break_ctl(struct tty_struct *tty, int break_state) { struct usb_serial_port *port = tty->driver_data; unsigned int state; - dbg("%s - port %d", __func__, port->number); if (break_state == 0) state = BREAK_OFF; else state = BREAK_ON; - dbg("%s - turning break %s", __func__, - state == BREAK_OFF ? "off" : "on"); + dev_dbg(&port->dev, "%s - turning break %s\n", __func__, + state == BREAK_OFF ? "off" : "on"); cp210x_set_config(port, CP210X_SET_BREAK, &state, 2); } static int cp210x_startup(struct usb_serial *serial) { + struct usb_host_interface *cur_altsetting; + struct cp210x_serial_private *spriv; + /* cp210x buffers behave strangely unless device is reset */ usb_reset_device(serial->dev); - return 0; -} -static int __init cp210x_init(void) -{ - int retval; + spriv = kzalloc(sizeof(*spriv), GFP_KERNEL); + if (!spriv) + return -ENOMEM; - retval = usb_serial_register(&cp210x_device); - if (retval) - return retval; /* Failed to register */ + cur_altsetting = serial->interface->cur_altsetting; + spriv->bInterfaceNumber = cur_altsetting->desc.bInterfaceNumber; - retval = usb_register(&cp210x_driver); - if (retval) { - /* Failed to register */ - usb_serial_deregister(&cp210x_device); - return retval; - } + usb_set_serial_data(serial, spriv); - /* Success */ - printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" - DRIVER_DESC "\n"); return 0; } -static void __exit cp210x_exit(void) +static void cp210x_release(struct usb_serial *serial) { - usb_deregister(&cp210x_driver); - usb_serial_deregister(&cp210x_device); + struct cp210x_serial_private *spriv; + + spriv = usb_get_serial_data(serial); + kfree(spriv); } -module_init(cp210x_init); -module_exit(cp210x_exit); +module_usb_serial_driver(serial_drivers, id_table); MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_VERSION(DRIVER_VERSION); MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Enable verbose debugging messages"); diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c index f744ab7a3b1..2916dea3ede 100644 --- a/drivers/usb/serial/cyberjack.c +++ b/drivers/usb/serial/cyberjack.c @@ -30,7 +30,6 @@ #include <linux/kernel.h> #include <linux/errno.h> -#include <linux/init.h> #include <linux/slab.h> #include <linux/tty.h> #include <linux/tty_driver.h> @@ -43,12 +42,6 @@ #define CYBERJACK_LOCAL_BUF_SIZE 32 -static int debug; - -/* - * Version Information - */ -#define DRIVER_VERSION "v1.01" #define DRIVER_AUTHOR "Matthias Bruestle" #define DRIVER_DESC "REINER SCT cyberJack pinpad/e-com USB Chipcard Reader Driver" @@ -57,9 +50,8 @@ static int debug; #define CYBERJACK_PRODUCT_ID 0x0100 /* Function prototypes */ -static int cyberjack_startup(struct usb_serial *serial); -static void cyberjack_disconnect(struct usb_serial *serial); -static void cyberjack_release(struct usb_serial *serial); +static int cyberjack_port_probe(struct usb_serial_port *port); +static int cyberjack_port_remove(struct usb_serial_port *port); static int cyberjack_open(struct tty_struct *tty, struct usb_serial_port *port); static void cyberjack_close(struct usb_serial_port *port); @@ -77,26 +69,16 @@ static const struct usb_device_id id_table[] = { MODULE_DEVICE_TABLE(usb, id_table); -static struct usb_driver cyberjack_driver = { - .name = "cyberjack", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, - .no_dynamic_id = 1, -}; - static struct usb_serial_driver cyberjack_device = { .driver = { .owner = THIS_MODULE, .name = "cyberjack", }, .description = "Reiner SCT Cyberjack USB card reader", - .usb_driver = &cyberjack_driver, .id_table = id_table, .num_ports = 1, - .attach = cyberjack_startup, - .disconnect = cyberjack_disconnect, - .release = cyberjack_release, + .port_probe = cyberjack_port_probe, + .port_remove = cyberjack_port_remove, .open = cyberjack_open, .close = cyberjack_close, .write = cyberjack_write, @@ -106,6 +88,10 @@ static struct usb_serial_driver cyberjack_device = { .write_bulk_callback = cyberjack_write_bulk_callback, }; +static struct usb_serial_driver * const serial_drivers[] = { + &cyberjack_device, NULL +}; + struct cyberjack_private { spinlock_t lock; /* Lock for SMP */ short rdtodo; /* Bytes still to read */ @@ -114,62 +100,39 @@ struct cyberjack_private { short wrsent; /* Data already sent */ }; -/* do some startup allocations not currently performed by usb_serial_probe() */ -static int cyberjack_startup(struct usb_serial *serial) +static int cyberjack_port_probe(struct usb_serial_port *port) { struct cyberjack_private *priv; - int i; - - dbg("%s", __func__); + int result; - /* allocate the private data structure */ priv = kmalloc(sizeof(struct cyberjack_private), GFP_KERNEL); if (!priv) return -ENOMEM; - /* set initial values */ spin_lock_init(&priv->lock); priv->rdtodo = 0; priv->wrfilled = 0; priv->wrsent = 0; - usb_set_serial_port_data(serial->port[0], priv); - init_waitqueue_head(&serial->port[0]->write_wait); + usb_set_serial_port_data(port, priv); - for (i = 0; i < serial->num_ports; ++i) { - int result; - serial->port[i]->interrupt_in_urb->dev = serial->dev; - result = usb_submit_urb(serial->port[i]->interrupt_in_urb, - GFP_KERNEL); - if (result) - dev_err(&serial->dev->dev, - "usb_submit_urb(read int) failed\n"); - dbg("%s - usb_submit_urb(int urb)", __func__); - } + result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); + if (result) + dev_err(&port->dev, "usb_submit_urb(read int) failed\n"); return 0; } -static void cyberjack_disconnect(struct usb_serial *serial) +static int cyberjack_port_remove(struct usb_serial_port *port) { - int i; - - dbg("%s", __func__); + struct cyberjack_private *priv; - for (i = 0; i < serial->num_ports; ++i) - usb_kill_urb(serial->port[i]->interrupt_in_urb); -} + usb_kill_urb(port->interrupt_in_urb); -static void cyberjack_release(struct usb_serial *serial) -{ - int i; - - dbg("%s", __func__); + priv = usb_get_serial_port_data(port); + kfree(priv); - for (i = 0; i < serial->num_ports; ++i) { - /* My special items, the standard routines free my urbs */ - kfree(usb_get_serial_port_data(serial->port[i])); - } + return 0; } static int cyberjack_open(struct tty_struct *tty, @@ -179,9 +142,7 @@ static int cyberjack_open(struct tty_struct *tty, unsigned long flags; int result = 0; - dbg("%s - port %d", __func__, port->number); - - dbg("%s - usb_clear_halt", __func__); + dev_dbg(&port->dev, "%s - usb_clear_halt\n", __func__); usb_clear_halt(port->serial->dev, port->write_urb->pipe); priv = usb_get_serial_port_data(port); @@ -196,60 +157,48 @@ static int cyberjack_open(struct tty_struct *tty, static void cyberjack_close(struct usb_serial_port *port) { - dbg("%s - port %d", __func__, port->number); - - if (port->serial->dev) { - /* shutdown any bulk reads that might be going on */ - usb_kill_urb(port->write_urb); - usb_kill_urb(port->read_urb); - } + usb_kill_urb(port->write_urb); + usb_kill_urb(port->read_urb); } static int cyberjack_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count) { - struct usb_serial *serial = port->serial; + struct device *dev = &port->dev; struct cyberjack_private *priv = usb_get_serial_port_data(port); unsigned long flags; int result; int wrexpected; - dbg("%s - port %d", __func__, port->number); - if (count == 0) { - dbg("%s - write request of 0 bytes", __func__); + dev_dbg(dev, "%s - write request of 0 bytes\n", __func__); return 0; } - spin_lock_bh(&port->lock); - if (port->write_urb_busy) { - spin_unlock_bh(&port->lock); - dbg("%s - already writing", __func__); + if (!test_and_clear_bit(0, &port->write_urbs_free)) { + dev_dbg(dev, "%s - already writing\n", __func__); return 0; } - port->write_urb_busy = 1; - spin_unlock_bh(&port->lock); spin_lock_irqsave(&priv->lock, flags); if (count+priv->wrfilled > sizeof(priv->wrbuf)) { /* To much data for buffer. Reset buffer. */ priv->wrfilled = 0; - port->write_urb_busy = 0; spin_unlock_irqrestore(&priv->lock, flags); + set_bit(0, &port->write_urbs_free); return 0; } /* Copy data */ memcpy(priv->wrbuf + priv->wrfilled, buf, count); - usb_serial_debug_data(debug, &port->dev, __func__, count, - priv->wrbuf + priv->wrfilled); + usb_serial_debug_data(dev, __func__, count, priv->wrbuf + priv->wrfilled); priv->wrfilled += count; if (priv->wrfilled >= 3) { wrexpected = ((int)priv->wrbuf[2]<<8)+priv->wrbuf[1]+3; - dbg("%s - expected data: %d", __func__, wrexpected); + dev_dbg(dev, "%s - expected data: %d\n", __func__, wrexpected); } else wrexpected = sizeof(priv->wrbuf); @@ -257,7 +206,7 @@ static int cyberjack_write(struct tty_struct *tty, /* We have enough data to begin transmission */ int length; - dbg("%s - transmitting data (frame 1)", __func__); + dev_dbg(dev, "%s - transmitting data (frame 1)\n", __func__); length = (wrexpected > port->bulk_out_size) ? port->bulk_out_size : wrexpected; @@ -265,33 +214,27 @@ static int cyberjack_write(struct tty_struct *tty, priv->wrsent = length; /* set up our urb */ - usb_fill_bulk_urb(port->write_urb, serial->dev, - usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress), - port->write_urb->transfer_buffer, length, - ((serial->type->write_bulk_callback) ? - serial->type->write_bulk_callback : - cyberjack_write_bulk_callback), - port); + port->write_urb->transfer_buffer_length = length; /* send the data out the bulk port */ result = usb_submit_urb(port->write_urb, GFP_ATOMIC); if (result) { dev_err(&port->dev, - "%s - failed submitting write urb, error %d", + "%s - failed submitting write urb, error %d\n", __func__, result); /* Throw away data. No better idea what to do with it. */ priv->wrfilled = 0; priv->wrsent = 0; spin_unlock_irqrestore(&priv->lock, flags); - port->write_urb_busy = 0; + set_bit(0, &port->write_urbs_free); return 0; } - dbg("%s - priv->wrsent=%d", __func__, priv->wrsent); - dbg("%s - priv->wrfilled=%d", __func__, priv->wrfilled); + dev_dbg(dev, "%s - priv->wrsent=%d\n", __func__, priv->wrsent); + dev_dbg(dev, "%s - priv->wrfilled=%d\n", __func__, priv->wrfilled); if (priv->wrsent >= priv->wrfilled) { - dbg("%s - buffer cleaned", __func__); + dev_dbg(dev, "%s - buffer cleaned\n", __func__); memset(priv->wrbuf, 0, sizeof(priv->wrbuf)); priv->wrfilled = 0; priv->wrsent = 0; @@ -313,18 +256,16 @@ static void cyberjack_read_int_callback(struct urb *urb) { struct usb_serial_port *port = urb->context; struct cyberjack_private *priv = usb_get_serial_port_data(port); + struct device *dev = &port->dev; unsigned char *data = urb->transfer_buffer; int status = urb->status; int result; - dbg("%s - port %d", __func__, port->number); - /* the urb might have been killed. */ if (status) return; - usb_serial_debug_data(debug, &port->dev, __func__, - urb->actual_length, data); + usb_serial_debug_data(dev, __func__, urb->actual_length, data); /* React only to interrupts signaling a bulk_in transfer */ if (urb->actual_length == 4 && data[0] == 0x01) { @@ -337,68 +278,56 @@ static void cyberjack_read_int_callback(struct urb *urb) old_rdtodo = priv->rdtodo; - if (old_rdtodo + size < old_rdtodo) { - dbg("To many bulk_in urbs to do."); + if (old_rdtodo > SHRT_MAX - size) { + dev_dbg(dev, "To many bulk_in urbs to do.\n"); spin_unlock(&priv->lock); goto resubmit; } - /* "+=" is probably more fault tollerant than "=" */ + /* "+=" is probably more fault tolerant than "=" */ priv->rdtodo += size; - dbg("%s - rdtodo: %d", __func__, priv->rdtodo); + dev_dbg(dev, "%s - rdtodo: %d\n", __func__, priv->rdtodo); spin_unlock(&priv->lock); if (!old_rdtodo) { - port->read_urb->dev = port->serial->dev; result = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (result) - dev_err(&port->dev, "%s - failed resubmitting " - "read urb, error %d\n", + dev_err(dev, "%s - failed resubmitting read urb, error %d\n", __func__, result); - dbg("%s - usb_submit_urb(read urb)", __func__); + dev_dbg(dev, "%s - usb_submit_urb(read urb)\n", __func__); } } resubmit: - port->interrupt_in_urb->dev = port->serial->dev; result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC); if (result) dev_err(&port->dev, "usb_submit_urb(read int) failed\n"); - dbg("%s - usb_submit_urb(int urb)", __func__); + dev_dbg(dev, "%s - usb_submit_urb(int urb)\n", __func__); } static void cyberjack_read_bulk_callback(struct urb *urb) { struct usb_serial_port *port = urb->context; struct cyberjack_private *priv = usb_get_serial_port_data(port); - struct tty_struct *tty; + struct device *dev = &port->dev; unsigned char *data = urb->transfer_buffer; short todo; int result; int status = urb->status; - dbg("%s - port %d", __func__, port->number); - - usb_serial_debug_data(debug, &port->dev, __func__, - urb->actual_length, data); + usb_serial_debug_data(dev, __func__, urb->actual_length, data); if (status) { - dbg("%s - nonzero read bulk status received: %d", - __func__, status); + dev_dbg(dev, "%s - nonzero read bulk status received: %d\n", + __func__, status); return; } - tty = tty_port_tty_get(&port->port); - if (!tty) { - dbg("%s - ignoring since device not open", __func__); - return; - } if (urb->actual_length) { - tty_insert_flip_string(tty, data, urb->actual_length); - tty_flip_buffer_push(tty); + tty_insert_flip_string(&port->port, data, urb->actual_length); + tty_flip_buffer_push(&port->port); } - tty_kref_put(tty); spin_lock(&priv->lock); @@ -411,16 +340,15 @@ static void cyberjack_read_bulk_callback(struct urb *urb) spin_unlock(&priv->lock); - dbg("%s - rdtodo: %d", __func__, todo); + dev_dbg(dev, "%s - rdtodo: %d\n", __func__, todo); /* Continue to read if we have still urbs to do. */ if (todo /* || (urb->actual_length==port->bulk_in_endpointAddress)*/) { - port->read_urb->dev = port->serial->dev; result = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (result) - dev_err(&port->dev, "%s - failed resubmitting read " - "urb, error %d\n", __func__, result); - dbg("%s - usb_submit_urb(read urb)", __func__); + dev_err(dev, "%s - failed resubmitting read urb, error %d\n", + __func__, result); + dev_dbg(dev, "%s - usb_submit_urb(read urb)\n", __func__); } } @@ -428,14 +356,13 @@ static void cyberjack_write_bulk_callback(struct urb *urb) { struct usb_serial_port *port = urb->context; struct cyberjack_private *priv = usb_get_serial_port_data(port); + struct device *dev = &port->dev; int status = urb->status; - dbg("%s - port %d", __func__, port->number); - - port->write_urb_busy = 0; + set_bit(0, &port->write_urbs_free); if (status) { - dbg("%s - nonzero write bulk status received: %d", - __func__, status); + dev_dbg(dev, "%s - nonzero write bulk status received: %d\n", + __func__, status); return; } @@ -445,7 +372,7 @@ static void cyberjack_write_bulk_callback(struct urb *urb) if (priv->wrfilled) { int length, blksize, result; - dbg("%s - transmitting data (frame n)", __func__); + dev_dbg(dev, "%s - transmitting data (frame n)\n", __func__); length = ((priv->wrfilled - priv->wrsent) > port->bulk_out_size) ? port->bulk_out_size : (priv->wrfilled - priv->wrsent); @@ -455,19 +382,12 @@ static void cyberjack_write_bulk_callback(struct urb *urb) priv->wrsent += length; /* set up our urb */ - usb_fill_bulk_urb(port->write_urb, port->serial->dev, - usb_sndbulkpipe(port->serial->dev, port->bulk_out_endpointAddress), - port->write_urb->transfer_buffer, length, - ((port->serial->type->write_bulk_callback) ? - port->serial->type->write_bulk_callback : - cyberjack_write_bulk_callback), - port); + port->write_urb->transfer_buffer_length = length; /* send the data out the bulk port */ result = usb_submit_urb(port->write_urb, GFP_ATOMIC); if (result) { - dev_err(&port->dev, - "%s - failed submitting write urb, error %d\n", + dev_err(dev, "%s - failed submitting write urb, error %d\n", __func__, result); /* Throw away data. No better idea what to do with it. */ priv->wrfilled = 0; @@ -475,14 +395,14 @@ static void cyberjack_write_bulk_callback(struct urb *urb) goto exit; } - dbg("%s - priv->wrsent=%d", __func__, priv->wrsent); - dbg("%s - priv->wrfilled=%d", __func__, priv->wrfilled); + dev_dbg(dev, "%s - priv->wrsent=%d\n", __func__, priv->wrsent); + dev_dbg(dev, "%s - priv->wrfilled=%d\n", __func__, priv->wrfilled); blksize = ((int)priv->wrbuf[2]<<8)+priv->wrbuf[1]+3; if (priv->wrsent >= priv->wrfilled || priv->wrsent >= blksize) { - dbg("%s - buffer cleaned", __func__); + dev_dbg(dev, "%s - buffer cleaned\n", __func__); memset(priv->wrbuf, 0, sizeof(priv->wrbuf)); priv->wrfilled = 0; priv->wrsent = 0; @@ -494,40 +414,8 @@ exit: usb_serial_port_softint(port); } -static int __init cyberjack_init(void) -{ - int retval; - retval = usb_serial_register(&cyberjack_device); - if (retval) - goto failed_usb_serial_register; - retval = usb_register(&cyberjack_driver); - if (retval) - goto failed_usb_register; - - printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION " " - DRIVER_AUTHOR "\n"); - printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n"); - - return 0; -failed_usb_register: - usb_serial_deregister(&cyberjack_device); -failed_usb_serial_register: - return retval; -} - -static void __exit cyberjack_exit(void) -{ - usb_deregister(&cyberjack_driver); - usb_serial_deregister(&cyberjack_device); -} - -module_init(cyberjack_init); -module_exit(cyberjack_exit); +module_usb_serial_driver(serial_drivers, id_table); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_VERSION(DRIVER_VERSION); MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index 2edf238b00b..01bf5339281 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c @@ -16,32 +16,6 @@ * * See http://geocities.com/i0xox0i for information on this driver and the * earthmate usb device. - * - * Lonnie Mendez <dignome@gmail.com> - * 4-29-2005 - * Fixed problem where setting or retreiving the serial config would fail - * with EPIPE. Removed CRTS toggling so the driver behaves more like - * other usbserial adapters. Issued new interval of 1ms instead of the - * default 10ms. As a result, transfer speed has been substantially - * increased from avg. 850bps to avg. 3300bps. initial termios has also - * been modified. Cleaned up code and formatting issues so it is more - * readable. Replaced the C++ style comments. - * - * Lonnie Mendez <dignome@gmail.com> - * 12-15-2004 - * Incorporated write buffering from pl2303 driver. Fixed bug with line - * handling so both lines are raised in cypress_open. (was dropping rts) - * Various code cleanups made as well along with other misc bug fixes. - * - * Lonnie Mendez <dignome@gmail.com> - * 04-10-2004 - * Driver modified to support dynamic line settings. Various improvments - * and features. - * - * Neil Whelchel - * 10-2003 - * Driver first released. - * */ /* Thanks to Neil Whelchel for writing the first cypress m8 implementation @@ -53,7 +27,6 @@ #include <linux/kernel.h> #include <linux/errno.h> -#include <linux/init.h> #include <linux/slab.h> #include <linux/tty.h> #include <linux/tty_driver.h> @@ -72,15 +45,10 @@ #include "cypress_m8.h" -static int debug; -static int stats; +static bool stats; static int interval; -static int unstable_bauds; +static bool unstable_bauds; -/* - * Version Information - */ -#define DRIVER_VERSION "v1.10" #define DRIVER_AUTHOR "Lonnie Mendez <dignome@gmail.com>, Neil Whelchel <koyama@firstlight.net>" #define DRIVER_DESC "Cypress USB to Serial Driver" @@ -96,6 +64,7 @@ static const struct usb_device_id id_table_earthmate[] = { static const struct usb_device_id id_table_cyphidcomrs232[] = { { USB_DEVICE(VENDOR_ID_CYPRESS, PRODUCT_ID_CYPHIDCOM) }, { USB_DEVICE(VENDOR_ID_POWERCOM, PRODUCT_ID_UPS) }, + { USB_DEVICE(VENDOR_ID_FRWD, PRODUCT_ID_CYPHIDCOM_FRWD) }, { } /* Terminating entry */ }; @@ -109,20 +78,13 @@ static const struct usb_device_id id_table_combined[] = { { USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB_LT20) }, { USB_DEVICE(VENDOR_ID_CYPRESS, PRODUCT_ID_CYPHIDCOM) }, { USB_DEVICE(VENDOR_ID_POWERCOM, PRODUCT_ID_UPS) }, + { USB_DEVICE(VENDOR_ID_FRWD, PRODUCT_ID_CYPHIDCOM_FRWD) }, { USB_DEVICE(VENDOR_ID_DAZZLE, PRODUCT_ID_CA42) }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, id_table_combined); -static struct usb_driver cypress_driver = { - .name = "cypress", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table_combined, - .no_dynamic_id = 1, -}; - enum packet_format { packet_format_1, /* b0:status, b1:payload count */ packet_format_2 /* b0[7:3]:status, b0[2:0]:payload count */ @@ -150,18 +112,17 @@ struct cypress_private { int baud_rate; /* stores current baud rate in integer form */ int isthrottled; /* if throttled, discard reads */ - wait_queue_head_t delta_msr_wait; /* used for TIOCMIWAIT */ - char prev_status, diff_status; /* used for TIOCMIWAIT */ + char prev_status; /* used for TIOCMIWAIT */ /* we pass a pointer to this as the argument sent to cypress_set_termios old_termios */ struct ktermios tmp_termios; /* stores the old termios settings */ }; /* function prototypes for the Cypress USB to serial device */ -static int cypress_earthmate_startup(struct usb_serial *serial); -static int cypress_hidcom_startup(struct usb_serial *serial); -static int cypress_ca42v2_startup(struct usb_serial *serial); -static void cypress_release(struct usb_serial *serial); +static int cypress_earthmate_port_probe(struct usb_serial_port *port); +static int cypress_hidcom_port_probe(struct usb_serial_port *port); +static int cypress_ca42v2_port_probe(struct usb_serial_port *port); +static int cypress_port_remove(struct usb_serial_port *port); static int cypress_open(struct tty_struct *tty, struct usb_serial_port *port); static void cypress_close(struct usb_serial_port *port); static void cypress_dtr_rts(struct usb_serial_port *port, int on); @@ -169,12 +130,10 @@ static int cypress_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count); static void cypress_send(struct usb_serial_port *port); static int cypress_write_room(struct tty_struct *tty); -static int cypress_ioctl(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg); static void cypress_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old); -static int cypress_tiocmget(struct tty_struct *tty, struct file *file); -static int cypress_tiocmset(struct tty_struct *tty, struct file *file, +static int cypress_tiocmget(struct tty_struct *tty); +static int cypress_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear); static int cypress_chars_in_buffer(struct tty_struct *tty); static void cypress_throttle(struct tty_struct *tty); @@ -189,20 +148,19 @@ static struct usb_serial_driver cypress_earthmate_device = { .name = "earthmate", }, .description = "DeLorme Earthmate USB", - .usb_driver = &cypress_driver, .id_table = id_table_earthmate, .num_ports = 1, - .attach = cypress_earthmate_startup, - .release = cypress_release, + .port_probe = cypress_earthmate_port_probe, + .port_remove = cypress_port_remove, .open = cypress_open, .close = cypress_close, .dtr_rts = cypress_dtr_rts, .write = cypress_write, .write_room = cypress_write_room, - .ioctl = cypress_ioctl, .set_termios = cypress_set_termios, .tiocmget = cypress_tiocmget, .tiocmset = cypress_tiocmset, + .tiocmiwait = usb_serial_generic_tiocmiwait, .chars_in_buffer = cypress_chars_in_buffer, .throttle = cypress_throttle, .unthrottle = cypress_unthrottle, @@ -216,20 +174,19 @@ static struct usb_serial_driver cypress_hidcom_device = { .name = "cyphidcom", }, .description = "HID->COM RS232 Adapter", - .usb_driver = &cypress_driver, .id_table = id_table_cyphidcomrs232, .num_ports = 1, - .attach = cypress_hidcom_startup, - .release = cypress_release, + .port_probe = cypress_hidcom_port_probe, + .port_remove = cypress_port_remove, .open = cypress_open, .close = cypress_close, .dtr_rts = cypress_dtr_rts, .write = cypress_write, .write_room = cypress_write_room, - .ioctl = cypress_ioctl, .set_termios = cypress_set_termios, .tiocmget = cypress_tiocmget, .tiocmset = cypress_tiocmset, + .tiocmiwait = usb_serial_generic_tiocmiwait, .chars_in_buffer = cypress_chars_in_buffer, .throttle = cypress_throttle, .unthrottle = cypress_unthrottle, @@ -243,20 +200,19 @@ static struct usb_serial_driver cypress_ca42v2_device = { .name = "nokiaca42v2", }, .description = "Nokia CA-42 V2 Adapter", - .usb_driver = &cypress_driver, .id_table = id_table_nokiaca42v2, .num_ports = 1, - .attach = cypress_ca42v2_startup, - .release = cypress_release, + .port_probe = cypress_ca42v2_port_probe, + .port_remove = cypress_port_remove, .open = cypress_open, .close = cypress_close, .dtr_rts = cypress_dtr_rts, .write = cypress_write, .write_room = cypress_write_room, - .ioctl = cypress_ioctl, .set_termios = cypress_set_termios, .tiocmget = cypress_tiocmget, .tiocmset = cypress_tiocmset, + .tiocmiwait = usb_serial_generic_tiocmiwait, .chars_in_buffer = cypress_chars_in_buffer, .throttle = cypress_throttle, .unthrottle = cypress_unthrottle, @@ -264,10 +220,21 @@ static struct usb_serial_driver cypress_ca42v2_device = { .write_int_callback = cypress_write_int_callback, }; +static struct usb_serial_driver * const serial_drivers[] = { + &cypress_earthmate_device, &cypress_hidcom_device, + &cypress_ca42v2_device, NULL +}; + /***************************************************************************** * Cypress serial helper functions *****************************************************************************/ +/* FRWD Dongle hidcom needs to skip reset and speed checks */ +static inline bool is_frwd(struct usb_device *dev) +{ + return ((le16_to_cpu(dev->descriptor.idVendor) == VENDOR_ID_FRWD) && + (le16_to_cpu(dev->descriptor.idProduct) == PRODUCT_ID_CYPHIDCOM_FRWD)); +} static int analyze_baud_rate(struct usb_serial_port *port, speed_t new_rate) { @@ -277,6 +244,10 @@ static int analyze_baud_rate(struct usb_serial_port *port, speed_t new_rate) if (unstable_bauds) return new_rate; + /* FRWD Dongle uses 115200 bps */ + if (is_frwd(port->serial->dev)) + return new_rate; + /* * The general purpose firmware for the Cypress M8 allows for * a maximum speed of 57600bps (I have no idea whether DeLorme @@ -295,8 +266,9 @@ static int analyze_baud_rate(struct usb_serial_port *port, speed_t new_rate) * safest speed for a part like that. */ if (new_rate > 4800) { - dbg("%s - failed setting baud rate, device incapable " - "speed %d", __func__, new_rate); + dev_dbg(&port->dev, + "%s - failed setting baud rate, device incapable speed %d\n", + __func__, new_rate); return -1; } } @@ -306,8 +278,9 @@ static int analyze_baud_rate(struct usb_serial_port *port, speed_t new_rate) /* 300 and 600 baud rates are supported under * the generic firmware, but are not used with * NMEA and SiRF protocols */ - dbg("%s - failed setting baud rate, unsupported speed " - "of %d on Earthmate GPS", __func__, new_rate); + dev_dbg(&port->dev, + "%s - failed setting baud rate, unsupported speed of %d on Earthmate GPS\n", + __func__, new_rate); return -1; } break; @@ -326,12 +299,11 @@ static int cypress_serial_control(struct tty_struct *tty, { int new_baudrate = 0, retval = 0, tries = 0; struct cypress_private *priv; + struct device *dev = &port->dev; u8 *feature_buffer; const unsigned int feature_len = 5; unsigned long flags; - dbg("%s", __func__); - priv = usb_get_serial_port_data(port); if (!priv->comm_is_ok) @@ -346,16 +318,16 @@ static int cypress_serial_control(struct tty_struct *tty, /* 0 means 'Hang up' so doesn't change the true bit rate */ new_baudrate = priv->baud_rate; if (baud_rate && baud_rate != priv->baud_rate) { - dbg("%s - baud rate is changing", __func__); + dev_dbg(dev, "%s - baud rate is changing\n", __func__); retval = analyze_baud_rate(port, baud_rate); if (retval >= 0) { new_baudrate = retval; - dbg("%s - New baud rate set to %d", - __func__, new_baudrate); + dev_dbg(dev, "%s - New baud rate set to %d\n", + __func__, new_baudrate); } } - dbg("%s - baud rate is being sent as %d", - __func__, new_baudrate); + dev_dbg(dev, "%s - baud rate is being sent as %d\n", __func__, + new_baudrate); /* fill the feature_buffer with new configuration */ put_unaligned_le32(new_baudrate, feature_buffer); @@ -367,9 +339,8 @@ static int cypress_serial_control(struct tty_struct *tty, /* 1 bit gap */ feature_buffer[4] |= (reset << 7); /* assign reset at end of byte, 1 bit space */ - dbg("%s - device is being sent this feature report:", - __func__); - dbg("%s - %02X - %02X - %02X - %02X - %02X", __func__, + dev_dbg(dev, "%s - device is being sent this feature report:\n", __func__); + dev_dbg(dev, "%s - %02X - %02X - %02X - %02X - %02X\n", __func__, feature_buffer[0], feature_buffer[1], feature_buffer[2], feature_buffer[3], feature_buffer[4]); @@ -389,8 +360,8 @@ static int cypress_serial_control(struct tty_struct *tty, retval != -ENODEV); if (retval != feature_len) { - dev_err(&port->dev, "%s - failed sending serial " - "line settings - %d\n", __func__, retval); + dev_err(dev, "%s - failed sending serial line settings - %d\n", + __func__, retval); cypress_set_dead(port); } else { spin_lock_irqsave(&priv->lock, flags); @@ -411,7 +382,7 @@ static int cypress_serial_control(struct tty_struct *tty, retval = -ENOTTY; goto out; } - dbg("%s - retreiving serial line settings", __func__); + dev_dbg(dev, "%s - retreiving serial line settings\n", __func__); do { retval = usb_control_msg(port->serial->dev, usb_rcvctrlpipe(port->serial->dev, 0), @@ -426,8 +397,8 @@ static int cypress_serial_control(struct tty_struct *tty, && retval != -ENODEV); if (retval != feature_len) { - dev_err(&port->dev, "%s - failed to retrieve serial " - "line settings - %d\n", __func__, retval); + dev_err(dev, "%s - failed to retrieve serial line settings - %d\n", + __func__, retval); cypress_set_dead(port); goto out; } else { @@ -462,7 +433,7 @@ static void cypress_set_dead(struct usb_serial_port *port) spin_unlock_irqrestore(&priv->lock, flags); dev_err(&port->dev, "cypress_m8 suspending failing port %d - " - "interval might be too short\n", port->number); + "interval might be too short\n", port->port_number); } @@ -471,12 +442,10 @@ static void cypress_set_dead(struct usb_serial_port *port) *****************************************************************************/ -static int generic_startup(struct usb_serial *serial) +static int cypress_generic_port_probe(struct usb_serial_port *port) { + struct usb_serial *serial = port->serial; struct cypress_private *priv; - struct usb_serial_port *port = serial->port[0]; - - dbg("%s - port %d", __func__, port->number); priv = kzalloc(sizeof(struct cypress_private), GFP_KERNEL); if (!priv) @@ -488,9 +457,12 @@ static int generic_startup(struct usb_serial *serial) kfree(priv); return -ENOMEM; } - init_waitqueue_head(&priv->delta_msr_wait); - usb_reset_configuration(serial->dev); + /* Skip reset for FRWD device. It is a workaound: + device hangs if it receives SET_CONFIGURE in Configured + state. */ + if (!is_frwd(serial->dev)) + usb_reset_configuration(serial->dev); priv->cmd_ctrl = 0; priv->line_control = 0; @@ -510,32 +482,33 @@ static int generic_startup(struct usb_serial *serial) if (interval > 0) { priv->write_urb_interval = interval; priv->read_urb_interval = interval; - dbg("%s - port %d read & write intervals forced to %d", - __func__, port->number, interval); + dev_dbg(&port->dev, "%s - read & write intervals forced to %d\n", + __func__, interval); } else { priv->write_urb_interval = port->interrupt_out_urb->interval; priv->read_urb_interval = port->interrupt_in_urb->interval; - dbg("%s - port %d intervals: read=%d write=%d", - __func__, port->number, - priv->read_urb_interval, priv->write_urb_interval); + dev_dbg(&port->dev, "%s - intervals: read=%d write=%d\n", + __func__, priv->read_urb_interval, + priv->write_urb_interval); } usb_set_serial_port_data(port, priv); + port->port.drain_delay = 256; + return 0; } -static int cypress_earthmate_startup(struct usb_serial *serial) +static int cypress_earthmate_port_probe(struct usb_serial_port *port) { + struct usb_serial *serial = port->serial; struct cypress_private *priv; - struct usb_serial_port *port = serial->port[0]; - - dbg("%s", __func__); + int ret; - if (generic_startup(serial)) { - dbg("%s - Failed setting up port %d", __func__, - port->number); - return 1; + ret = cypress_generic_port_probe(port); + if (ret) { + dev_dbg(&port->dev, "%s - Failed setting up port\n", __func__); + return ret; } priv = usb_get_serial_port_data(port); @@ -549,70 +522,61 @@ static int cypress_earthmate_startup(struct usb_serial *serial) handle GET_CONFIG requests; everything they've produced since that time crashes if this command is attempted :-( */ - dbg("%s - Marking this device as unsafe for GET_CONFIG " - "commands", __func__); + dev_dbg(&port->dev, + "%s - Marking this device as unsafe for GET_CONFIG commands\n", + __func__); priv->get_cfg_unsafe = !0; } return 0; -} /* cypress_earthmate_startup */ - +} -static int cypress_hidcom_startup(struct usb_serial *serial) +static int cypress_hidcom_port_probe(struct usb_serial_port *port) { struct cypress_private *priv; + int ret; - dbg("%s", __func__); - - if (generic_startup(serial)) { - dbg("%s - Failed setting up port %d", __func__, - serial->port[0]->number); - return 1; + ret = cypress_generic_port_probe(port); + if (ret) { + dev_dbg(&port->dev, "%s - Failed setting up port\n", __func__); + return ret; } - priv = usb_get_serial_port_data(serial->port[0]); + priv = usb_get_serial_port_data(port); priv->chiptype = CT_CYPHIDCOM; return 0; -} /* cypress_hidcom_startup */ - +} -static int cypress_ca42v2_startup(struct usb_serial *serial) +static int cypress_ca42v2_port_probe(struct usb_serial_port *port) { struct cypress_private *priv; + int ret; - dbg("%s", __func__); - - if (generic_startup(serial)) { - dbg("%s - Failed setting up port %d", __func__, - serial->port[0]->number); - return 1; + ret = cypress_generic_port_probe(port); + if (ret) { + dev_dbg(&port->dev, "%s - Failed setting up port\n", __func__); + return ret; } - priv = usb_get_serial_port_data(serial->port[0]); + priv = usb_get_serial_port_data(port); priv->chiptype = CT_CA42V2; return 0; -} /* cypress_ca42v2_startup */ - +} -static void cypress_release(struct usb_serial *serial) +static int cypress_port_remove(struct usb_serial_port *port) { struct cypress_private *priv; - dbg("%s - port %d", __func__, serial->port[0]->number); - - /* all open ports are closed at this point */ + priv = usb_get_serial_port_data(port); - priv = usb_get_serial_port_data(serial->port[0]); + kfifo_free(&priv->write_fifo); + kfree(priv); - if (priv) { - kfifo_free(&priv->write_fifo); - kfree(priv); - } + return 0; } - static int cypress_open(struct tty_struct *tty, struct usb_serial_port *port) { struct cypress_private *priv = usb_get_serial_port_data(port); @@ -620,8 +584,6 @@ static int cypress_open(struct tty_struct *tty, struct usb_serial_port *port) unsigned long flags; int result = 0; - dbg("%s - port %d", __func__, port->number); - if (!priv->comm_is_ok) return -EIO; @@ -663,7 +625,7 @@ static int cypress_open(struct tty_struct *tty, struct usb_serial_port *port) __func__, result); cypress_set_dead(port); } - port->port.drain_delay = 256; + return result; } /* cypress_open */ @@ -686,26 +648,17 @@ static void cypress_close(struct usb_serial_port *port) struct cypress_private *priv = usb_get_serial_port_data(port); unsigned long flags; - dbg("%s - port %d", __func__, port->number); - - /* writing is potentially harmful, lock must be taken */ - mutex_lock(&port->serial->disc_mutex); - if (port->serial->disconnected) { - mutex_unlock(&port->serial->disc_mutex); - return; - } spin_lock_irqsave(&priv->lock, flags); kfifo_reset_out(&priv->write_fifo); spin_unlock_irqrestore(&priv->lock, flags); - dbg("%s - stopping urbs", __func__); + dev_dbg(&port->dev, "%s - stopping urbs\n", __func__); usb_kill_urb(port->interrupt_in_urb); usb_kill_urb(port->interrupt_out_urb); if (stats) dev_info(&port->dev, "Statistics: %d Bytes In | %d Bytes Out | %d Commands Issued\n", priv->bytes_in, priv->bytes_out, priv->cmd_count); - mutex_unlock(&port->serial->disc_mutex); } /* cypress_close */ @@ -714,7 +667,7 @@ static int cypress_write(struct tty_struct *tty, struct usb_serial_port *port, { struct cypress_private *priv = usb_get_serial_port_data(port); - dbg("%s - port %d, %d bytes", __func__, port->number, count); + dev_dbg(&port->dev, "%s - %d bytes\n", __func__, count); /* line control commands, which need to be executed immediately, are not put into the buffer for obvious reasons. @@ -740,18 +693,18 @@ static void cypress_send(struct usb_serial_port *port) { int count = 0, result, offset, actual_size; struct cypress_private *priv = usb_get_serial_port_data(port); + struct device *dev = &port->dev; unsigned long flags; if (!priv->comm_is_ok) return; - dbg("%s - port %d", __func__, port->number); - dbg("%s - interrupt out size is %d", __func__, - port->interrupt_out_size); + dev_dbg(dev, "%s - interrupt out size is %d\n", __func__, + port->interrupt_out_size); spin_lock_irqsave(&priv->lock, flags); if (priv->write_urb_in_use) { - dbg("%s - can't write, urb in use", __func__); + dev_dbg(dev, "%s - can't write, urb in use\n", __func__); spin_unlock_irqrestore(&priv->lock, flags); return; } @@ -781,7 +734,7 @@ static void cypress_send(struct usb_serial_port *port) if (priv->cmd_ctrl) { priv->cmd_count++; - dbg("%s - line control command being issued", __func__); + dev_dbg(dev, "%s - line control command being issued\n", __func__); spin_unlock_irqrestore(&priv->lock, flags); goto send; } else @@ -803,7 +756,7 @@ static void cypress_send(struct usb_serial_port *port) port->interrupt_out_buffer[0] |= count; } - dbg("%s - count is %d", __func__, count); + dev_dbg(dev, "%s - count is %d\n", __func__, count); send: spin_lock_irqsave(&priv->lock, flags); @@ -816,9 +769,8 @@ send: actual_size = count + (priv->pkt_fmt == packet_format_1 ? 2 : 1); - usb_serial_debug_data(debug, &port->dev, __func__, - port->interrupt_out_size, - port->interrupt_out_urb->transfer_buffer); + usb_serial_debug_data(dev, __func__, port->interrupt_out_size, + port->interrupt_out_urb->transfer_buffer); usb_fill_int_urb(port->interrupt_out_urb, port->serial->dev, usb_sndintpipe(port->serial->dev, port->interrupt_out_endpointAddress), @@ -826,7 +778,7 @@ send: cypress_write_int_callback, port, priv->write_urb_interval); result = usb_submit_urb(port->interrupt_out_urb, GFP_ATOMIC); if (result) { - dev_err(&port->dev, + dev_err_console(port, "%s - failed submitting write urb, error %d\n", __func__, result); priv->write_urb_in_use = 0; @@ -853,18 +805,16 @@ static int cypress_write_room(struct tty_struct *tty) int room = 0; unsigned long flags; - dbg("%s - port %d", __func__, port->number); - spin_lock_irqsave(&priv->lock, flags); room = kfifo_avail(&priv->write_fifo); spin_unlock_irqrestore(&priv->lock, flags); - dbg("%s - returns %d", __func__, room); + dev_dbg(&port->dev, "%s - returns %d\n", __func__, room); return room; } -static int cypress_tiocmget(struct tty_struct *tty, struct file *file) +static int cypress_tiocmget(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; struct cypress_private *priv = usb_get_serial_port_data(port); @@ -872,8 +822,6 @@ static int cypress_tiocmget(struct tty_struct *tty, struct file *file) unsigned int result = 0; unsigned long flags; - dbg("%s - port %d", __func__, port->number); - spin_lock_irqsave(&priv->lock, flags); control = priv->line_control; status = priv->current_status; @@ -886,21 +834,19 @@ static int cypress_tiocmget(struct tty_struct *tty, struct file *file) | ((status & UART_RI) ? TIOCM_RI : 0) | ((status & UART_CD) ? TIOCM_CD : 0); - dbg("%s - result = %x", __func__, result); + dev_dbg(&port->dev, "%s - result = %x\n", __func__, result); return result; } -static int cypress_tiocmset(struct tty_struct *tty, struct file *file, +static int cypress_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) { struct usb_serial_port *port = tty->driver_data; struct cypress_private *priv = usb_get_serial_port_data(port); unsigned long flags; - dbg("%s - port %d", __func__, port->number); - spin_lock_irqsave(&priv->lock, flags); if (set & TIOCM_RTS) priv->line_control |= CONTROL_RTS; @@ -916,102 +862,54 @@ static int cypress_tiocmset(struct tty_struct *tty, struct file *file, return cypress_write(tty, port, NULL, 0); } - -static int cypress_ioctl(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct usb_serial_port *port = tty->driver_data; - struct cypress_private *priv = usb_get_serial_port_data(port); - - dbg("%s - port %d, cmd 0x%.4x", __func__, port->number, cmd); - - switch (cmd) { - /* This code comes from drivers/char/serial.c and ftdi_sio.c */ - case TIOCMIWAIT: - while (priv != NULL) { - interruptible_sleep_on(&priv->delta_msr_wait); - /* see if a signal did it */ - if (signal_pending(current)) - return -ERESTARTSYS; - else { - char diff = priv->diff_status; - if (diff == 0) - return -EIO; /* no change => error */ - - /* consume all events */ - priv->diff_status = 0; - - /* return 0 if caller wanted to know about - these bits */ - if (((arg & TIOCM_RNG) && (diff & UART_RI)) || - ((arg & TIOCM_DSR) && (diff & UART_DSR)) || - ((arg & TIOCM_CD) && (diff & UART_CD)) || - ((arg & TIOCM_CTS) && (diff & UART_CTS))) - return 0; - /* otherwise caller can't care less about what - * happened, and so we continue to wait for - * more events. - */ - } - } - return 0; - default: - break; - } - dbg("%s - arg not supported - it was 0x%04x - check include/asm/ioctls.h", __func__, cmd); - return -ENOIOCTLCMD; -} /* cypress_ioctl */ - - static void cypress_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios) { struct cypress_private *priv = usb_get_serial_port_data(port); + struct device *dev = &port->dev; int data_bits, stop_bits, parity_type, parity_enable; unsigned cflag, iflag; unsigned long flags; __u8 oldlines; int linechange = 0; - dbg("%s - port %d", __func__, port->number); - spin_lock_irqsave(&priv->lock, flags); /* We can't clean this one up as we don't know the device type early enough */ if (!priv->termios_initialized) { if (priv->chiptype == CT_EARTHMATE) { - *(tty->termios) = tty_std_termios; - tty->termios->c_cflag = B4800 | CS8 | CREAD | HUPCL | + tty->termios = tty_std_termios; + tty->termios.c_cflag = B4800 | CS8 | CREAD | HUPCL | CLOCAL; - tty->termios->c_ispeed = 4800; - tty->termios->c_ospeed = 4800; + tty->termios.c_ispeed = 4800; + tty->termios.c_ospeed = 4800; } else if (priv->chiptype == CT_CYPHIDCOM) { - *(tty->termios) = tty_std_termios; - tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL | + tty->termios = tty_std_termios; + tty->termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; - tty->termios->c_ispeed = 9600; - tty->termios->c_ospeed = 9600; + tty->termios.c_ispeed = 9600; + tty->termios.c_ospeed = 9600; } else if (priv->chiptype == CT_CA42V2) { - *(tty->termios) = tty_std_termios; - tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL | + tty->termios = tty_std_termios; + tty->termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; - tty->termios->c_ispeed = 9600; - tty->termios->c_ospeed = 9600; + tty->termios.c_ispeed = 9600; + tty->termios.c_ospeed = 9600; } priv->termios_initialized = 1; } spin_unlock_irqrestore(&priv->lock, flags); /* Unsupported features need clearing */ - tty->termios->c_cflag &= ~(CMSPAR|CRTSCTS); + tty->termios.c_cflag &= ~(CMSPAR|CRTSCTS); - cflag = tty->termios->c_cflag; - iflag = tty->termios->c_iflag; + cflag = tty->termios.c_cflag; + iflag = tty->termios.c_iflag; /* check if there are new settings */ if (old_termios) { spin_lock_irqsave(&priv->lock, flags); - priv->tmp_termios = *(tty->termios); + priv->tmp_termios = tty->termios; spin_unlock_irqrestore(&priv->lock, flags); } @@ -1042,23 +940,21 @@ static void cypress_set_termios(struct tty_struct *tty, data_bits = 3; break; default: - dev_err(&port->dev, "%s - CSIZE was set, but not CS5-CS8\n", - __func__); + dev_err(dev, "%s - CSIZE was set, but not CS5-CS8\n", __func__); data_bits = 3; } spin_lock_irqsave(&priv->lock, flags); oldlines = priv->line_control; if ((cflag & CBAUD) == B0) { /* drop dtr and rts */ - dbg("%s - dropping the lines, baud rate 0bps", __func__); + dev_dbg(dev, "%s - dropping the lines, baud rate 0bps\n", __func__); priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS); } else priv->line_control = (CONTROL_DTR | CONTROL_RTS); spin_unlock_irqrestore(&priv->lock, flags); - dbg("%s - sending %d stop_bits, %d parity_enable, %d parity_type, " - "%d data_bits (+5)", __func__, stop_bits, - parity_enable, parity_type, data_bits); + dev_dbg(dev, "%s - sending %d stop_bits, %d parity_enable, %d parity_type, %d data_bits (+5)\n", + __func__, stop_bits, parity_enable, parity_type, data_bits); cypress_serial_control(tty, port, tty_get_baud_rate(tty), data_bits, stop_bits, @@ -1075,11 +971,10 @@ static void cypress_set_termios(struct tty_struct *tty, spin_lock_irqsave(&priv->lock, flags); if (priv->chiptype == CT_EARTHMATE && priv->baud_rate == 4800) { - dbg("Using custom termios settings for a baud rate of " - "4800bps."); + dev_dbg(dev, "Using custom termios settings for a baud rate of 4800bps.\n"); /* define custom termios settings for NMEA protocol */ - tty->termios->c_iflag /* input modes - */ + tty->termios.c_iflag /* input modes - */ &= ~(IGNBRK /* disable ignore break */ | BRKINT /* disable break causes interrupt */ | PARMRK /* disable mark parity errors */ @@ -1089,10 +984,10 @@ static void cypress_set_termios(struct tty_struct *tty, | ICRNL /* disable translate CR to NL */ | IXON); /* disable enable XON/XOFF flow control */ - tty->termios->c_oflag /* output modes */ + tty->termios.c_oflag /* output modes */ &= ~OPOST; /* disable postprocess output char */ - tty->termios->c_lflag /* line discipline modes */ + tty->termios.c_lflag /* line discipline modes */ &= ~(ECHO /* disable echo input characters */ | ECHONL /* disable echo new line */ | ICANON /* disable erase, kill, werase, and rprnt @@ -1121,13 +1016,11 @@ static int cypress_chars_in_buffer(struct tty_struct *tty) int chars = 0; unsigned long flags; - dbg("%s - port %d", __func__, port->number); - spin_lock_irqsave(&priv->lock, flags); chars = kfifo_len(&priv->write_fifo); spin_unlock_irqrestore(&priv->lock, flags); - dbg("%s - returns %d", __func__, chars); + dev_dbg(&port->dev, "%s - returns %d\n", __func__, chars); return chars; } @@ -1137,8 +1030,6 @@ static void cypress_throttle(struct tty_struct *tty) struct usb_serial_port *port = tty->driver_data; struct cypress_private *priv = usb_get_serial_port_data(port); - dbg("%s - port %d", __func__, port->number); - spin_lock_irq(&priv->lock); priv->rx_flags = THROTTLED; spin_unlock_irq(&priv->lock); @@ -1151,8 +1042,6 @@ static void cypress_unthrottle(struct tty_struct *tty) struct cypress_private *priv = usb_get_serial_port_data(port); int actually_throttled, result; - dbg("%s - port %d", __func__, port->number); - spin_lock_irq(&priv->lock); actually_throttled = priv->rx_flags & ACTUALLY_THROTTLED; priv->rx_flags = 0; @@ -1162,8 +1051,6 @@ static void cypress_unthrottle(struct tty_struct *tty) return; if (actually_throttled) { - port->interrupt_in_urb->dev = port->serial->dev; - result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); if (result) { dev_err(&port->dev, "%s - failed submitting read urb, " @@ -1178,6 +1065,7 @@ static void cypress_read_int_callback(struct urb *urb) { struct usb_serial_port *port = urb->context; struct cypress_private *priv = usb_get_serial_port_data(port); + struct device *dev = &urb->dev->dev; struct tty_struct *tty; unsigned char *data = urb->transfer_buffer; unsigned long flags; @@ -1188,8 +1076,6 @@ static void cypress_read_int_callback(struct urb *urb) int i = 0; int status = urb->status; - dbg("%s - port %d", __func__, port->number); - switch (status) { case 0: /* success */ break; @@ -1203,16 +1089,15 @@ static void cypress_read_int_callback(struct urb *urb) /* FALLS THROUGH */ default: /* something ugly is going on... */ - dev_err(&urb->dev->dev, - "%s - unexpected nonzero read status received: %d\n", - __func__, status); + dev_err(dev, "%s - unexpected nonzero read status received: %d\n", + __func__, status); cypress_set_dead(port); return; } spin_lock_irqsave(&priv->lock, flags); if (priv->rx_flags & THROTTLED) { - dbg("%s - now throttling", __func__); + dev_dbg(dev, "%s - now throttling\n", __func__); priv->rx_flags |= ACTUALLY_THROTTLED; spin_unlock_irqrestore(&priv->lock, flags); return; @@ -1221,7 +1106,7 @@ static void cypress_read_int_callback(struct urb *urb) tty = tty_port_tty_get(&port->port); if (!tty) { - dbg("%s - bad tty pointer - exiting", __func__); + dev_dbg(dev, "%s - bad tty pointer - exiting\n", __func__); return; } @@ -1248,29 +1133,41 @@ static void cypress_read_int_callback(struct urb *urb) } spin_unlock_irqrestore(&priv->lock, flags); if (result < bytes) { - dbg("%s - wrong packet size - received %d bytes but packet " - "said %d bytes", __func__, result, bytes); + dev_dbg(dev, + "%s - wrong packet size - received %d bytes but packet said %d bytes\n", + __func__, result, bytes); goto continue_read; } - usb_serial_debug_data(debug, &port->dev, __func__, - urb->actual_length, data); + usb_serial_debug_data(&port->dev, __func__, urb->actual_length, data); spin_lock_irqsave(&priv->lock, flags); /* check to see if status has changed */ if (priv->current_status != priv->prev_status) { - priv->diff_status |= priv->current_status ^ - priv->prev_status; - wake_up_interruptible(&priv->delta_msr_wait); + u8 delta = priv->current_status ^ priv->prev_status; + + if (delta & UART_MSR_MASK) { + if (delta & UART_CTS) + port->icount.cts++; + if (delta & UART_DSR) + port->icount.dsr++; + if (delta & UART_RI) + port->icount.rng++; + if (delta & UART_CD) + port->icount.dcd++; + + wake_up_interruptible(&port->port.delta_msr_wait); + } + priv->prev_status = priv->current_status; } spin_unlock_irqrestore(&priv->lock, flags); /* hangup, as defined in acm.c... this might be a bad place for it * though */ - if (tty && !(tty->termios->c_cflag & CLOCAL) && + if (tty && !(tty->termios.c_cflag & CLOCAL) && !(priv->current_status & UART_CD)) { - dbg("%s - calling hangup", __func__); + dev_dbg(dev, "%s - calling hangup\n", __func__); tty_hangup(tty); goto continue_read; } @@ -1283,15 +1180,15 @@ static void cypress_read_int_callback(struct urb *urb) if (priv->current_status & CYP_ERROR) { spin_unlock_irqrestore(&priv->lock, flags); tty_flag = TTY_PARITY; - dbg("%s - Parity Error detected", __func__); + dev_dbg(dev, "%s - Parity Error detected\n", __func__); } else spin_unlock_irqrestore(&priv->lock, flags); /* process read if there is data other than line status */ - if (tty && bytes > i) { - tty_insert_flip_string_fixed_flag(tty, data + i, + if (bytes > i) { + tty_insert_flip_string_fixed_flag(&port->port, data + i, tty_flag, bytes - i); - tty_flip_buffer_push(tty); + tty_flip_buffer_push(&port->port); } spin_lock_irqsave(&priv->lock, flags); @@ -1314,9 +1211,8 @@ continue_read: priv->read_urb_interval); result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC); if (result && result != -EPERM) { - dev_err(&urb->dev->dev, "%s - failed resubmitting " - "read urb, error %d\n", __func__, - result); + dev_err(dev, "%s - failed resubmitting read urb, error %d\n", + __func__, result); cypress_set_dead(port); } } @@ -1327,11 +1223,9 @@ static void cypress_write_int_callback(struct urb *urb) { struct usb_serial_port *port = urb->context; struct cypress_private *priv = usb_get_serial_port_data(port); - int result; + struct device *dev = &urb->dev->dev; int status = urb->status; - dbg("%s - port %d", __func__, port->number); - switch (status) { case 0: /* success */ @@ -1340,31 +1234,16 @@ static void cypress_write_int_callback(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", - __func__, status); + dev_dbg(dev, "%s - urb shutting down with status: %d\n", + __func__, status); priv->write_urb_in_use = 0; return; - case -EPIPE: /* no break needed; clear halt and resubmit */ - if (!priv->comm_is_ok) - break; - usb_clear_halt(port->serial->dev, 0x02); - /* error in the urb, so we have to resubmit it */ - dbg("%s - nonzero write bulk status received: %d", - __func__, status); - port->interrupt_out_urb->transfer_buffer_length = 1; - port->interrupt_out_urb->dev = port->serial->dev; - result = usb_submit_urb(port->interrupt_out_urb, GFP_ATOMIC); - if (!result) - return; - dev_err(&urb->dev->dev, - "%s - failed resubmitting write urb, error %d\n", - __func__, result); - cypress_set_dead(port); - break; + case -EPIPE: + /* Cannot call usb_clear_halt while in_interrupt */ + /* FALLTHROUGH */ default: - dev_err(&urb->dev->dev, - "%s - unexpected nonzero write status received: %d\n", - __func__, status); + dev_err(dev, "%s - unexpected nonzero write status received: %d\n", + __func__, status); cypress_set_dead(port); break; } @@ -1374,66 +1253,12 @@ static void cypress_write_int_callback(struct urb *urb) cypress_send(port); } - -/***************************************************************************** - * Module functions - *****************************************************************************/ - -static int __init cypress_init(void) -{ - int retval; - - dbg("%s", __func__); - - retval = usb_serial_register(&cypress_earthmate_device); - if (retval) - goto failed_em_register; - retval = usb_serial_register(&cypress_hidcom_device); - if (retval) - goto failed_hidcom_register; - retval = usb_serial_register(&cypress_ca42v2_device); - if (retval) - goto failed_ca42v2_register; - retval = usb_register(&cypress_driver); - if (retval) - goto failed_usb_register; - - printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" - DRIVER_DESC "\n"); - return 0; - -failed_usb_register: - usb_serial_deregister(&cypress_ca42v2_device); -failed_ca42v2_register: - usb_serial_deregister(&cypress_hidcom_device); -failed_hidcom_register: - usb_serial_deregister(&cypress_earthmate_device); -failed_em_register: - return retval; -} - - -static void __exit cypress_exit(void) -{ - dbg("%s", __func__); - - usb_deregister(&cypress_driver); - usb_serial_deregister(&cypress_earthmate_device); - usb_serial_deregister(&cypress_hidcom_device); - usb_serial_deregister(&cypress_ca42v2_device); -} - - -module_init(cypress_init); -module_exit(cypress_exit); +module_usb_serial_driver(serial_drivers, id_table_combined); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_VERSION(DRIVER_VERSION); MODULE_LICENSE("GPL"); -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); module_param(stats, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(stats, "Enable statistics or not"); module_param(interval, int, S_IRUGO | S_IWUSR); diff --git a/drivers/usb/serial/cypress_m8.h b/drivers/usb/serial/cypress_m8.h index 67cf6082688..119d2e17077 100644 --- a/drivers/usb/serial/cypress_m8.h +++ b/drivers/usb/serial/cypress_m8.h @@ -24,6 +24,10 @@ #define VENDOR_ID_CYPRESS 0x04b4 #define PRODUCT_ID_CYPHIDCOM 0x5500 +/* FRWD Dongle - a GPS sports watch */ +#define VENDOR_ID_FRWD 0x6737 +#define PRODUCT_ID_CYPHIDCOM_FRWD 0x0001 + /* Powercom UPS, chip CY7C63723 */ #define VENDOR_ID_POWERCOM 0x0d9f #define PRODUCT_ID_UPS 0x0002 @@ -51,19 +55,23 @@ #define CT_GENERIC 0x0F /* End of chiptype definitions */ -/* RS-232 serial data communication protocol definitions */ -/* these are sent / read at byte 0 of the input/output hid reports */ -/* You can find these values defined in the CY4601 USB to Serial design notes */ - -#define CONTROL_DTR 0x20 /* data terminal ready - flow control - host to device */ -#define UART_DSR 0x20 /* data set ready - flow control - device to host */ -#define CONTROL_RTS 0x10 /* request to send - flow control - host to device */ -#define UART_CTS 0x10 /* clear to send - flow control - device to host */ -#define UART_RI 0x10 /* ring indicator - modem - device to host */ -#define UART_CD 0x40 /* carrier detect - modem - device to host */ -#define CYP_ERROR 0x08 /* received from input report - device to host */ -/* Note - the below has nothing to do with the "feature report" reset */ -#define CONTROL_RESET 0x08 /* sent with output report - host to device */ +/* + * RS-232 serial data communication protocol definitions. + * + * These are sent / read at byte 0 of the input/output hid reports. + * You can find these values defined in the CY4601 USB to Serial design notes. + */ + +#define CONTROL_DTR 0x20 /* data terminal ready */ +#define CONTROL_RTS 0x10 /* request to send */ +#define CONTROL_RESET 0x08 /* sent with output report */ + +#define UART_MSR_MASK 0xf0 +#define UART_RI 0x80 /* ring indicator */ +#define UART_CD 0x40 /* carrier detect */ +#define UART_DSR 0x20 /* data set ready */ +#define UART_CTS 0x10 /* clear to send */ +#define CYP_ERROR 0x08 /* received from input report */ /* End of RS-232 protocol definitions */ diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index b92070c103c..8a23c53b946 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -13,227 +13,10 @@ * * Peter Berger (pberger@brimson.com) * Al Borchers (borchers@steinerpoint.com) -* -* (12/03/2001) gkh -* switched to using port->port.count instead of private version. -* Removed port->active -* -* (04/08/2001) gb -* Identify version on module load. -* -* (11/01/2000) Adam J. Richter -* usb_device_id table support -* -* (11/01/2000) pberger and borchers -* -- Turned off the USB_DISABLE_SPD flag for write bulk urbs--it caused -* USB 4 ports to hang on startup. -* -- Serialized access to write urbs by adding the dp_write_urb_in_use -* flag; otherwise, the driver caused SMP system hangs. Watching the -* urb status is not sufficient. -* -* (10/05/2000) gkh -* -- Fixed bug with urb->dev not being set properly, now that the usb -* core needs it. -* -* (8/8/2000) pberger and borchers -* -- Fixed close so that -* - it can timeout while waiting for transmit idle, if needed; -* - it ignores interrupts when flushing the port, turning -* of modem signalling, and so on; -* - it waits for the flush to really complete before returning. -* -- Read_bulk_callback and write_bulk_callback check for a closed -* port before using the tty struct or writing to the port. -* -- The two changes above fix the oops caused by interrupted closes. -* -- Added interruptible args to write_oob_command and set_modem_signals -* and added a timeout arg to transmit_idle; needed for fixes to -* close. -* -- Added code for rx_throttle and rx_unthrottle so that input flow -* control works. -* -- Added code to set overrun, parity, framing, and break errors -* (untested). -* -- Set USB_DISABLE_SPD flag for write bulk urbs, so no 0 length -* bulk writes are done. These hung the Digi USB device. The -* 0 length bulk writes were a new feature of usb-uhci added in -* the 2.4.0-test6 kernels. -* -- Fixed mod inc race in open; do mod inc before sleeping to wait -* for a close to finish. -* -* (7/31/2000) pberger -* -- Fixed bugs with hardware handshaking: -* - Added code to set/clear tty->hw_stopped in digi_read_oob_callback() -* and digi_set_termios() -* -- Added code in digi_set_termios() to -* - add conditional in code handling transition from B0 to only -* set RTS if RTS/CTS flow control is either not in use or if -* the port is not currently throttled. -* - handle turning off CRTSCTS. -* -* (7/30/2000) borchers -* -- Added support for more than one Digi USB device by moving -* globals to a private structure in the pointed to from the -* usb_serial structure. -* -- Moved the modem change and transmit idle wait queues into -* the port private structure, so each port has its own queue -* rather than sharing global queues. -* -- Added support for break signals. -* -* (7/25/2000) pberger -* -- Added USB-2 support. Note: the USB-2 supports 3 devices: two -* serial and a parallel port. The parallel port is implemented -* as a serial-to-parallel converter. That is, the driver actually -* presents all three USB-2 interfaces as serial ports, but the third -* one physically connects to a parallel device. Thus, for example, -* one could plug a parallel printer into the USB-2's third port, -* but from the kernel's (and userland's) point of view what's -* actually out there is a serial device. -* -* (7/15/2000) borchers -* -- Fixed race in open when a close is in progress. -* -- Keep count of opens and dec the module use count for each -* outstanding open when shutdown is called (on disconnect). -* -- Fixed sanity checks in read_bulk_callback and write_bulk_callback -* so pointers are checked before use. -* -- Split read bulk callback into in band and out of band -* callbacks, and no longer restart read chains if there is -* a status error or a sanity error. This fixed the seg -* faults and other errors we used to get on disconnect. -* -- Port->active is once again a flag as usb-serial intended it -* to be, not a count. Since it was only a char it would -* have been limited to 256 simultaneous opens. Now the open -* count is kept in the port private structure in dp_open_count. -* -- Added code for modularization of the digi_acceleport driver. -* -* (6/27/2000) pberger and borchers -* -- Zeroed out sync field in the wakeup_task before first use; -* otherwise the uninitialized value might prevent the task from -* being scheduled. -* -- Initialized ret value to 0 in write_bulk_callback, otherwise -* the uninitialized value could cause a spurious debugging message. -* -* (6/22/2000) pberger and borchers -* -- Made cond_wait_... inline--apparently on SPARC the flags arg -* to spin_lock_irqsave cannot be passed to another function -* to call spin_unlock_irqrestore. Thanks to Pauline Middelink. -* -- In digi_set_modem_signals the inner nested spin locks use just -* spin_lock() rather than spin_lock_irqsave(). The old code -* mistakenly left interrupts off. Thanks to Pauline Middelink. -* -- copy_from_user (which can sleep) is no longer called while a -* spinlock is held. We copy to a local buffer before getting -* the spinlock--don't like the extra copy but the code is simpler. -* -- Printk and dbg are no longer called while a spin lock is held. -* -* (6/4/2000) pberger and borchers -* -- Replaced separate calls to spin_unlock_irqrestore and -* interruptible_sleep_on_timeout with a new function -* cond_wait_interruptible_timeout_irqrestore. This eliminates -* the race condition where the wake up could happen after -* the unlock and before the sleep. -* -- Close now waits for output to drain. -* -- Open waits until any close in progress is finished. -* -- All out of band responses are now processed, not just the -* first in a USB packet. -* -- Fixed a bug that prevented the driver from working when the -* first Digi port was not the first USB serial port--the driver -* was mistakenly using the external USB serial port number to -* try to index into its internal ports. -* -- Fixed an SMP bug -- write_bulk_callback is called directly from -* an interrupt, so spin_lock_irqsave/spin_unlock_irqrestore are -* needed for locks outside write_bulk_callback that are also -* acquired by write_bulk_callback to prevent deadlocks. -* -- Fixed support for select() by making digi_chars_in_buffer() -* return 256 when -EINPROGRESS is set, as the line discipline -* code in n_tty.c expects. -* -- Fixed an include file ordering problem that prevented debugging -* messages from working. -* -- Fixed an intermittent timeout problem that caused writes to -* sometimes get stuck on some machines on some kernels. It turns -* out in these circumstances write_chan() (in n_tty.c) was -* asleep waiting for our wakeup call. Even though we call -* wake_up_interruptible() in digi_write_bulk_callback(), there is -* a race condition that could cause the wakeup to fail: if our -* wake_up_interruptible() call occurs between the time that our -* driver write routine finishes and write_chan() sets current->state -* to TASK_INTERRUPTIBLE, the effect of our wakeup setting the state -* to TASK_RUNNING will be lost and write_chan's subsequent call to -* schedule() will never return (unless it catches a signal). -* This race condition occurs because write_bulk_callback() (and thus -* the wakeup) are called asynchronously from an interrupt, rather than -* from the scheduler. We can avoid the race by calling the wakeup -* from the scheduler queue and that's our fix: Now, at the end of -* write_bulk_callback() we queue up a wakeup call on the scheduler -* task queue. We still also invoke the wakeup directly since that -* squeezes a bit more performance out of the driver, and any lost -* race conditions will get cleaned up at the next scheduler run. -* -* NOTE: The problem also goes away if you comment out -* the two code lines in write_chan() where current->state -* is set to TASK_RUNNING just before calling driver.write() and to -* TASK_INTERRUPTIBLE immediately afterwards. This is why the -* problem did not show up with the 2.2 kernels -- they do not -* include that code. -* -* (5/16/2000) pberger and borchers -* -- Added timeouts to sleeps, to defend against lost wake ups. -* -- Handle transition to/from B0 baud rate in digi_set_termios. -* -* (5/13/2000) pberger and borchers -* -- All commands now sent on out of band port, using -* digi_write_oob_command. -* -- Get modem control signals whenever they change, support TIOCMGET/ -* SET/BIS/BIC ioctls. -* -- digi_set_termios now supports parity, word size, stop bits, and -* receive enable. -* -- Cleaned up open and close, use digi_set_termios and -* digi_write_oob_command to set port parameters. -* -- Added digi_startup_device to start read chains on all ports. -* -- Write buffer is only used when count==1, to be sure put_char can -* write a char (unless the buffer is full). -* -* (5/10/2000) pberger and borchers -* -- Added MOD_INC_USE_COUNT/MOD_DEC_USE_COUNT calls on open/close. -* -- Fixed problem where the first incoming character is lost on -* port opens after the first close on that port. Now we keep -* the read_urb chain open until shutdown. -* -- Added more port conditioning calls in digi_open and digi_close. -* -- Convert port->active to a use count so that we can deal with multiple -* opens and closes properly. -* -- Fixed some problems with the locking code. -* -* (5/3/2000) pberger and borchers -* -- First alpha version of the driver--many known limitations and bugs. -* -* -* Locking and SMP -* -* - Each port, including the out-of-band port, has a lock used to -* serialize all access to the port's private structure. -* - The port lock is also used to serialize all writes and access to -* the port's URB. -* - The port lock is also used for the port write_wait condition -* variable. Holding the port lock will prevent a wake up on the -* port's write_wait; this can be used with cond_wait_... to be sure -* the wake up is not lost in a race when dropping the lock and -* sleeping waiting for the wakeup. -* - digi_write() does not sleep, since it is sometimes called on -* interrupt time. -* - digi_write_bulk_callback() and digi_read_bulk_callback() are -* called directly from interrupts. Hence spin_lock_irqsave() -* and spin_unlock_irqrestore() are used in the rest of the code -* for any locks they acquire. -* - digi_write_bulk_callback() gets the port lock before waking up -* processes sleeping on the port write_wait. It also schedules -* wake ups so they happen from the scheduler, because the tty -* system can miss wake ups from interrupts. -* - All sleeps use a timeout of DIGI_RETRY_TIMEOUT before looping to -* recheck the condition they are sleeping on. This is defensive, -* in case a wake up is lost. -* - Following Documentation/DocBook/kernel-locking.pdf no spin locks -* are held when calling copy_to/from_user or printk. */ #include <linux/kernel.h> #include <linux/errno.h> -#include <linux/init.h> #include <linux/slab.h> #include <linux/tty.h> #include <linux/tty_driver.h> @@ -248,10 +31,6 @@ /* Defines */ -/* - * Version Information - */ -#define DRIVER_VERSION "v1.80.1.2" #define DRIVER_AUTHOR "Peter Berger <pberger@brimson.com>, Al Borchers <borchers@steinerpoint.com>" #define DRIVER_DESC "Digi AccelePort USB-2/USB-4 Serial Converter driver" @@ -416,7 +195,6 @@ struct digi_port { unsigned char dp_out_buf[DIGI_OUT_BUF_SIZE]; int dp_write_urb_in_use; unsigned int dp_modem_signals; - wait_queue_head_t dp_modem_change_wait; int dp_transmit_idle; wait_queue_head_t dp_transmit_idle_wait; int dp_throttled; @@ -430,7 +208,6 @@ struct digi_port { /* Local Function Declarations */ -static void digi_wakeup_write(struct usb_serial_port *port); static void digi_wakeup_write_lock(struct work_struct *work); static int digi_write_oob_command(struct usb_serial_port *port, unsigned char *buf, int count, int interruptible); @@ -445,31 +222,28 @@ static void digi_rx_unthrottle(struct tty_struct *tty); static void digi_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios); static void digi_break_ctl(struct tty_struct *tty, int break_state); -static int digi_tiocmget(struct tty_struct *tty, struct file *file); -static int digi_tiocmset(struct tty_struct *tty, struct file *file, - unsigned int set, unsigned int clear); +static int digi_tiocmget(struct tty_struct *tty); +static int digi_tiocmset(struct tty_struct *tty, unsigned int set, + unsigned int clear); static int digi_write(struct tty_struct *tty, struct usb_serial_port *port, - const unsigned char *buf, int count); + const unsigned char *buf, int count); static void digi_write_bulk_callback(struct urb *urb); static int digi_write_room(struct tty_struct *tty); static int digi_chars_in_buffer(struct tty_struct *tty); static int digi_open(struct tty_struct *tty, struct usb_serial_port *port); static void digi_close(struct usb_serial_port *port); -static int digi_carrier_raised(struct usb_serial_port *port); static void digi_dtr_rts(struct usb_serial_port *port, int on); static int digi_startup_device(struct usb_serial *serial); static int digi_startup(struct usb_serial *serial); static void digi_disconnect(struct usb_serial *serial); static void digi_release(struct usb_serial *serial); +static int digi_port_probe(struct usb_serial_port *port); +static int digi_port_remove(struct usb_serial_port *port); static void digi_read_bulk_callback(struct urb *urb); static int digi_read_inb_callback(struct urb *urb); static int digi_read_oob_callback(struct urb *urb); -/* Statics */ - -static int debug; - static const struct usb_device_id id_table_combined[] = { { USB_DEVICE(DIGI_VENDOR_ID, DIGI_2_ID) }, { USB_DEVICE(DIGI_VENDOR_ID, DIGI_4_ID) }, @@ -488,15 +262,6 @@ static const struct usb_device_id id_table_4[] = { MODULE_DEVICE_TABLE(usb, id_table_combined); -static struct usb_driver digi_driver = { - .name = "digi_acceleport", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table_combined, - .no_dynamic_id = 1, -}; - - /* device info needed for the Digi serial converter */ static struct usb_serial_driver digi_acceleport_2_device = { @@ -505,13 +270,11 @@ static struct usb_serial_driver digi_acceleport_2_device = { .name = "digi_2", }, .description = "Digi 2 port USB adapter", - .usb_driver = &digi_driver, .id_table = id_table_2, .num_ports = 3, .open = digi_open, .close = digi_close, .dtr_rts = digi_dtr_rts, - .carrier_raised = digi_carrier_raised, .write = digi_write, .write_room = digi_write_room, .write_bulk_callback = digi_write_bulk_callback, @@ -526,6 +289,8 @@ static struct usb_serial_driver digi_acceleport_2_device = { .attach = digi_startup, .disconnect = digi_disconnect, .release = digi_release, + .port_probe = digi_port_probe, + .port_remove = digi_port_remove, }; static struct usb_serial_driver digi_acceleport_4_device = { @@ -534,7 +299,6 @@ static struct usb_serial_driver digi_acceleport_4_device = { .name = "digi_4", }, .description = "Digi 4 port USB adapter", - .usb_driver = &digi_driver, .id_table = id_table_4, .num_ports = 4, .open = digi_open, @@ -553,8 +317,13 @@ static struct usb_serial_driver digi_acceleport_4_device = { .attach = digi_startup, .disconnect = digi_disconnect, .release = digi_release, + .port_probe = digi_port_probe, + .port_remove = digi_port_remove, }; +static struct usb_serial_driver * const serial_drivers[] = { + &digi_acceleport_2_device, &digi_acceleport_4_device, NULL +}; /* Functions */ @@ -602,20 +371,10 @@ static void digi_wakeup_write_lock(struct work_struct *work) unsigned long flags; spin_lock_irqsave(&priv->dp_port_lock, flags); - digi_wakeup_write(port); + tty_port_tty_wakeup(&port->port); spin_unlock_irqrestore(&priv->dp_port_lock, flags); } -static void digi_wakeup_write(struct usb_serial_port *port) -{ - struct tty_struct *tty = tty_port_tty_get(&port->port); - if (tty) { - tty_wakeup(tty); - tty_kref_put(tty); - } -} - - /* * Digi Write OOB Command * @@ -630,14 +389,15 @@ static void digi_wakeup_write(struct usb_serial_port *port) static int digi_write_oob_command(struct usb_serial_port *port, unsigned char *buf, int count, int interruptible) { - int ret = 0; int len; struct usb_serial_port *oob_port = (struct usb_serial_port *)((struct digi_serial *)(usb_get_serial_data(port->serial)))->ds_oob_port; struct digi_port *oob_priv = usb_get_serial_port_data(oob_port); unsigned long flags = 0; - dbg("digi_write_oob_command: TOP: port=%d, count=%d", oob_priv->dp_port_num, count); + dev_dbg(&port->dev, + "digi_write_oob_command: TOP: port=%d, count=%d\n", + oob_priv->dp_port_num, count); spin_lock_irqsave(&oob_priv->dp_port_lock, flags); while (count > 0) { @@ -656,7 +416,6 @@ static int digi_write_oob_command(struct usb_serial_port *port, len &= ~3; memcpy(oob_port->write_urb->transfer_buffer, buf, len); oob_port->write_urb->transfer_buffer_length = len; - oob_port->write_urb->dev = port->serial->dev; ret = usb_submit_urb(oob_port->write_urb, GFP_ATOMIC); if (ret == 0) { oob_priv->dp_write_urb_in_use = 1; @@ -694,7 +453,7 @@ static int digi_write_inb_command(struct usb_serial_port *port, unsigned char *data = port->write_urb->transfer_buffer; unsigned long flags = 0; - dbg("digi_write_inb_command: TOP: port=%d, count=%d", + dev_dbg(&port->dev, "digi_write_inb_command: TOP: port=%d, count=%d\n", priv->dp_port_num, count); if (timeout) @@ -734,7 +493,6 @@ static int digi_write_inb_command(struct usb_serial_port *port, memcpy(data, buf, len); port->write_urb->transfer_buffer_length = len; } - port->write_urb->dev = port->serial->dev; ret = usb_submit_urb(port->write_urb, GFP_ATOMIC); if (ret == 0) { @@ -777,7 +535,8 @@ static int digi_set_modem_signals(struct usb_serial_port *port, unsigned long flags = 0; - dbg("digi_set_modem_signals: TOP: port=%d, modem_signals=0x%x", + dev_dbg(&port->dev, + "digi_set_modem_signals: TOP: port=%d, modem_signals=0x%x\n", port_priv->dp_port_num, modem_signals); spin_lock_irqsave(&oob_priv->dp_port_lock, flags); @@ -805,7 +564,6 @@ static int digi_set_modem_signals(struct usb_serial_port *port, data[7] = 0; oob_port->write_urb->transfer_buffer_length = 8; - oob_port->write_urb->dev = port->serial->dev; ret = usb_submit_urb(oob_port->write_urb, GFP_ATOMIC); if (ret == 0) { @@ -878,9 +636,6 @@ static void digi_rx_throttle(struct tty_struct *tty) struct usb_serial_port *port = tty->driver_data; struct digi_port *priv = usb_get_serial_port_data(port); - - dbg("digi_rx_throttle: TOP: port=%d", priv->dp_port_num); - /* stop receiving characters by not resubmitting the read urb */ spin_lock_irqsave(&priv->dp_port_lock, flags); priv->dp_throttled = 1; @@ -896,15 +651,11 @@ static void digi_rx_unthrottle(struct tty_struct *tty) struct usb_serial_port *port = tty->driver_data; struct digi_port *priv = usb_get_serial_port_data(port); - dbg("digi_rx_unthrottle: TOP: port=%d", priv->dp_port_num); - spin_lock_irqsave(&priv->dp_port_lock, flags); /* restart read chain */ - if (priv->dp_throttle_restart) { - port->read_urb->dev = port->serial->dev; + if (priv->dp_throttle_restart) ret = usb_submit_urb(port->read_urb, GFP_ATOMIC); - } /* turn throttle off */ priv->dp_throttled = 0; @@ -923,8 +674,9 @@ static void digi_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios) { struct digi_port *priv = usb_get_serial_port_data(port); - unsigned int iflag = tty->termios->c_iflag; - unsigned int cflag = tty->termios->c_cflag; + struct device *dev = &port->dev; + unsigned int iflag = tty->termios.c_iflag; + unsigned int cflag = tty->termios.c_cflag; unsigned int old_iflag = old_termios->c_iflag; unsigned int old_cflag = old_termios->c_cflag; unsigned char buf[32]; @@ -933,7 +685,9 @@ static void digi_set_termios(struct tty_struct *tty, int i = 0; speed_t baud; - dbg("digi_set_termios: TOP: port=%d, iflag=0x%x, old_iflag=0x%x, cflag=0x%x, old_cflag=0x%x", priv->dp_port_num, iflag, old_iflag, cflag, old_cflag); + dev_dbg(dev, + "digi_set_termios: TOP: port=%d, iflag=0x%x, old_iflag=0x%x, cflag=0x%x, old_cflag=0x%x\n", + priv->dp_port_num, iflag, old_iflag, cflag, old_cflag); /* set baud rate */ baud = tty_get_baud_rate(tty); @@ -945,7 +699,7 @@ static void digi_set_termios(struct tty_struct *tty, /* don't set RTS if using hardware flow control */ /* and throttling input */ modem_signals = TIOCM_DTR; - if (!(tty->termios->c_cflag & CRTSCTS) || + if (!(tty->termios.c_cflag & CRTSCTS) || !test_bit(TTY_THROTTLED, &tty->flags)) modem_signals |= TIOCM_RTS; digi_set_modem_signals(port, modem_signals, 1); @@ -984,7 +738,7 @@ static void digi_set_termios(struct tty_struct *tty, } } /* set parity */ - tty->termios->c_cflag &= ~CMSPAR; + tty->termios.c_cflag &= ~CMSPAR; if ((cflag&(PARENB|PARODD)) != (old_cflag&(PARENB|PARODD))) { if (cflag&PARENB) { @@ -1009,7 +763,8 @@ static void digi_set_termios(struct tty_struct *tty, case CS7: arg = DIGI_WORD_SIZE_7; break; case CS8: arg = DIGI_WORD_SIZE_8; break; default: - dbg("digi_set_termios: can't handle word size %d", + dev_dbg(dev, + "digi_set_termios: can't handle word size %d\n", (cflag&CSIZE)); break; } @@ -1102,7 +857,7 @@ static void digi_set_termios(struct tty_struct *tty, } ret = digi_write_oob_command(port, buf, i, 1); if (ret != 0) - dbg("digi_set_termios: write oob failed, ret=%d", ret); + dev_dbg(dev, "digi_set_termios: write oob failed, ret=%d\n", ret); tty_encode_baud_rate(tty, baud, baud); } @@ -1120,15 +875,13 @@ static void digi_break_ctl(struct tty_struct *tty, int break_state) } -static int digi_tiocmget(struct tty_struct *tty, struct file *file) +static int digi_tiocmget(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; struct digi_port *priv = usb_get_serial_port_data(port); unsigned int val; unsigned long flags; - dbg("%s: TOP: port=%d", __func__, priv->dp_port_num); - spin_lock_irqsave(&priv->dp_port_lock, flags); val = priv->dp_modem_signals; spin_unlock_irqrestore(&priv->dp_port_lock, flags); @@ -1136,16 +889,14 @@ static int digi_tiocmget(struct tty_struct *tty, struct file *file) } -static int digi_tiocmset(struct tty_struct *tty, struct file *file, - unsigned int set, unsigned int clear) +static int digi_tiocmset(struct tty_struct *tty, + unsigned int set, unsigned int clear) { struct usb_serial_port *port = tty->driver_data; struct digi_port *priv = usb_get_serial_port_data(port); unsigned int val; unsigned long flags; - dbg("%s: TOP: port=%d", __func__, priv->dp_port_num); - spin_lock_irqsave(&priv->dp_port_lock, flags); val = (priv->dp_modem_signals & ~clear) | set; spin_unlock_irqrestore(&priv->dp_port_lock, flags); @@ -1162,7 +913,8 @@ static int digi_write(struct tty_struct *tty, struct usb_serial_port *port, unsigned char *data = port->write_urb->transfer_buffer; unsigned long flags = 0; - dbg("digi_write: TOP: port=%d, count=%d, in_interrupt=%ld", + dev_dbg(&port->dev, + "digi_write: TOP: port=%d, count=%d, in_interrupt=%ld\n", priv->dp_port_num, count, in_interrupt()); /* copy user data (which can sleep) before getting spin lock */ @@ -1197,7 +949,6 @@ static int digi_write(struct tty_struct *tty, struct usb_serial_port *port, } port->write_urb->transfer_buffer_length = data_len+2; - port->write_urb->dev = port->serial->dev; *data++ = DIGI_CMD_SEND_DATA; *data++ = data_len; @@ -1219,10 +970,10 @@ static int digi_write(struct tty_struct *tty, struct usb_serial_port *port, /* return length of new data written, or error */ spin_unlock_irqrestore(&priv->dp_port_lock, flags); if (ret < 0) - dev_err(&port->dev, + dev_err_console(port, "%s: usb_submit_urb failed, ret=%d, port=%d\n", __func__, ret, priv->dp_port_num); - dbg("digi_write: returning %d", ret); + dev_dbg(&port->dev, "digi_write: returning %d\n", ret); return ret; } @@ -1237,8 +988,6 @@ static void digi_write_bulk_callback(struct urb *urb) int ret = 0; int status = urb->status; - dbg("digi_write_bulk_callback: TOP, status=%d", status); - /* port and serial sanity check */ if (port == NULL || (priv = usb_get_serial_port_data(port)) == NULL) { pr_err("%s: port or port->private is NULL, status=%d\n", @@ -1255,7 +1004,7 @@ static void digi_write_bulk_callback(struct urb *urb) /* handle oob callback */ if (priv->dp_port_num == serial_priv->ds_oob_port_num) { - dbg("digi_write_bulk_callback: oob callback"); + dev_dbg(&port->dev, "digi_write_bulk_callback: oob callback\n"); spin_lock(&priv->dp_port_lock); priv->dp_write_urb_in_use = 0; wake_up_interruptible(&port->write_wait); @@ -1273,7 +1022,6 @@ static void digi_write_bulk_callback(struct urb *urb) = (unsigned char)priv->dp_out_buf_len; port->write_urb->transfer_buffer_length = priv->dp_out_buf_len + 2; - port->write_urb->dev = serial->dev; memcpy(port->write_urb->transfer_buffer + 2, priv->dp_out_buf, priv->dp_out_buf_len); ret = usb_submit_urb(port->write_urb, GFP_ATOMIC); @@ -1283,14 +1031,14 @@ static void digi_write_bulk_callback(struct urb *urb) } } /* wake up processes sleeping on writes immediately */ - digi_wakeup_write(port); + tty_port_tty_wakeup(&port->port); /* also queue up a wakeup at scheduler time, in case we */ /* lost the race in write_chan(). */ schedule_work(&priv->dp_wakeup_work); spin_unlock(&priv->dp_port_lock); if (ret && ret != -EPERM) - dev_err(&port->dev, + dev_err_console(port, "%s: usb_submit_urb failed, ret=%d, port=%d\n", __func__, ret, priv->dp_port_num); } @@ -1310,7 +1058,7 @@ static int digi_write_room(struct tty_struct *tty) room = port->bulk_out_size - 2 - priv->dp_out_buf_len; spin_unlock_irqrestore(&priv->dp_port_lock, flags); - dbg("digi_write_room: port=%d, room=%d", priv->dp_port_num, room); + dev_dbg(&port->dev, "digi_write_room: port=%d, room=%d\n", priv->dp_port_num, room); return room; } @@ -1321,12 +1069,12 @@ static int digi_chars_in_buffer(struct tty_struct *tty) struct digi_port *priv = usb_get_serial_port_data(port); if (priv->dp_write_urb_in_use) { - dbg("digi_chars_in_buffer: port=%d, chars=%d", + dev_dbg(&port->dev, "digi_chars_in_buffer: port=%d, chars=%d\n", priv->dp_port_num, port->bulk_out_size - 2); /* return(port->bulk_out_size - 2); */ return 256; } else { - dbg("digi_chars_in_buffer: port=%d, chars=%d", + dev_dbg(&port->dev, "digi_chars_in_buffer: port=%d, chars=%d\n", priv->dp_port_num, priv->dp_out_buf_len); return priv->dp_out_buf_len; } @@ -1339,14 +1087,6 @@ static void digi_dtr_rts(struct usb_serial_port *port, int on) digi_set_modem_signals(port, on * (TIOCM_DTR|TIOCM_RTS), 1); } -static int digi_carrier_raised(struct usb_serial_port *port) -{ - struct digi_port *priv = usb_get_serial_port_data(port); - if (priv->dp_modem_signals & TIOCM_CD) - return 1; - return 0; -} - static int digi_open(struct tty_struct *tty, struct usb_serial_port *port) { int ret; @@ -1354,8 +1094,6 @@ static int digi_open(struct tty_struct *tty, struct usb_serial_port *port) struct digi_port *priv = usb_get_serial_port_data(port); struct ktermios not_termios; - dbg("digi_open: TOP: port=%d", priv->dp_port_num); - /* be sure the device is started up */ if (digi_startup_device(port->serial) != 0) return -ENXIO; @@ -1374,12 +1112,12 @@ static int digi_open(struct tty_struct *tty, struct usb_serial_port *port) ret = digi_write_oob_command(port, buf, 8, 1); if (ret != 0) - dbg("digi_open: write oob failed, ret=%d", ret); + dev_dbg(&port->dev, "digi_open: write oob failed, ret=%d\n", ret); /* set termios settings */ if (tty) { - not_termios.c_cflag = ~tty->termios->c_cflag; - not_termios.c_iflag = ~tty->termios->c_iflag; + not_termios.c_cflag = ~tty->termios.c_cflag; + not_termios.c_iflag = ~tty->termios.c_iflag; digi_set_termios(tty, port, ¬_termios); } return 0; @@ -1393,67 +1131,62 @@ static void digi_close(struct usb_serial_port *port) unsigned char buf[32]; struct digi_port *priv = usb_get_serial_port_data(port); - dbg("digi_close: TOP: port=%d", priv->dp_port_num); - mutex_lock(&port->serial->disc_mutex); /* if disconnected, just clear flags */ if (port->serial->disconnected) goto exit; - if (port->serial->dev) { - /* FIXME: Transmit idle belongs in the wait_unti_sent path */ - digi_transmit_idle(port, DIGI_CLOSE_TIMEOUT); - - /* disable input flow control */ - buf[0] = DIGI_CMD_SET_INPUT_FLOW_CONTROL; - buf[1] = priv->dp_port_num; - buf[2] = DIGI_DISABLE; - buf[3] = 0; - - /* disable output flow control */ - buf[4] = DIGI_CMD_SET_OUTPUT_FLOW_CONTROL; - buf[5] = priv->dp_port_num; - buf[6] = DIGI_DISABLE; - buf[7] = 0; - - /* disable reading modem signals automatically */ - buf[8] = DIGI_CMD_READ_INPUT_SIGNALS; - buf[9] = priv->dp_port_num; - buf[10] = DIGI_DISABLE; - buf[11] = 0; - - /* disable receive */ - buf[12] = DIGI_CMD_RECEIVE_ENABLE; - buf[13] = priv->dp_port_num; - buf[14] = DIGI_DISABLE; - buf[15] = 0; - - /* flush fifos */ - buf[16] = DIGI_CMD_IFLUSH_FIFO; - buf[17] = priv->dp_port_num; - buf[18] = DIGI_FLUSH_TX | DIGI_FLUSH_RX; - buf[19] = 0; - - ret = digi_write_oob_command(port, buf, 20, 0); - if (ret != 0) - dbg("digi_close: write oob failed, ret=%d", ret); - - /* wait for final commands on oob port to complete */ - prepare_to_wait(&priv->dp_flush_wait, &wait, - TASK_INTERRUPTIBLE); - schedule_timeout(DIGI_CLOSE_TIMEOUT); - finish_wait(&priv->dp_flush_wait, &wait); - - /* shutdown any outstanding bulk writes */ - usb_kill_urb(port->write_urb); - } + /* FIXME: Transmit idle belongs in the wait_unti_sent path */ + digi_transmit_idle(port, DIGI_CLOSE_TIMEOUT); + + /* disable input flow control */ + buf[0] = DIGI_CMD_SET_INPUT_FLOW_CONTROL; + buf[1] = priv->dp_port_num; + buf[2] = DIGI_DISABLE; + buf[3] = 0; + + /* disable output flow control */ + buf[4] = DIGI_CMD_SET_OUTPUT_FLOW_CONTROL; + buf[5] = priv->dp_port_num; + buf[6] = DIGI_DISABLE; + buf[7] = 0; + + /* disable reading modem signals automatically */ + buf[8] = DIGI_CMD_READ_INPUT_SIGNALS; + buf[9] = priv->dp_port_num; + buf[10] = DIGI_DISABLE; + buf[11] = 0; + + /* disable receive */ + buf[12] = DIGI_CMD_RECEIVE_ENABLE; + buf[13] = priv->dp_port_num; + buf[14] = DIGI_DISABLE; + buf[15] = 0; + + /* flush fifos */ + buf[16] = DIGI_CMD_IFLUSH_FIFO; + buf[17] = priv->dp_port_num; + buf[18] = DIGI_FLUSH_TX | DIGI_FLUSH_RX; + buf[19] = 0; + + ret = digi_write_oob_command(port, buf, 20, 0); + if (ret != 0) + dev_dbg(&port->dev, "digi_close: write oob failed, ret=%d\n", + ret); + /* wait for final commands on oob port to complete */ + prepare_to_wait(&priv->dp_flush_wait, &wait, + TASK_INTERRUPTIBLE); + schedule_timeout(DIGI_CLOSE_TIMEOUT); + finish_wait(&priv->dp_flush_wait, &wait); + + /* shutdown any outstanding bulk writes */ + usb_kill_urb(port->write_urb); exit: spin_lock_irq(&priv->dp_port_lock); priv->dp_write_urb_in_use = 0; wake_up_interruptible(&priv->dp_close_wait); spin_unlock_irq(&priv->dp_port_lock); mutex_unlock(&port->serial->disc_mutex); - dbg("digi_close: done"); } @@ -1483,7 +1216,6 @@ static int digi_startup_device(struct usb_serial *serial) /* set USB_DISABLE_SPD flag for write bulk urbs */ for (i = 0; i < serial->type->num_ports + 1; i++) { port = serial->port[i]; - port->write_urb->dev = port->serial->dev; ret = usb_submit_urb(port->read_urb, GFP_KERNEL); if (ret != 0) { dev_err(&port->dev, @@ -1495,61 +1227,49 @@ static int digi_startup_device(struct usb_serial *serial) return ret; } - -static int digi_startup(struct usb_serial *serial) +static int digi_port_init(struct usb_serial_port *port, unsigned port_num) { - - int i; struct digi_port *priv; - struct digi_serial *serial_priv; - dbg("digi_startup: TOP"); + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; - /* allocate the private data structures for all ports */ - /* number of regular ports + 1 for the out-of-band port */ - for (i = 0; i < serial->type->num_ports + 1; i++) { - /* allocate port private structure */ - priv = kmalloc(sizeof(struct digi_port), GFP_KERNEL); - if (priv == NULL) { - while (--i >= 0) - kfree(usb_get_serial_port_data(serial->port[i])); - return 1; /* error */ - } + spin_lock_init(&priv->dp_port_lock); + priv->dp_port_num = port_num; + init_waitqueue_head(&priv->dp_transmit_idle_wait); + init_waitqueue_head(&priv->dp_flush_wait); + init_waitqueue_head(&priv->dp_close_wait); + INIT_WORK(&priv->dp_wakeup_work, digi_wakeup_write_lock); + priv->dp_port = port; - /* initialize port private structure */ - spin_lock_init(&priv->dp_port_lock); - priv->dp_port_num = i; - priv->dp_out_buf_len = 0; - priv->dp_write_urb_in_use = 0; - priv->dp_modem_signals = 0; - init_waitqueue_head(&priv->dp_modem_change_wait); - priv->dp_transmit_idle = 0; - init_waitqueue_head(&priv->dp_transmit_idle_wait); - priv->dp_throttled = 0; - priv->dp_throttle_restart = 0; - init_waitqueue_head(&priv->dp_flush_wait); - init_waitqueue_head(&priv->dp_close_wait); - INIT_WORK(&priv->dp_wakeup_work, digi_wakeup_write_lock); - priv->dp_port = serial->port[i]; - /* initialize write wait queue for this port */ - init_waitqueue_head(&serial->port[i]->write_wait); - - usb_set_serial_port_data(serial->port[i], priv); - } + init_waitqueue_head(&port->write_wait); - /* allocate serial private structure */ - serial_priv = kmalloc(sizeof(struct digi_serial), GFP_KERNEL); - if (serial_priv == NULL) { - for (i = 0; i < serial->type->num_ports + 1; i++) - kfree(usb_get_serial_port_data(serial->port[i])); - return 1; /* error */ - } + usb_set_serial_port_data(port, priv); + + return 0; +} + +static int digi_startup(struct usb_serial *serial) +{ + struct digi_serial *serial_priv; + int ret; + + serial_priv = kzalloc(sizeof(*serial_priv), GFP_KERNEL); + if (!serial_priv) + return -ENOMEM; - /* initialize serial private structure */ spin_lock_init(&serial_priv->ds_serial_lock); serial_priv->ds_oob_port_num = serial->type->num_ports; serial_priv->ds_oob_port = serial->port[serial_priv->ds_oob_port_num]; - serial_priv->ds_device_started = 0; + + ret = digi_port_init(serial_priv->ds_oob_port, + serial_priv->ds_oob_port_num); + if (ret) { + kfree(serial_priv); + return ret; + } + usb_set_serial_data(serial, serial_priv); return 0; @@ -1559,7 +1279,6 @@ static int digi_startup(struct usb_serial *serial) static void digi_disconnect(struct usb_serial *serial) { int i; - dbg("digi_disconnect: TOP, in_interrupt()=%ld", in_interrupt()); /* stop reads and writes on all ports */ for (i = 0; i < serial->type->num_ports + 1; i++) { @@ -1571,16 +1290,31 @@ static void digi_disconnect(struct usb_serial *serial) static void digi_release(struct usb_serial *serial) { - int i; - dbg("digi_release: TOP, in_interrupt()=%ld", in_interrupt()); + struct digi_serial *serial_priv; + struct digi_port *priv; + + serial_priv = usb_get_serial_data(serial); - /* free the private data structures for all ports */ - /* number of regular ports + 1 for the out-of-band port */ - for (i = 0; i < serial->type->num_ports + 1; i++) - kfree(usb_get_serial_port_data(serial->port[i])); - kfree(usb_get_serial_data(serial)); + priv = usb_get_serial_port_data(serial_priv->ds_oob_port); + kfree(priv); + + kfree(serial_priv); +} + +static int digi_port_probe(struct usb_serial_port *port) +{ + return digi_port_init(port, port->port_number); } +static int digi_port_remove(struct usb_serial_port *port) +{ + struct digi_port *priv; + + priv = usb_get_serial_port_data(port); + kfree(priv); + + return 0; +} static void digi_read_bulk_callback(struct urb *urb) { @@ -1590,8 +1324,6 @@ static void digi_read_bulk_callback(struct urb *urb) int ret; int status = urb->status; - dbg("digi_read_bulk_callback: TOP"); - /* port sanity check, do not resubmit if port is not valid */ if (port == NULL) return; @@ -1626,7 +1358,6 @@ static void digi_read_bulk_callback(struct urb *urb) } /* continue read */ - urb->dev = port->serial->dev; ret = usb_submit_urb(urb, GFP_ATOMIC); if (ret != 0 && ret != -EPERM) { dev_err(&port->dev, @@ -1648,9 +1379,7 @@ static void digi_read_bulk_callback(struct urb *urb) static int digi_read_inb_callback(struct urb *urb) { - struct usb_serial_port *port = urb->context; - struct tty_struct *tty; struct digi_port *priv = usb_get_serial_port_data(port); int opcode = ((unsigned char *)urb->transfer_buffer)[0]; int len = ((unsigned char *)urb->transfer_buffer)[1]; @@ -1674,7 +1403,6 @@ static int digi_read_inb_callback(struct urb *urb) return -1; } - tty = tty_port_tty_get(&port->port); spin_lock(&priv->dp_port_lock); /* check for throttle; if set, do not resubmit read urb */ @@ -1684,13 +1412,13 @@ static int digi_read_inb_callback(struct urb *urb) priv->dp_throttle_restart = 1; /* receive data */ - if (tty && opcode == DIGI_CMD_RECEIVE_DATA) { + if (opcode == DIGI_CMD_RECEIVE_DATA) { /* get flag from port_status */ flag = 0; /* overrun is special, not associated with a char */ if (port_status & DIGI_OVERRUN_ERROR) - tty_insert_flip_char(tty, 0, TTY_OVERRUN); + tty_insert_flip_char(&port->port, 0, TTY_OVERRUN); /* break takes precedence over parity, */ /* which takes precedence over framing errors */ @@ -1704,18 +1432,17 @@ static int digi_read_inb_callback(struct urb *urb) /* data length is len-1 (one byte of len is port_status) */ --len; if (len > 0) { - tty_insert_flip_string_fixed_flag(tty, data, flag, - len); - tty_flip_buffer_push(tty); + tty_insert_flip_string_fixed_flag(&port->port, data, + flag, len); + tty_flip_buffer_push(&port->port); } } spin_unlock(&priv->dp_port_lock); - tty_kref_put(tty); if (opcode == DIGI_CMD_RECEIVE_DISABLE) - dbg("%s: got RECEIVE_DISABLE", __func__); + dev_dbg(&port->dev, "%s: got RECEIVE_DISABLE\n", __func__); else if (opcode != DIGI_CMD_RECEIVE_DATA) - dbg("%s: unknown opcode: %d", __func__, opcode); + dev_dbg(&port->dev, "%s: unknown opcode: %d\n", __func__, opcode); return throttled ? 1 : 0; @@ -1742,9 +1469,6 @@ static int digi_read_oob_callback(struct urb *urb) int i; unsigned int rts; - dbg("digi_read_oob_callback: port=%d, len=%d", - priv->dp_port_num, urb->actual_length); - /* handle each oob command */ for (i = 0; i < urb->actual_length - 3;) { opcode = ((unsigned char *)urb->transfer_buffer)[i++]; @@ -1752,7 +1476,7 @@ static int digi_read_oob_callback(struct urb *urb) status = ((unsigned char *)urb->transfer_buffer)[i++]; val = ((unsigned char *)urb->transfer_buffer)[i++]; - dbg("digi_read_oob_callback: opcode=%d, line=%d, status=%d, val=%d", + dev_dbg(&port->dev, "digi_read_oob_callback: opcode=%d, line=%d, status=%d, val=%d\n", opcode, line, status, val); if (status != 0 || line >= serial->type->num_ports) @@ -1768,7 +1492,7 @@ static int digi_read_oob_callback(struct urb *urb) rts = 0; if (tty) - rts = tty->termios->c_cflag & CRTSCTS; + rts = tty->termios.c_cflag & CRTSCTS; if (tty && opcode == DIGI_CMD_READ_INPUT_SIGNALS) { spin_lock(&priv->dp_port_lock); @@ -1778,7 +1502,7 @@ static int digi_read_oob_callback(struct urb *urb) /* port must be open to use tty struct */ if (rts) { tty->hw_stopped = 0; - digi_wakeup_write(port); + tty_port_tty_wakeup(&port->port); } } else { priv->dp_modem_signals &= ~TIOCM_CTS; @@ -1799,7 +1523,6 @@ static int digi_read_oob_callback(struct urb *urb) else priv->dp_modem_signals &= ~TIOCM_CD; - wake_up_interruptible(&priv->dp_modem_change_wait); spin_unlock(&priv->dp_port_lock); } else if (opcode == DIGI_CMD_TRANSMIT_IDLE) { spin_lock(&priv->dp_port_lock); @@ -1815,44 +1538,8 @@ static int digi_read_oob_callback(struct urb *urb) } -static int __init digi_init(void) -{ - int retval; - retval = usb_serial_register(&digi_acceleport_2_device); - if (retval) - goto failed_acceleport_2_device; - retval = usb_serial_register(&digi_acceleport_4_device); - if (retval) - goto failed_acceleport_4_device; - retval = usb_register(&digi_driver); - if (retval) - goto failed_usb_register; - printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" - DRIVER_DESC "\n"); - return 0; -failed_usb_register: - usb_serial_deregister(&digi_acceleport_4_device); -failed_acceleport_4_device: - usb_serial_deregister(&digi_acceleport_2_device); -failed_acceleport_2_device: - return retval; -} - -static void __exit digi_exit (void) -{ - usb_deregister(&digi_driver); - usb_serial_deregister(&digi_acceleport_2_device); - usb_serial_deregister(&digi_acceleport_4_device); -} - - -module_init(digi_init); -module_exit(digi_exit); - +module_usb_serial_driver(serial_drivers, id_table_combined); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c index 504b5585ea4..90e603d5f66 100644 --- a/drivers/usb/serial/empeg.c +++ b/drivers/usb/serial/empeg.c @@ -17,7 +17,6 @@ #include <linux/kernel.h> #include <linux/errno.h> -#include <linux/init.h> #include <linux/slab.h> #include <linux/tty.h> #include <linux/tty_driver.h> @@ -28,12 +27,6 @@ #include <linux/usb.h> #include <linux/usb/serial.h> -static int debug; - -/* - * Version Information - */ -#define DRIVER_VERSION "v1.3" #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Gary Brubaker <xavyer@ix.netcom.com>" #define DRIVER_DESC "USB Empeg Mark I/II Driver" @@ -51,21 +44,12 @@ static const struct usb_device_id id_table[] = { MODULE_DEVICE_TABLE(usb, id_table); -static struct usb_driver empeg_driver = { - .name = "empeg", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, - .no_dynamic_id = 1, -}; - static struct usb_serial_driver empeg_device = { .driver = { .owner = THIS_MODULE, .name = "empeg", }, .id_table = id_table, - .usb_driver = &empeg_driver, .num_ports = 1, .bulk_out_size = 256, .throttle = usb_serial_generic_throttle, @@ -74,18 +58,20 @@ static struct usb_serial_driver empeg_device = { .init_termios = empeg_init_termios, }; +static struct usb_serial_driver * const serial_drivers[] = { + &empeg_device, NULL +}; + static int empeg_startup(struct usb_serial *serial) { int r; - dbg("%s", __func__); - if (serial->dev->actconfig->desc.bConfigurationValue != 1) { dev_err(&serial->dev->dev, "active config #%d != 1 ??\n", serial->dev->actconfig->desc.bConfigurationValue); return -ENODEV; } - dbg("%s - reset config", __func__); + r = usb_reset_configuration(serial->dev); /* continue on with initialization */ @@ -94,7 +80,7 @@ static int empeg_startup(struct usb_serial *serial) static void empeg_init_termios(struct tty_struct *tty) { - struct ktermios *termios = tty->termios; + struct ktermios *termios = &tty->termios; /* * The empeg-car player wants these particular tty settings. @@ -136,37 +122,8 @@ static void empeg_init_termios(struct tty_struct *tty) tty_encode_baud_rate(tty, 115200, 115200); } -static int __init empeg_init(void) -{ - int retval; - - retval = usb_serial_register(&empeg_device); - if (retval) - return retval; - retval = usb_register(&empeg_driver); - if (retval) { - usb_serial_deregister(&empeg_device); - return retval; - } - printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" - DRIVER_DESC "\n"); - - return 0; -} - -static void __exit empeg_exit(void) -{ - usb_deregister(&empeg_driver); - usb_serial_deregister(&empeg_device); -} - - -module_init(empeg_init); -module_exit(empeg_exit); +module_usb_serial_driver(serial_drivers, id_table); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/drivers/usb/serial/ezusb.c b/drivers/usb/serial/ezusb.c deleted file mode 100644 index 3cfc762f505..00000000000 --- a/drivers/usb/serial/ezusb.c +++ /dev/null @@ -1,61 +0,0 @@ -/* - * EZ-USB specific functions used by some of the USB to Serial drivers. - * - * Copyright (C) 1999 - 2002 Greg Kroah-Hartman (greg@kroah.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - */ - -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/tty.h> -#include <linux/module.h> -#include <linux/usb.h> -#include <linux/usb/serial.h> - -/* EZ-USB Control and Status Register. Bit 0 controls 8051 reset */ -#define CPUCS_REG 0x7F92 - -int ezusb_writememory(struct usb_serial *serial, int address, - unsigned char *data, int length, __u8 request) -{ - int result; - unsigned char *transfer_buffer; - - /* dbg("ezusb_writememory %x, %d", address, length); */ - if (!serial->dev) { - printk(KERN_ERR "ezusb: %s - no physical device present, " - "failing.\n", __func__); - return -ENODEV; - } - - transfer_buffer = kmemdup(data, length, GFP_KERNEL); - if (!transfer_buffer) { - dev_err(&serial->dev->dev, "%s - kmalloc(%d) failed.\n", - __func__, length); - return -ENOMEM; - } - result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - request, 0x40, address, 0, transfer_buffer, length, 3000); - kfree(transfer_buffer); - return result; -} -EXPORT_SYMBOL_GPL(ezusb_writememory); - -int ezusb_set_reset(struct usb_serial *serial, unsigned char reset_bit) -{ - int response; - - /* dbg("%s - %d", __func__, reset_bit); */ - response = ezusb_writememory(serial, CPUCS_REG, &reset_bit, 1, 0xa0); - if (response < 0) - dev_err(&serial->dev->dev, "%s- %d failed\n", - __func__, reset_bit); - return response; -} -EXPORT_SYMBOL_GPL(ezusb_set_reset); - diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c new file mode 100644 index 00000000000..c5dc233db2d --- /dev/null +++ b/drivers/usb/serial/f81232.c @@ -0,0 +1,334 @@ +/* + * Fintek F81232 USB to serial adaptor driver + * + * Copyright (C) 2012 Greg Kroah-Hartman (gregkh@linuxfoundation.org) + * Copyright (C) 2012 Linux Foundation + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + */ + +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/slab.h> +#include <linux/tty.h> +#include <linux/tty_driver.h> +#include <linux/tty_flip.h> +#include <linux/serial.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/spinlock.h> +#include <linux/uaccess.h> +#include <linux/usb.h> +#include <linux/usb/serial.h> + +static const struct usb_device_id id_table[] = { + { USB_DEVICE(0x1934, 0x0706) }, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(usb, id_table); + +#define CONTROL_DTR 0x01 +#define CONTROL_RTS 0x02 + +#define UART_STATE 0x08 +#define UART_STATE_TRANSIENT_MASK 0x74 +#define UART_DCD 0x01 +#define UART_DSR 0x02 +#define UART_BREAK_ERROR 0x04 +#define UART_RING 0x08 +#define UART_FRAME_ERROR 0x10 +#define UART_PARITY_ERROR 0x20 +#define UART_OVERRUN_ERROR 0x40 +#define UART_CTS 0x80 + +struct f81232_private { + spinlock_t lock; + u8 line_control; + u8 line_status; +}; + +static void f81232_update_line_status(struct usb_serial_port *port, + unsigned char *data, + unsigned int actual_length) +{ + /* + * FIXME: Update port->icount, and call + * + * wake_up_interruptible(&port->port.delta_msr_wait); + * + * on MSR changes. + */ +} + +static void f81232_read_int_callback(struct urb *urb) +{ + struct usb_serial_port *port = urb->context; + unsigned char *data = urb->transfer_buffer; + unsigned int actual_length = urb->actual_length; + int status = urb->status; + int retval; + + switch (status) { + case 0: + /* success */ + break; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + /* this urb is terminated, clean up */ + dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n", + __func__, status); + return; + default: + dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n", + __func__, status); + goto exit; + } + + usb_serial_debug_data(&port->dev, __func__, + urb->actual_length, urb->transfer_buffer); + + f81232_update_line_status(port, data, actual_length); + +exit: + retval = usb_submit_urb(urb, GFP_ATOMIC); + if (retval) + dev_err(&urb->dev->dev, + "%s - usb_submit_urb failed with result %d\n", + __func__, retval); +} + +static void f81232_process_read_urb(struct urb *urb) +{ + struct usb_serial_port *port = urb->context; + struct f81232_private *priv = usb_get_serial_port_data(port); + unsigned char *data = urb->transfer_buffer; + char tty_flag = TTY_NORMAL; + unsigned long flags; + u8 line_status; + int i; + + /* update line status */ + spin_lock_irqsave(&priv->lock, flags); + line_status = priv->line_status; + priv->line_status &= ~UART_STATE_TRANSIENT_MASK; + spin_unlock_irqrestore(&priv->lock, flags); + + if (!urb->actual_length) + return; + + /* break takes precedence over parity, */ + /* which takes precedence over framing errors */ + if (line_status & UART_BREAK_ERROR) + tty_flag = TTY_BREAK; + else if (line_status & UART_PARITY_ERROR) + tty_flag = TTY_PARITY; + else if (line_status & UART_FRAME_ERROR) + tty_flag = TTY_FRAME; + dev_dbg(&port->dev, "%s - tty_flag = %d\n", __func__, tty_flag); + + /* overrun is special, not associated with a char */ + if (line_status & UART_OVERRUN_ERROR) + tty_insert_flip_char(&port->port, 0, TTY_OVERRUN); + + if (port->port.console && port->sysrq) { + for (i = 0; i < urb->actual_length; ++i) + if (!usb_serial_handle_sysrq_char(port, data[i])) + tty_insert_flip_char(&port->port, data[i], + tty_flag); + } else { + tty_insert_flip_string_fixed_flag(&port->port, data, tty_flag, + urb->actual_length); + } + + tty_flip_buffer_push(&port->port); +} + +static int set_control_lines(struct usb_device *dev, u8 value) +{ + /* FIXME - Stubbed out for now */ + return 0; +} + +static void f81232_break_ctl(struct tty_struct *tty, int break_state) +{ + /* FIXME - Stubbed out for now */ + + /* + * break_state = -1 to turn on break, and 0 to turn off break + * see drivers/char/tty_io.c to see it used. + * last_set_data_urb_value NEVER has the break bit set in it. + */ +} + +static void f81232_set_termios(struct tty_struct *tty, + struct usb_serial_port *port, struct ktermios *old_termios) +{ + /* FIXME - Stubbed out for now */ + + /* Don't change anything if nothing has changed */ + if (old_termios && !tty_termios_hw_change(&tty->termios, old_termios)) + return; + + /* Do the real work here... */ + if (old_termios) + tty_termios_copy_hw(&tty->termios, old_termios); +} + +static int f81232_tiocmget(struct tty_struct *tty) +{ + /* FIXME - Stubbed out for now */ + return 0; +} + +static int f81232_tiocmset(struct tty_struct *tty, + unsigned int set, unsigned int clear) +{ + /* FIXME - Stubbed out for now */ + return 0; +} + +static int f81232_open(struct tty_struct *tty, struct usb_serial_port *port) +{ + int result; + + /* Setup termios */ + if (tty) + f81232_set_termios(tty, port, NULL); + + result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); + if (result) { + dev_err(&port->dev, "%s - failed submitting interrupt urb," + " error %d\n", __func__, result); + return result; + } + + result = usb_serial_generic_open(tty, port); + if (result) { + usb_kill_urb(port->interrupt_in_urb); + return result; + } + + return 0; +} + +static void f81232_close(struct usb_serial_port *port) +{ + usb_serial_generic_close(port); + usb_kill_urb(port->interrupt_in_urb); +} + +static void f81232_dtr_rts(struct usb_serial_port *port, int on) +{ + struct f81232_private *priv = usb_get_serial_port_data(port); + unsigned long flags; + u8 control; + + spin_lock_irqsave(&priv->lock, flags); + /* Change DTR and RTS */ + if (on) + priv->line_control |= (CONTROL_DTR | CONTROL_RTS); + else + priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS); + control = priv->line_control; + spin_unlock_irqrestore(&priv->lock, flags); + set_control_lines(port->serial->dev, control); +} + +static int f81232_carrier_raised(struct usb_serial_port *port) +{ + struct f81232_private *priv = usb_get_serial_port_data(port); + if (priv->line_status & UART_DCD) + return 1; + return 0; +} + +static int f81232_ioctl(struct tty_struct *tty, + unsigned int cmd, unsigned long arg) +{ + struct serial_struct ser; + struct usb_serial_port *port = tty->driver_data; + + switch (cmd) { + case TIOCGSERIAL: + memset(&ser, 0, sizeof ser); + ser.type = PORT_16654; + ser.line = port->minor; + ser.port = port->port_number; + ser.baud_base = 460800; + + if (copy_to_user((void __user *)arg, &ser, sizeof ser)) + return -EFAULT; + + return 0; + default: + break; + } + return -ENOIOCTLCMD; +} + +static int f81232_port_probe(struct usb_serial_port *port) +{ + struct f81232_private *priv; + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + spin_lock_init(&priv->lock); + + usb_set_serial_port_data(port, priv); + + port->port.drain_delay = 256; + + return 0; +} + +static int f81232_port_remove(struct usb_serial_port *port) +{ + struct f81232_private *priv; + + priv = usb_get_serial_port_data(port); + kfree(priv); + + return 0; +} + +static struct usb_serial_driver f81232_device = { + .driver = { + .owner = THIS_MODULE, + .name = "f81232", + }, + .id_table = id_table, + .num_ports = 1, + .bulk_in_size = 256, + .bulk_out_size = 256, + .open = f81232_open, + .close = f81232_close, + .dtr_rts = f81232_dtr_rts, + .carrier_raised = f81232_carrier_raised, + .ioctl = f81232_ioctl, + .break_ctl = f81232_break_ctl, + .set_termios = f81232_set_termios, + .tiocmget = f81232_tiocmget, + .tiocmset = f81232_tiocmset, + .tiocmiwait = usb_serial_generic_tiocmiwait, + .process_read_urb = f81232_process_read_urb, + .read_int_callback = f81232_read_int_callback, + .port_probe = f81232_port_probe, + .port_remove = f81232_port_remove, +}; + +static struct usb_serial_driver * const serial_drivers[] = { + &f81232_device, + NULL, +}; + +module_usb_serial_driver(serial_drivers, id_table); + +MODULE_DESCRIPTION("Fintek F81232 USB to serial adaptor driver"); +MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@linuxfoundation.org"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 76f8b355667..8a3813be1b2 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1,7 +1,7 @@ /* * USB FTDI SIO driver * - * Copyright (C) 2009 - 2010 + * Copyright (C) 2009 - 2013 * Johan Hovold (jhovold@gmail.com) * Copyright (C) 1999 - 2001 * Greg Kroah-Hartman (greg@kroah.com) @@ -17,7 +17,7 @@ * See Documentation/usb/usb-serial.txt for more information on using this * driver * - * See http://ftdi-usb-sio.sourceforge.net for upto date testing info + * See http://ftdi-usb-sio.sourceforge.net for up to date testing info * and extra documentation * * Change entries from 2004 and earlier can be found in versions of this @@ -33,7 +33,6 @@ #include <linux/kernel.h> #include <linux/errno.h> -#include <linux/init.h> #include <linux/slab.h> #include <linux/tty.h> #include <linux/tty_driver.h> @@ -48,19 +47,11 @@ #include "ftdi_sio.h" #include "ftdi_sio_ids.h" -/* - * Version Information - */ -#define DRIVER_VERSION "v1.6.0" #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Bill Ryder <bryder@sgi.com>, Kuba Ober <kuba@mareimbrium.org>, Andreas Mohr, Johan Hovold <jhovold@gmail.com>" #define DRIVER_DESC "USB FTDI Serial Converters Driver" -static int debug; -static __u16 vendor = FTDI_VID; -static __u16 product; struct ftdi_private { - struct kref kref; enum ftdi_chip_type chip_type; /* type of device, either SIO or FT8U232AM */ int baud_base; /* baud base clock for divisor setting */ @@ -73,9 +64,8 @@ struct ftdi_private { */ int flags; /* some ASYNC_xxxx flags are supported */ unsigned long last_dtr_rts; /* saved modem control outputs */ - wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */ - char prev_status, diff_status; /* Used for TIOCMIWAIT */ - struct usb_serial_port *port; + char prev_status; /* Used for TIOCMIWAIT */ + char transmit_empty; /* If transmitter is empty or not */ __u16 interface; /* FT2232C, FT2232H or FT4232H port interface (0 for FT232/245) */ @@ -99,6 +89,8 @@ struct ftdi_sio_quirk { static int ftdi_jtag_probe(struct usb_serial *serial); static int ftdi_mtxorb_hack_setup(struct usb_serial *serial); static int ftdi_NDI_device_setup(struct usb_serial *serial); +static int ftdi_stmclite_probe(struct usb_serial *serial); +static int ftdi_8u2232c_probe(struct usb_serial *serial); static void ftdi_USB_UIRT_setup(struct ftdi_private *priv); static void ftdi_HE_TIRA1_setup(struct ftdi_private *priv); @@ -122,6 +114,14 @@ static struct ftdi_sio_quirk ftdi_HE_TIRA1_quirk = { .port_probe = ftdi_HE_TIRA1_setup, }; +static struct ftdi_sio_quirk ftdi_stmclite_quirk = { + .probe = ftdi_stmclite_probe, +}; + +static struct ftdi_sio_quirk ftdi_8u2232c_quirk = { + .probe = ftdi_8u2232c_probe, +}; + /* * The 8U232AM has the same API as the sio except for: * - it can support MUCH higher baudrates; up to: @@ -141,14 +141,18 @@ static struct ftdi_sio_quirk ftdi_HE_TIRA1_quirk = { /* - * Device ID not listed? Test via module params product/vendor or - * /sys/bus/usb/ftdi_sio/new_id, then send patch/report! + * Device ID not listed? Test it using + * /sys/bus/usb-serial/drivers/ftdi_sio/new_id and send a patch or report. */ -static struct usb_device_id id_table_combined [] = { +static const struct usb_device_id id_table_combined[] = { + { USB_DEVICE(FTDI_VID, FTDI_ZEITCONTROL_TAGTRACE_MIFARE_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CTI_MINI_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CTI_NANO_PID) }, { USB_DEVICE(FTDI_VID, FTDI_AMC232_PID) }, { USB_DEVICE(FTDI_VID, FTDI_CANUSB_PID) }, { USB_DEVICE(FTDI_VID, FTDI_CANDAPTER_PID) }, { USB_DEVICE(FTDI_VID, FTDI_NXTCAM_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_EV3CON_PID) }, { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_0_PID) }, { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_1_PID) }, { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_2_PID) }, @@ -169,8 +173,11 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) }, { USB_DEVICE(FTDI_VID, FTDI_8U232AM_ALT_PID) }, { USB_DEVICE(FTDI_VID, FTDI_232RL_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_8U2232C_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_8U2232C_PID) , + .driver_info = (kernel_ulong_t)&ftdi_8u2232c_quirk }, { USB_DEVICE(FTDI_VID, FTDI_4232H_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_232H_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_FTX_PID) }, { USB_DEVICE(FTDI_VID, FTDI_MICRO_CHAMELEON_PID) }, { USB_DEVICE(FTDI_VID, FTDI_RELAIS_PID) }, { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_PID) }, @@ -178,9 +185,15 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_THROTTLE_PID) }, { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_GATEWAY_PID) }, { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_GBM_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_GBM_BOOST_PID) }, + { USB_DEVICE(NEWPORT_VID, NEWPORT_AGILIS_PID) }, + { USB_DEVICE(NEWPORT_VID, NEWPORT_CONEX_CC_PID) }, + { USB_DEVICE(NEWPORT_VID, NEWPORT_CONEX_AGP_PID) }, { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_IOBOARD_PID) }, { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_MINI_IOBOARD_PID) }, { USB_DEVICE(FTDI_VID, FTDI_SPROG_II) }, + { USB_DEVICE(FTDI_VID, FTDI_TAGSYS_LP101_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_TAGSYS_P200X_PID) }, { USB_DEVICE(FTDI_VID, FTDI_LENZ_LIUSB_PID) }, { USB_DEVICE(FTDI_VID, FTDI_XF_632_PID) }, { USB_DEVICE(FTDI_VID, FTDI_XF_634_PID) }, @@ -191,6 +204,8 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_XF_640_PID) }, { USB_DEVICE(FTDI_VID, FTDI_XF_642_PID) }, { USB_DEVICE(FTDI_VID, FTDI_DSS20_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_URBAN_0_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_URBAN_1_PID) }, { USB_DEVICE(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID) }, { USB_DEVICE(FTDI_VID, FTDI_VNHCPCUSB_D_PID) }, { USB_DEVICE(FTDI_VID, FTDI_MTXORB_0_PID) }, @@ -201,6 +216,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_MTXORB_5_PID) }, { USB_DEVICE(FTDI_VID, FTDI_MTXORB_6_PID) }, { USB_DEVICE(FTDI_VID, FTDI_R2000KU_TRUE_RNG) }, + { USB_DEVICE(FTDI_VID, FTDI_VARDAAN_PID) }, { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0100_PID) }, { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0101_PID) }, { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0102_PID) }, @@ -516,8 +532,13 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_6_PID) }, { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_7_PID) }, { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_8_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803R_1_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803R_2_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803R_3_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803R_4_PID) }, { USB_DEVICE(IDTECH_VID, IDTECH_IDT1221U_PID) }, { USB_DEVICE(OCT_VID, OCT_US101_PID) }, + { USB_DEVICE(OCT_VID, OCT_DK201_PID) }, { USB_DEVICE(FTDI_VID, FTDI_HE_TIRA1_PID), .driver_info = (kernel_ulong_t)&ftdi_HE_TIRA1_quirk }, { USB_DEVICE(FTDI_VID, FTDI_USB_UIRT_PID), @@ -556,9 +577,15 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_IBS_APP70_PID) }, { USB_DEVICE(FTDI_VID, FTDI_IBS_PEDO_PID) }, { USB_DEVICE(FTDI_VID, FTDI_IBS_PROD_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_TAVIR_STK500_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_TIAO_UMPA_PID), + .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, + { USB_DEVICE(FTDI_VID, FTDI_NT_ORIONLXM_PID), + .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, /* * ELV devices: */ + { USB_DEVICE(FTDI_ELV_VID, FTDI_ELV_WS300_PID) }, { USB_DEVICE(FTDI_VID, FTDI_ELV_USR_PID) }, { USB_DEVICE(FTDI_VID, FTDI_ELV_MSM1_PID) }, { USB_DEVICE(FTDI_VID, FTDI_ELV_KL100_PID) }, @@ -614,7 +641,9 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_OCEANIC_PID) }, { USB_DEVICE(TTI_VID, TTI_QL355P_PID) }, { USB_DEVICE(FTDI_VID, FTDI_RM_CANVIEW_PID) }, + { USB_DEVICE(ACTON_VID, ACTON_SPECTRAPRO_PID) }, { USB_DEVICE(CONTEC_VID, CONTEC_COM1USBH_PID) }, + { USB_DEVICE(MITSUBISHI_VID, MITSUBISHI_FXUSB_PID) }, { USB_DEVICE(BANDB_VID, BANDB_USOTL4_PID) }, { USB_DEVICE(BANDB_VID, BANDB_USTL4_PID) }, { USB_DEVICE(BANDB_VID, BANDB_USO9ML2_PID) }, @@ -635,6 +664,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, EVER_ECO_PRO_CDS) }, { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_1_PID) }, { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_2_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_3_PID) }, { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_0_PID) }, { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_1_PID) }, { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_2_PID) }, @@ -643,6 +673,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_5_PID) }, { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_6_PID) }, { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_7_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_OMNI1509) }, { USB_DEVICE(MOBILITY_VID, MOBILITY_USB_SERIAL_PID) }, { USB_DEVICE(FTDI_VID, FTDI_ACTIVE_ROBOTS_PID) }, { USB_DEVICE(FTDI_VID, FTDI_MHAM_KW_PID) }, @@ -674,11 +705,23 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_PCDJ_DAC2_PID) }, { USB_DEVICE(FTDI_VID, FTDI_RRCIRKITS_LOCOBUFFER_PID) }, { USB_DEVICE(FTDI_VID, FTDI_ASK_RDR400_PID) }, - { USB_DEVICE(ICOM_ID1_VID, ICOM_ID1_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_NZR_SEM_USB_PID) }, + { USB_DEVICE(ICOM_VID, ICOM_ID_1_PID) }, + { USB_DEVICE(ICOM_VID, ICOM_OPC_U_UC_PID) }, + { USB_DEVICE(ICOM_VID, ICOM_ID_RP2C1_PID) }, + { USB_DEVICE(ICOM_VID, ICOM_ID_RP2C2_PID) }, + { USB_DEVICE(ICOM_VID, ICOM_ID_RP2D_PID) }, + { USB_DEVICE(ICOM_VID, ICOM_ID_RP2VT_PID) }, + { USB_DEVICE(ICOM_VID, ICOM_ID_RP2VR_PID) }, + { USB_DEVICE(ICOM_VID, ICOM_ID_RP4KVT_PID) }, + { USB_DEVICE(ICOM_VID, ICOM_ID_RP4KVR_PID) }, + { USB_DEVICE(ICOM_VID, ICOM_ID_RP2KVT_PID) }, + { USB_DEVICE(ICOM_VID, ICOM_ID_RP2KVR_PID) }, { USB_DEVICE(FTDI_VID, FTDI_ACG_HFDUAL_PID) }, { USB_DEVICE(FTDI_VID, FTDI_YEI_SERVOCENTER31_PID) }, { USB_DEVICE(FTDI_VID, FTDI_THORLABS_PID) }, - { USB_DEVICE(TESTO_VID, TESTO_USB_INTERFACE_PID) }, + { USB_DEVICE(TESTO_VID, TESTO_1_PID) }, + { USB_DEVICE(TESTO_VID, TESTO_3_PID) }, { USB_DEVICE(FTDI_VID, FTDI_GAMMA_SCOUT_PID) }, { USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13M_PID) }, { USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13S_PID) }, @@ -695,14 +738,44 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_NDI_AURORA_SCU_PID), .driver_info = (kernel_ulong_t)&ftdi_NDI_device_quirk }, { USB_DEVICE(TELLDUS_VID, TELLDUS_TELLSTICK_PID) }, - { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_SERIAL_VX7_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_S03_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_59_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_57A_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_57B_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_29A_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_29B_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_29F_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_62B_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_S01_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_63_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_29C_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_81B_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_82B_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_K5D_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_K4Y_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_K5G_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_S05_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_60_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_61_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_62_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_63B_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_64_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_65_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_92_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_92D_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_W5R_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_A5R_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_PW1_PID) }, { USB_DEVICE(FTDI_VID, FTDI_MAXSTREAM_PID) }, { USB_DEVICE(FTDI_VID, FTDI_PHI_FISCO_PID) }, { USB_DEVICE(TML_VID, TML_USB_SERIAL_PID) }, { USB_DEVICE(FTDI_VID, FTDI_ELSTER_UNICOM_PID) }, { USB_DEVICE(FTDI_VID, FTDI_PROPOX_JTAGCABLEII_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_PROPOX_ISPCABLEIII_PID) }, { USB_DEVICE(OLIMEX_VID, OLIMEX_ARM_USB_OCD_PID), .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, + { USB_DEVICE(OLIMEX_VID, OLIMEX_ARM_USB_OCD_H_PID), + .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, { USB_DEVICE(FIC_VID, FIC_NEO1973_DEBUG_PID), .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, { USB_DEVICE(FTDI_VID, FTDI_OOCDLINK_PID), @@ -711,6 +784,8 @@ static struct usb_device_id id_table_combined [] = { .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, { USB_DEVICE(FTDI_VID, LMI_LM3S_EVAL_BOARD_PID), .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, + { USB_DEVICE(FTDI_VID, LMI_LM3S_ICDI_BOARD_PID), + .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, { USB_DEVICE(FTDI_VID, FTDI_TURTELIZER_PID), .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID_USB60F) }, @@ -757,15 +832,41 @@ static struct usb_device_id id_table_combined [] = { .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, { USB_DEVICE(ADI_VID, ADI_GNICEPLUS_PID), .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, + { USB_DEVICE_AND_INTERFACE_INFO(MICROCHIP_VID, MICROCHIP_USB_BOARD_PID, + USB_CLASS_VENDOR_SPEC, + USB_SUBCLASS_VENDOR_SPEC, 0x00) }, { USB_DEVICE(JETI_VID, JETI_SPC1201_PID) }, { USB_DEVICE(MARVELL_VID, MARVELL_SHEEVAPLUG_PID), .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, { USB_DEVICE(LARSENBRUSGAARD_VID, LB_ALTITRACK_PID) }, { USB_DEVICE(GN_OTOMETRICS_VID, AURICAL_USB_PID) }, + { USB_DEVICE(FTDI_VID, PI_C865_PID) }, + { USB_DEVICE(FTDI_VID, PI_C857_PID) }, + { USB_DEVICE(PI_VID, PI_C866_PID) }, + { USB_DEVICE(PI_VID, PI_C663_PID) }, + { USB_DEVICE(PI_VID, PI_C725_PID) }, + { USB_DEVICE(PI_VID, PI_E517_PID) }, + { USB_DEVICE(PI_VID, PI_C863_PID) }, + { USB_DEVICE(PI_VID, PI_E861_PID) }, + { USB_DEVICE(PI_VID, PI_C867_PID) }, + { USB_DEVICE(PI_VID, PI_E609_PID) }, + { USB_DEVICE(PI_VID, PI_E709_PID) }, + { USB_DEVICE(PI_VID, PI_100F_PID) }, + { USB_DEVICE(PI_VID, PI_1011_PID) }, + { USB_DEVICE(PI_VID, PI_1012_PID) }, + { USB_DEVICE(PI_VID, PI_1013_PID) }, + { USB_DEVICE(PI_VID, PI_1014_PID) }, + { USB_DEVICE(PI_VID, PI_1015_PID) }, + { USB_DEVICE(PI_VID, PI_1016_PID) }, + { USB_DEVICE(KONDO_VID, KONDO_USB_SERIAL_PID) }, { USB_DEVICE(BAYER_VID, BAYER_CONTOUR_CABLE_PID) }, { USB_DEVICE(FTDI_VID, MARVELL_OPENRD_PID), .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, + { USB_DEVICE(FTDI_VID, TI_XDS100V2_PID), + .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, { USB_DEVICE(FTDI_VID, HAMEG_HO820_PID) }, + { USB_DEVICE(FTDI_VID, HAMEG_HO720_PID) }, + { USB_DEVICE(FTDI_VID, HAMEG_HO730_PID) }, { USB_DEVICE(FTDI_VID, HAMEG_HO870_PID) }, { USB_DEVICE(FTDI_VID, MJSG_GENERIC_PID) }, { USB_DEVICE(FTDI_VID, MJSG_SR_RADIO_PID) }, @@ -794,22 +895,63 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_LOGBOOKML_PID) }, { USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_LS_LOGBOOK_PID) }, { USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_HS_LOGBOOK_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CINTERION_MC55I_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_DOTEC_PID) }, { USB_DEVICE(QIHARDWARE_VID, MILKYMISTONE_JTAGSERIAL_PID), .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, - { }, /* Optional parameter entry */ + { USB_DEVICE(ST_VID, ST_STMCLT_2232_PID), + .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, + { USB_DEVICE(ST_VID, ST_STMCLT_4232_PID), + .driver_info = (kernel_ulong_t)&ftdi_stmclite_quirk }, + { USB_DEVICE(FTDI_VID, FTDI_RF_R106) }, + { USB_DEVICE(FTDI_VID, FTDI_DISTORTEC_JTAG_LOCK_PICK_PID), + .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, + { USB_DEVICE(FTDI_VID, FTDI_LUMEL_PD12_PID) }, + /* Crucible Devices */ + { USB_DEVICE(FTDI_VID, FTDI_CT_COMET_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_Z3X_PID) }, + /* Cressi Devices */ + { USB_DEVICE(FTDI_VID, FTDI_CRESSI_PID) }, + /* Brainboxes Devices */ + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_VX_001_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_VX_012_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_VX_023_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_VX_034_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_101_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_160_1_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_160_2_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_160_3_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_160_4_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_160_5_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_160_6_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_160_7_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_160_8_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_257_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_279_1_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_279_2_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_279_3_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_279_4_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_313_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_324_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_346_1_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_346_2_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_357_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_606_1_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_606_2_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_606_3_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_701_1_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_701_2_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_842_1_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_842_2_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_842_3_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_842_4_PID) }, + /* Infineon Devices */ + { USB_DEVICE_INTERFACE_NUMBER(INFINEON_VID, INFINEON_TRIBOARD_PID, 1) }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, id_table_combined); -static struct usb_driver ftdi_driver = { - .name = "ftdi_sio", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table_combined, - .no_dynamic_id = 1, -}; - static const char *ftdi_chip_name[] = { [SIO] = "SIO", /* the serial part of FT8U100AX */ [FT8U232AM] = "FT8U232AM", @@ -817,7 +959,9 @@ static const char *ftdi_chip_name[] = { [FT2232C] = "FT2232C", [FT232RL] = "FT232RL", [FT2232H] = "FT2232H", - [FT4232H] = "FT4232H" + [FT4232H] = "FT4232H", + [FT232H] = "FT232H", + [FTX] = "FT-X" }; @@ -826,28 +970,27 @@ static const char *ftdi_chip_name[] = { #define FTDI_STATUS_B1_MASK (FTDI_RS_BI) /* End TIOCMIWAIT */ -#define FTDI_IMPL_ASYNC_FLAGS = (ASYNC_SPD_HI | ASYNC_SPD_VHI \ - | ASYNC_SPD_CUST | ASYNC_SPD_SHI | ASYNC_SPD_WARP) - /* function prototypes for a FTDI serial converter */ static int ftdi_sio_probe(struct usb_serial *serial, const struct usb_device_id *id); static int ftdi_sio_port_probe(struct usb_serial_port *port); static int ftdi_sio_port_remove(struct usb_serial_port *port); static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port); -static void ftdi_close(struct usb_serial_port *port); static void ftdi_dtr_rts(struct usb_serial_port *port, int on); static void ftdi_process_read_urb(struct urb *urb); static int ftdi_prepare_write_buffer(struct usb_serial_port *port, void *dest, size_t size); static void ftdi_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old); -static int ftdi_tiocmget(struct tty_struct *tty, struct file *file); -static int ftdi_tiocmset(struct tty_struct *tty, struct file *file, +static int ftdi_tiocmget(struct tty_struct *tty); +static int ftdi_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear); -static int ftdi_ioctl(struct tty_struct *tty, struct file *file, +static int ftdi_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg); static void ftdi_break_ctl(struct tty_struct *tty, int break_state); +static bool ftdi_tx_empty(struct usb_serial_port *port); +static int ftdi_get_modem_status(struct usb_serial_port *port, + unsigned char status[2]); static unsigned short int ftdi_232am_baud_base_to_divisor(int baud, int base); static unsigned short int ftdi_232am_baud_to_divisor(int baud); @@ -862,7 +1005,6 @@ static struct usb_serial_driver ftdi_sio_device = { .name = "ftdi_sio", }, .description = "FTDI USB Serial Device", - .usb_driver = &ftdi_driver, .id_table = id_table_combined, .num_ports = 1, .bulk_in_size = 512, @@ -871,7 +1013,6 @@ static struct usb_serial_driver ftdi_sio_device = { .port_probe = ftdi_sio_port_probe, .port_remove = ftdi_sio_port_remove, .open = ftdi_open, - .close = ftdi_close, .dtr_rts = ftdi_dtr_rts, .throttle = usb_serial_generic_throttle, .unthrottle = usb_serial_generic_unthrottle, @@ -879,19 +1020,22 @@ static struct usb_serial_driver ftdi_sio_device = { .prepare_write_buffer = ftdi_prepare_write_buffer, .tiocmget = ftdi_tiocmget, .tiocmset = ftdi_tiocmset, + .tiocmiwait = usb_serial_generic_tiocmiwait, + .get_icount = usb_serial_generic_get_icount, .ioctl = ftdi_ioctl, .set_termios = ftdi_set_termios, .break_ctl = ftdi_break_ctl, + .tx_empty = ftdi_tx_empty, +}; + +static struct usb_serial_driver * const serial_drivers[] = { + &ftdi_sio_device, NULL }; #define WDR_TIMEOUT 5000 /* default urb timeout */ #define WDR_SHORT_TIMEOUT 1000 /* shorter urb timeout */ -/* High and low are for DTR, RTS etc etc */ -#define HIGH 1 -#define LOW 0 - /* * *************************************************************************** * Utility functions @@ -951,7 +1095,7 @@ static __u32 ftdi_2232h_baud_base_to_divisor(int baud, int base) int divisor3; /* hi-speed baud rate is 10-bit sampling instead of 16-bit */ - divisor3 = (base / 10 / baud) * 8; + divisor3 = base * 8 / (baud * 10); divisor = divisor3 >> 3; divisor |= (__u32)divfrac[divisor3 & 0x7] << 14; @@ -981,11 +1125,12 @@ static int update_mctrl(struct usb_serial_port *port, unsigned int set, unsigned int clear) { struct ftdi_private *priv = usb_get_serial_port_data(port); + struct device *dev = &port->dev; unsigned urb_value; int rv; if (((set | clear) & (TIOCM_DTR | TIOCM_RTS)) == 0) { - dbg("%s - DTR|RTS not being set|cleared", __func__); + dev_dbg(dev, "%s - DTR|RTS not being set|cleared\n", __func__); return 0; /* no change */ } @@ -1006,18 +1151,15 @@ static int update_mctrl(struct usb_serial_port *port, unsigned int set, urb_value, priv->interface, NULL, 0, WDR_TIMEOUT); if (rv < 0) { - dbg("%s Error from MODEM_CTRL urb: DTR %s, RTS %s", - __func__, - (set & TIOCM_DTR) ? "HIGH" : - (clear & TIOCM_DTR) ? "LOW" : "unchanged", - (set & TIOCM_RTS) ? "HIGH" : - (clear & TIOCM_RTS) ? "LOW" : "unchanged"); + dev_dbg(dev, "%s Error from MODEM_CTRL urb: DTR %s, RTS %s\n", + __func__, + (set & TIOCM_DTR) ? "HIGH" : (clear & TIOCM_DTR) ? "LOW" : "unchanged", + (set & TIOCM_RTS) ? "HIGH" : (clear & TIOCM_RTS) ? "LOW" : "unchanged"); + rv = usb_translate_errors(rv); } else { - dbg("%s - DTR %s, RTS %s", __func__, - (set & TIOCM_DTR) ? "HIGH" : - (clear & TIOCM_DTR) ? "LOW" : "unchanged", - (set & TIOCM_RTS) ? "HIGH" : - (clear & TIOCM_RTS) ? "LOW" : "unchanged"); + dev_dbg(dev, "%s - DTR %s, RTS %s\n", __func__, + (set & TIOCM_DTR) ? "HIGH" : (clear & TIOCM_DTR) ? "LOW" : "unchanged", + (set & TIOCM_RTS) ? "HIGH" : (clear & TIOCM_RTS) ? "LOW" : "unchanged"); /* FIXME: locking on last_dtr_rts */ priv->last_dtr_rts = (priv->last_dtr_rts & ~clear) | set; } @@ -1029,6 +1171,7 @@ static __u32 get_ftdi_divisor(struct tty_struct *tty, struct usb_serial_port *port) { struct ftdi_private *priv = usb_get_serial_port_data(port); + struct device *dev = &port->dev; __u32 div_value = 0; int div_okay = 1; int baud; @@ -1064,7 +1207,7 @@ static __u32 get_ftdi_divisor(struct tty_struct *tty, alt_speed hack */ baud = tty_get_baud_rate(tty); - dbg("%s - tty_get_baud_rate reports speed %d", __func__, baud); + dev_dbg(dev, "%s - tty_get_baud_rate reports speed %d\n", __func__, baud); /* 2. Observe async-compatible custom_divisor hack, update baudrate if needed */ @@ -1073,8 +1216,8 @@ static __u32 get_ftdi_divisor(struct tty_struct *tty, ((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) && (priv->custom_divisor)) { baud = priv->baud_base / priv->custom_divisor; - dbg("%s - custom divisor %d sets baud rate to %d", - __func__, priv->custom_divisor, baud); + dev_dbg(dev, "%s - custom divisor %d sets baud rate to %d\n", + __func__, priv->custom_divisor, baud); } /* 3. Convert baudrate to device-specific divisor */ @@ -1096,8 +1239,8 @@ static __u32 get_ftdi_divisor(struct tty_struct *tty, case 115200: div_value = ftdi_sio_b115200; break; } /* baud */ if (div_value == 0) { - dbg("%s - Baudrate (%d) requested is not supported", - __func__, baud); + dev_dbg(dev, "%s - Baudrate (%d) requested is not supported\n", + __func__, baud); div_value = ftdi_sio_b9600; baud = 9600; div_okay = 0; @@ -1107,7 +1250,7 @@ static __u32 get_ftdi_divisor(struct tty_struct *tty, if (baud <= 3000000) { div_value = ftdi_232am_baud_to_divisor(baud); } else { - dbg("%s - Baud rate too high!", __func__); + dev_dbg(dev, "%s - Baud rate too high!\n", __func__); baud = 9600; div_value = ftdi_232am_baud_to_divisor(9600); div_okay = 0; @@ -1115,7 +1258,8 @@ static __u32 get_ftdi_divisor(struct tty_struct *tty, break; case FT232BM: /* FT232BM chip */ case FT2232C: /* FT2232C chip */ - case FT232RL: + case FT232RL: /* FT232RL chip */ + case FTX: /* FT-X series */ if (baud <= 3000000) { __u16 product_id = le16_to_cpu( port->serial->dev->descriptor.idProduct); @@ -1129,7 +1273,7 @@ static __u32 get_ftdi_divisor(struct tty_struct *tty, } div_value = ftdi_232bm_baud_to_divisor(baud); } else { - dbg("%s - Baud rate too high!", __func__); + dev_dbg(dev, "%s - Baud rate too high!\n", __func__); div_value = ftdi_232bm_baud_to_divisor(9600); div_okay = 0; baud = 9600; @@ -1137,12 +1281,13 @@ static __u32 get_ftdi_divisor(struct tty_struct *tty, break; case FT2232H: /* FT2232H chip */ case FT4232H: /* FT4232H chip */ - if ((baud <= 12000000) & (baud >= 1200)) { + case FT232H: /* FT232H chip */ + if ((baud <= 12000000) && (baud >= 1200)) { div_value = ftdi_2232h_baud_to_divisor(baud); } else if (baud < 1200) { div_value = ftdi_232bm_baud_to_divisor(baud); } else { - dbg("%s - Baud rate too high!", __func__); + dev_dbg(dev, "%s - Baud rate too high!\n", __func__); div_value = ftdi_232bm_baud_to_divisor(9600); div_okay = 0; baud = 9600; @@ -1151,7 +1296,7 @@ static __u32 get_ftdi_divisor(struct tty_struct *tty, } /* priv->chip_type */ if (div_okay) { - dbg("%s - Baud rate set to %d (divisor 0x%lX) on chip %s", + dev_dbg(dev, "%s - Baud rate set to %d (divisor 0x%lX) on chip %s\n", __func__, baud, (unsigned long)div_value, ftdi_chip_name[priv->chip_type]); } @@ -1171,7 +1316,10 @@ static int change_speed(struct tty_struct *tty, struct usb_serial_port *port) urb_index_value = get_ftdi_divisor(tty, port); urb_value = (__u16)urb_index_value; urb_index = (__u16)(urb_index_value >> 16); - if (priv->interface) { /* FT2232C */ + if ((priv->chip_type == FT2232C) || (priv->chip_type == FT2232H) || + (priv->chip_type == FT4232H) || (priv->chip_type == FT232H)) { + /* Probably the BM type needs the MSB of the encoded fractional + * divider also moved like for the chips above. Any infos? */ urb_index = (__u16)((urb_index << 8) | priv->interface); } @@ -1194,7 +1342,7 @@ static int write_latency_timer(struct usb_serial_port *port) if (priv->flags & ASYNC_LOW_LATENCY) l = 1; - dbg("%s: setting latency timer = %i", __func__, l); + dev_dbg(&port->dev, "%s: setting latency timer = %i\n", __func__, l); rv = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), @@ -1214,8 +1362,6 @@ static int read_latency_timer(struct usb_serial_port *port) unsigned char *buf; int rv; - dbg("%s", __func__); - buf = kmalloc(1, GFP_KERNEL); if (!buf) return -ENOMEM; @@ -1280,8 +1426,7 @@ static int set_serial_info(struct tty_struct *tty, goto check_and_exit; } - if ((new_serial.baud_base != priv->baud_base) && - (new_serial.baud_base < 9600)) { + if (new_serial.baud_base != priv->baud_base) { mutex_unlock(&priv->cfg_lock); return -EINVAL; } @@ -1320,6 +1465,23 @@ check_and_exit: return 0; } +static int get_lsr_info(struct usb_serial_port *port, + struct serial_struct __user *retinfo) +{ + struct ftdi_private *priv = usb_get_serial_port_data(port); + unsigned int result = 0; + + if (!retinfo) + return -EFAULT; + + if (priv->transmit_empty) + result = TIOCSER_TEMT; + + if (copy_to_user(retinfo, &result, sizeof(unsigned int))) + return -EFAULT; + return 0; +} + /* Determine type of FTDI chip based on USB config and descriptor. */ static void ftdi_determine_type(struct usb_serial_port *port) @@ -1335,8 +1497,8 @@ static void ftdi_determine_type(struct usb_serial_port *port) version = le16_to_cpu(udev->descriptor.bcdDevice); interfaces = udev->actconfig->desc.bNumInterfaces; - dbg("%s: bcdDevice = 0x%x, bNumInterfaces = %u", __func__, - version, interfaces); + dev_dbg(&port->dev, "%s: bcdDevice = 0x%x, bNumInterfaces = %u\n", __func__, + version, interfaces); if (interfaces > 1) { int inter; @@ -1366,8 +1528,9 @@ static void ftdi_determine_type(struct usb_serial_port *port) /* BM-type devices have a bug where bcdDevice gets set * to 0x200 when iSerialNumber is 0. */ if (version < 0x500) { - dbg("%s: something fishy - bcdDevice too low for multi-interface device", - __func__); + dev_dbg(&port->dev, + "%s: something fishy - bcdDevice too low for multi-interface device\n", + __func__); } } else if (version < 0x200) { /* Old device. Assume it's the original SIO. */ @@ -1381,10 +1544,17 @@ static void ftdi_determine_type(struct usb_serial_port *port) } else if (version < 0x600) { /* Assume it's an FT232BM (or FT245BM) */ priv->chip_type = FT232BM; - } else { - /* Assume it's an FT232R */ + } else if (version < 0x900) { + /* Assume it's an FT232RL */ priv->chip_type = FT232RL; + } else if (version < 0x1000) { + /* Assume it's an FT232H */ + priv->chip_type = FT232H; + } else { + /* Assume it's an FT-X series device */ + priv->chip_type = FTX; } + dev_info(&udev->dev, "Detected %s\n", ftdi_chip_name[priv->chip_type]); } @@ -1399,14 +1569,17 @@ static void ftdi_set_max_packet_size(struct usb_serial_port *port) struct usb_device *udev = serial->dev; struct usb_interface *interface = serial->interface; - struct usb_endpoint_descriptor *ep_desc = &interface->cur_altsetting->endpoint[1].desc; + struct usb_endpoint_descriptor *ep_desc; unsigned num_endpoints; - int i; + unsigned i; num_endpoints = interface->cur_altsetting->desc.bNumEndpoints; dev_info(&udev->dev, "Number of endpoints %d\n", num_endpoints); + if (!num_endpoints) + return; + /* NOTE: some customers have programmed FT232R/FT245R devices * with an endpoint size of 0 - not good. In this case, we * want to override the endpoint descriptor setting and use a @@ -1422,7 +1595,7 @@ static void ftdi_set_max_packet_size(struct usb_serial_port *port) } /* set max packet size based on descriptor */ - priv->max_packet_size = le16_to_cpu(ep_desc->wMaxPacketSize); + priv->max_packet_size = usb_endpoint_maxp(ep_desc); dev_info(&udev->dev, "Setting MaxPacketSize %d\n", priv->max_packet_size); } @@ -1434,8 +1607,8 @@ static void ftdi_set_max_packet_size(struct usb_serial_port *port) * *************************************************************************** */ -static ssize_t show_latency_timer(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t latency_timer_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct usb_serial_port *port = to_usb_serial_port(dev); struct ftdi_private *priv = usb_get_serial_port_data(port); @@ -1445,11 +1618,10 @@ static ssize_t show_latency_timer(struct device *dev, return sprintf(buf, "%i\n", priv->latency); } - /* Write a new value of the latency timer, in units of milliseconds. */ -static ssize_t store_latency_timer(struct device *dev, - struct device_attribute *attr, const char *valbuf, - size_t count) +static ssize_t latency_timer_store(struct device *dev, + struct device_attribute *attr, + const char *valbuf, size_t count) { struct usb_serial_port *port = to_usb_serial_port(dev); struct ftdi_private *priv = usb_get_serial_port_data(port); @@ -1462,6 +1634,7 @@ static ssize_t store_latency_timer(struct device *dev, return -EIO; return count; } +static DEVICE_ATTR_RW(latency_timer); /* Write an event character directly to the FTDI register. The ASCII value is in the low 8 bits, with the enable bit in the 9th bit. */ @@ -1474,7 +1647,7 @@ static ssize_t store_event_char(struct device *dev, int v = simple_strtoul(valbuf, NULL, 10); int rv; - dbg("%s: setting event char = %i", __func__, v); + dev_dbg(&port->dev, "%s: setting event char = %i\n", __func__, v); rv = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), @@ -1483,15 +1656,12 @@ static ssize_t store_event_char(struct device *dev, v, priv->interface, NULL, 0, WDR_TIMEOUT); if (rv < 0) { - dbg("Unable to write event character: %i", rv); + dev_dbg(&port->dev, "Unable to write event character: %i\n", rv); return -EIO; } return count; } - -static DEVICE_ATTR(latency_timer, S_IWUSR | S_IRUGO, show_latency_timer, - store_latency_timer); static DEVICE_ATTR(event_char, S_IWUSR, NULL, store_event_char); static int create_sysfs_attrs(struct usb_serial_port *port) @@ -1499,19 +1669,19 @@ static int create_sysfs_attrs(struct usb_serial_port *port) struct ftdi_private *priv = usb_get_serial_port_data(port); int retval = 0; - dbg("%s", __func__); - /* XXX I've no idea if the original SIO supports the event_char * sysfs parameter, so I'm playing it safe. */ if (priv->chip_type != SIO) { - dbg("sysfs attributes for %s", ftdi_chip_name[priv->chip_type]); + dev_dbg(&port->dev, "sysfs attributes for %s\n", ftdi_chip_name[priv->chip_type]); retval = device_create_file(&port->dev, &dev_attr_event_char); if ((!retval) && (priv->chip_type == FT232BM || priv->chip_type == FT2232C || priv->chip_type == FT232RL || priv->chip_type == FT2232H || - priv->chip_type == FT4232H)) { + priv->chip_type == FT4232H || + priv->chip_type == FT232H || + priv->chip_type == FTX)) { retval = device_create_file(&port->dev, &dev_attr_latency_timer); } @@ -1523,8 +1693,6 @@ static void remove_sysfs_attrs(struct usb_serial_port *port) { struct ftdi_private *priv = usb_get_serial_port_data(port); - dbg("%s", __func__); - /* XXX see create_sysfs_attrs */ if (priv->chip_type != SIO) { device_remove_file(&port->dev, &dev_attr_event_char); @@ -1532,7 +1700,9 @@ static void remove_sysfs_attrs(struct usb_serial_port *port) priv->chip_type == FT2232C || priv->chip_type == FT232RL || priv->chip_type == FT2232H || - priv->chip_type == FT4232H) { + priv->chip_type == FT4232H || + priv->chip_type == FT232H || + priv->chip_type == FTX) { device_remove_file(&port->dev, &dev_attr_latency_timer); } } @@ -1569,25 +1739,17 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port) struct ftdi_sio_quirk *quirk = usb_get_serial_data(port->serial); - dbg("%s", __func__); - priv = kzalloc(sizeof(struct ftdi_private), GFP_KERNEL); - if (!priv) { - dev_err(&port->dev, "%s- kmalloc(%Zd) failed.\n", __func__, - sizeof(struct ftdi_private)); + if (!priv) return -ENOMEM; - } - kref_init(&priv->kref); mutex_init(&priv->cfg_lock); - init_waitqueue_head(&priv->delta_msr_wait); priv->flags = ASYNC_LOW_LATENCY; if (quirk && quirk->port_probe) quirk->port_probe(priv); - priv->port = port; usb_set_serial_port_data(port, priv); ftdi_determine_type(port); @@ -1604,8 +1766,6 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port) /* Called from usbserial:serial_probe */ static void ftdi_USB_UIRT_setup(struct ftdi_private *priv) { - dbg("%s", __func__); - priv->flags |= ASYNC_SPD_CUST; priv->custom_divisor = 77; priv->force_baud = 38400; @@ -1616,8 +1776,6 @@ static void ftdi_USB_UIRT_setup(struct ftdi_private *priv) static void ftdi_HE_TIRA1_setup(struct ftdi_private *priv) { - dbg("%s", __func__); - priv->flags |= ASYNC_SPD_CUST; priv->custom_divisor = 240; priv->force_baud = 38400; @@ -1626,7 +1784,8 @@ static void ftdi_HE_TIRA1_setup(struct ftdi_private *priv) /* * Module parameter to control latency timer for NDI FTDI-based USB devices. - * If this value is not set in modprobe.conf.local its value will be set to 1ms. + * If this value is not set in /etc/modprobe.d/ its value will be set + * to 1ms. */ static int ndi_latency_timer = 1; @@ -1645,8 +1804,8 @@ static int ftdi_NDI_device_setup(struct usb_serial *serial) if (latency > 99) latency = 99; - dbg("%s setting NDI device latency to %d", __func__, latency); - dev_info(&udev->dev, "NDI device with a latency value of %d", latency); + dev_dbg(&udev->dev, "%s setting NDI device latency to %d\n", __func__, latency); + dev_info(&udev->dev, "NDI device with a latency value of %d\n", latency); /* FIXME: errors are not returned */ usb_control_msg(udev, usb_sndctrlpipe(udev, 0), @@ -1666,8 +1825,6 @@ static int ftdi_jtag_probe(struct usb_serial *serial) struct usb_device *udev = serial->dev; struct usb_interface *interface = serial->interface; - dbg("%s", __func__); - if (interface == udev->actconfig->interface[0]) { dev_info(&udev->dev, "Ignoring serial port reserved for JTAG\n"); @@ -1677,6 +1834,38 @@ static int ftdi_jtag_probe(struct usb_serial *serial) return 0; } +static int ftdi_8u2232c_probe(struct usb_serial *serial) +{ + struct usb_device *udev = serial->dev; + + if ((udev->manufacturer && !strcmp(udev->manufacturer, "CALAO Systems")) || + (udev->product && !strcmp(udev->product, "BeagleBone/XDS100V2"))) + return ftdi_jtag_probe(serial); + + return 0; +} + +/* + * First two ports on JTAG adaptors using an FT4232 such as STMicroelectronics's + * ST Micro Connect Lite are reserved for JTAG or other non-UART interfaces and + * can be accessed from userspace. + * The next two ports are enabled as UARTs by default, where port 2 is + * a conventional RS-232 UART. + */ +static int ftdi_stmclite_probe(struct usb_serial *serial) +{ + struct usb_device *udev = serial->dev; + struct usb_interface *interface = serial->interface; + + if (interface == udev->actconfig->interface[0] || + interface == udev->actconfig->interface[1]) { + dev_info(&udev->dev, "Ignoring serial port reserved for JTAG\n"); + return -ENODEV; + } + + return 0; +} + /* * The Matrix Orbital VK204-25-USB has an invalid IN endpoint. * We have to correct it if we want to read from it. @@ -1695,22 +1884,13 @@ static int ftdi_mtxorb_hack_setup(struct usb_serial *serial) return 0; } -static void ftdi_sio_priv_release(struct kref *k) -{ - struct ftdi_private *priv = container_of(k, struct ftdi_private, kref); - - kfree(priv); -} - static int ftdi_sio_port_remove(struct usb_serial_port *port) { struct ftdi_private *priv = usb_get_serial_port_data(port); - dbg("%s", __func__); - remove_sysfs_attrs(port); - kref_put(&priv->kref, ftdi_sio_priv_release); + kfree(priv); return 0; } @@ -1719,9 +1899,6 @@ static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port) { struct usb_device *dev = port->serial->dev; struct ftdi_private *priv = usb_get_serial_port_data(port); - int result; - - dbg("%s", __func__); /* No error checking for this (will get errors later anyway) */ /* See ftdi_sio.h for description of what is reset */ @@ -1736,53 +1913,31 @@ static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port) /* ftdi_set_termios will send usb control messages */ if (tty) - ftdi_set_termios(tty, port, tty->termios); + ftdi_set_termios(tty, port, NULL); - /* Start reading from the device */ - result = usb_serial_generic_open(tty, port); - if (!result) - kref_get(&priv->kref); - - return result; + return usb_serial_generic_open(tty, port); } static void ftdi_dtr_rts(struct usb_serial_port *port, int on) { struct ftdi_private *priv = usb_get_serial_port_data(port); - mutex_lock(&port->serial->disc_mutex); - if (!port->serial->disconnected) { - /* Disable flow control */ - if (!on && usb_control_msg(port->serial->dev, + /* Disable flow control */ + if (!on) { + if (usb_control_msg(port->serial->dev, usb_sndctrlpipe(port->serial->dev, 0), FTDI_SIO_SET_FLOW_CTRL_REQUEST, FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, 0, priv->interface, NULL, 0, WDR_TIMEOUT) < 0) { - dev_err(&port->dev, "error from flowcontrol urb\n"); + dev_err(&port->dev, "error from flowcontrol urb\n"); } - /* drop RTS and DTR */ - if (on) - set_mctrl(port, TIOCM_DTR | TIOCM_RTS); - else - clear_mctrl(port, TIOCM_DTR | TIOCM_RTS); } - mutex_unlock(&port->serial->disc_mutex); -} - -/* - * usbserial:__serial_close only calls ftdi_close if the point is open - * - * This only gets called when it is the last close - */ -static void ftdi_close(struct usb_serial_port *port) -{ - struct ftdi_private *priv = usb_get_serial_port_data(port); - - dbg("%s", __func__); - - usb_serial_generic_close(port); - kref_put(&priv->kref, ftdi_sio_priv_release); + /* drop RTS and DTR */ + if (on) + set_mctrl(port, TIOCM_DTR | TIOCM_RTS); + else + clear_mctrl(port, TIOCM_DTR | TIOCM_RTS); } /* The SIO requires the first byte to have: @@ -1812,6 +1967,7 @@ static int ftdi_prepare_write_buffer(struct usb_serial_port *port, c = kfifo_out(&port->write_fifo, &buffer[i + 1], len); if (!c) break; + port->icount.tx += c; buffer[i] = (c << 2) + 1; count += c + 1; } @@ -1819,6 +1975,7 @@ static int ftdi_prepare_write_buffer(struct usb_serial_port *port, } else { count = kfifo_out_locked(&port->write_fifo, dest, size, &port->lock); + port->icount.tx += count; } return count; @@ -1826,19 +1983,16 @@ static int ftdi_prepare_write_buffer(struct usb_serial_port *port, #define FTDI_RS_ERR_MASK (FTDI_RS_BI | FTDI_RS_PE | FTDI_RS_FE | FTDI_RS_OE) -static int ftdi_process_packet(struct tty_struct *tty, - struct usb_serial_port *port, struct ftdi_private *priv, - char *packet, int len) +static int ftdi_process_packet(struct usb_serial_port *port, + struct ftdi_private *priv, char *packet, int len) { int i; char status; char flag; char *ch; - dbg("%s - port %d", __func__, port->number); - if (len < 2) { - dbg("malformed packet"); + dev_dbg(&port->dev, "malformed packet\n"); return 0; } @@ -1847,8 +2001,26 @@ static int ftdi_process_packet(struct tty_struct *tty, are only processed once. */ status = packet[0] & FTDI_STATUS_B0_MASK; if (status != priv->prev_status) { - priv->diff_status |= status ^ priv->prev_status; - wake_up_interruptible(&priv->delta_msr_wait); + char diff_status = status ^ priv->prev_status; + + if (diff_status & FTDI_RS0_CTS) + port->icount.cts++; + if (diff_status & FTDI_RS0_DSR) + port->icount.dsr++; + if (diff_status & FTDI_RS0_RI) + port->icount.rng++; + if (diff_status & FTDI_RS0_RLSD) { + struct tty_struct *tty; + + port->icount.dcd++; + tty = tty_port_tty_get(&port->port); + if (tty) + usb_serial_handle_dcd_change(port, tty, + status & FTDI_RS0_RLSD); + tty_kref_put(tty); + } + + wake_up_interruptible(&port->port.delta_msr_wait); priv->prev_status = status; } @@ -1858,29 +2030,41 @@ static int ftdi_process_packet(struct tty_struct *tty, * over framing errors */ if (packet[1] & FTDI_RS_BI) { flag = TTY_BREAK; + port->icount.brk++; usb_serial_handle_break(port); } else if (packet[1] & FTDI_RS_PE) { flag = TTY_PARITY; + port->icount.parity++; } else if (packet[1] & FTDI_RS_FE) { flag = TTY_FRAME; + port->icount.frame++; } /* Overrun is special, not associated with a char */ - if (packet[1] & FTDI_RS_OE) - tty_insert_flip_char(tty, 0, TTY_OVERRUN); + if (packet[1] & FTDI_RS_OE) { + port->icount.overrun++; + tty_insert_flip_char(&port->port, 0, TTY_OVERRUN); + } } + /* save if the transmitter is empty or not */ + if (packet[1] & FTDI_RS_TEMT) + priv->transmit_empty = 1; + else + priv->transmit_empty = 0; + len -= 2; if (!len) return 0; /* status only */ + port->icount.rx += len; ch = packet + 2; if (port->port.console && port->sysrq) { for (i = 0; i < len; i++, ch++) { if (!usb_serial_handle_sysrq_char(port, *ch)) - tty_insert_flip_char(tty, *ch, flag); + tty_insert_flip_char(&port->port, *ch, flag); } } else { - tty_insert_flip_string_fixed_flag(tty, ch, flag, len); + tty_insert_flip_string_fixed_flag(&port->port, ch, flag, len); } return len; @@ -1889,25 +2073,19 @@ static int ftdi_process_packet(struct tty_struct *tty, static void ftdi_process_read_urb(struct urb *urb) { struct usb_serial_port *port = urb->context; - struct tty_struct *tty; struct ftdi_private *priv = usb_get_serial_port_data(port); char *data = (char *)urb->transfer_buffer; int i; int len; int count = 0; - tty = tty_port_tty_get(&port->port); - if (!tty) - return; - for (i = 0; i < urb->actual_length; i += priv->max_packet_size) { len = min_t(int, urb->actual_length - i, priv->max_packet_size); - count += ftdi_process_packet(tty, port, priv, &data[i], len); + count += ftdi_process_packet(port, priv, &data[i], len); } if (count) - tty_flip_buffer_push(tty); - tty_kref_put(tty); + tty_flip_buffer_push(&port->port); } static void ftdi_break_ctl(struct tty_struct *tty, int break_state) @@ -1931,15 +2109,29 @@ static void ftdi_break_ctl(struct tty_struct *tty, int break_state) FTDI_SIO_SET_DATA_REQUEST_TYPE, urb_value , priv->interface, NULL, 0, WDR_TIMEOUT) < 0) { - dev_err(&port->dev, "%s FAILED to enable/disable break state " - "(state was %d)\n", __func__, break_state); + dev_err(&port->dev, "%s FAILED to enable/disable break state (state was %d)\n", + __func__, break_state); } - dbg("%s break state is %d - urb is %d", __func__, - break_state, urb_value); + dev_dbg(&port->dev, "%s break state is %d - urb is %d\n", __func__, + break_state, urb_value); } +static bool ftdi_tx_empty(struct usb_serial_port *port) +{ + unsigned char buf[2]; + int ret; + + ret = ftdi_get_modem_status(port, buf); + if (ret == 2) { + if (!(buf[1] & FTDI_RS_TEMT)) + return false; + } + + return true; +} + /* old_termios contains the original termios settings and tty->termios contains * the new setting to be used * WARNING: set_termios calls this with old_termios in kernel space @@ -1948,8 +2140,9 @@ static void ftdi_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios) { struct usb_device *dev = port->serial->dev; + struct device *ddev = &port->dev; struct ftdi_private *priv = usb_get_serial_port_data(port); - struct ktermios *termios = tty->termios; + struct ktermios *termios = &tty->termios; unsigned int cflag = termios->c_cflag; __u16 urb_value; /* will hold the new flags */ @@ -1958,31 +2151,63 @@ static void ftdi_set_termios(struct tty_struct *tty, unsigned char vstop; unsigned char vstart; - dbg("%s", __func__); - /* Force baud rate if this device requires it, unless it is set to B0. */ if (priv->force_baud && ((termios->c_cflag & CBAUD) != B0)) { - dbg("%s: forcing baud rate for this device", __func__); + dev_dbg(ddev, "%s: forcing baud rate for this device\n", __func__); tty_encode_baud_rate(tty, priv->force_baud, priv->force_baud); } /* Force RTS-CTS if this device requires it. */ if (priv->force_rtscts) { - dbg("%s: forcing rtscts for this device", __func__); + dev_dbg(ddev, "%s: forcing rtscts for this device\n", __func__); termios->c_cflag |= CRTSCTS; } + /* + * All FTDI UART chips are limited to CS7/8. We shouldn't pretend to + * support CS5/6 and revert the CSIZE setting instead. + * + * CS5 however is used to control some smartcard readers which abuse + * this limitation to switch modes. Original FTDI chips fall back to + * eight data bits. + * + * TODO: Implement a quirk to only allow this with mentioned + * readers. One I know of (Argolis Smartreader V1) + * returns "USB smartcard server" as iInterface string. + * The vendor didn't bother with a custom VID/PID of + * course. + */ + if (C_CSIZE(tty) == CS6) { + dev_warn(ddev, "requested CSIZE setting not supported\n"); + + termios->c_cflag &= ~CSIZE; + if (old_termios) + termios->c_cflag |= old_termios->c_cflag & CSIZE; + else + termios->c_cflag |= CS8; + } + cflag = termios->c_cflag; - /* FIXME -For this cut I don't care if the line is really changing or - not - so just do the change regardless - should be able to - compare old_termios and tty->termios */ + if (!old_termios) + goto no_skip; + + if (old_termios->c_cflag == termios->c_cflag + && old_termios->c_ispeed == termios->c_ispeed + && old_termios->c_ospeed == termios->c_ospeed) + goto no_c_cflag_changes; + /* NOTE These routines can get interrupted by ftdi_sio_read_bulk_callback - need to examine what this means - don't see any problems yet */ + if ((old_termios->c_cflag & (CSIZE|PARODD|PARENB|CMSPAR|CSTOPB)) == + (termios->c_cflag & (CSIZE|PARODD|PARENB|CMSPAR|CSTOPB))) + goto no_data_parity_stop_changes; + +no_skip: /* Set number of data bits, parity, stop bits */ urb_value = 0; @@ -2000,13 +2225,19 @@ static void ftdi_set_termios(struct tty_struct *tty, } else { urb_value |= FTDI_SIO_SET_DATA_PARITY_NONE; } - if (cflag & CSIZE) { - switch (cflag & CSIZE) { - case CS7: urb_value |= 7; dbg("Setting CS7"); break; - case CS8: urb_value |= 8; dbg("Setting CS8"); break; - default: - dev_err(&port->dev, "CSIZE was set but not CS7-CS8\n"); - } + switch (cflag & CSIZE) { + case CS5: + dev_dbg(ddev, "Setting CS5 quirk\n"); + break; + case CS7: + urb_value |= 7; + dev_dbg(ddev, "Setting CS7\n"); + break; + default: + case CS8: + urb_value |= 8; + dev_dbg(ddev, "Setting CS8\n"); + break; } /* This is needed by the break command since it uses the same command @@ -2018,11 +2249,12 @@ static void ftdi_set_termios(struct tty_struct *tty, FTDI_SIO_SET_DATA_REQUEST_TYPE, urb_value , priv->interface, NULL, 0, WDR_SHORT_TIMEOUT) < 0) { - dev_err(&port->dev, "%s FAILED to set " - "databits/stopbits/parity\n", __func__); + dev_err(ddev, "%s FAILED to set databits/stopbits/parity\n", + __func__); } /* Now do the baudrate */ +no_data_parity_stop_changes: if ((cflag & CBAUD) == B0) { /* Disable flow control */ if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), @@ -2030,8 +2262,7 @@ static void ftdi_set_termios(struct tty_struct *tty, FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, 0, priv->interface, NULL, 0, WDR_TIMEOUT) < 0) { - dev_err(&port->dev, - "%s error from disable flowcontrol urb\n", + dev_err(ddev, "%s error from disable flowcontrol urb\n", __func__); } /* Drop RTS and DTR */ @@ -2040,28 +2271,26 @@ static void ftdi_set_termios(struct tty_struct *tty, /* set the baudrate determined before */ mutex_lock(&priv->cfg_lock); if (change_speed(tty, port)) - dev_err(&port->dev, "%s urb failed to set baudrate\n", - __func__); + dev_err(ddev, "%s urb failed to set baudrate\n", __func__); mutex_unlock(&priv->cfg_lock); /* Ensure RTS and DTR are raised when baudrate changed from 0 */ - if (!old_termios || (old_termios->c_cflag & CBAUD) == B0) + if (old_termios && (old_termios->c_cflag & CBAUD) == B0) set_mctrl(port, TIOCM_DTR | TIOCM_RTS); } /* Set flow control */ /* Note device also supports DTR/CD (ugh) and Xon/Xoff in hardware */ +no_c_cflag_changes: if (cflag & CRTSCTS) { - dbg("%s Setting to CRTSCTS flow control", __func__); + dev_dbg(ddev, "%s Setting to CRTSCTS flow control\n", __func__); if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), FTDI_SIO_SET_FLOW_CTRL_REQUEST, FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, 0 , (FTDI_SIO_RTS_CTS_HS | priv->interface), NULL, 0, WDR_TIMEOUT) < 0) { - dev_err(&port->dev, - "urb failed to set to rts/cts flow control\n"); + dev_err(ddev, "urb failed to set to rts/cts flow control\n"); } - } else { /* * Xon/Xoff code @@ -2071,8 +2300,8 @@ static void ftdi_set_termios(struct tty_struct *tty, * code is executed. */ if (iflag & IXOFF) { - dbg("%s request to enable xonxoff iflag=%04x", - __func__, iflag); + dev_dbg(ddev, "%s request to enable xonxoff iflag=%04x\n", + __func__, iflag); /* Try to enable the XON/XOFF on the ftdi_sio * Set the vstart and vstop -- could have been done up * above where a lot of other dereferencing is done but @@ -2097,31 +2326,33 @@ static void ftdi_set_termios(struct tty_struct *tty, /* else clause to only run if cflag ! CRTSCTS and iflag * ! XOFF. CHECKME Assuming XON/XOFF handled by tty * stack - not by device */ - dbg("%s Turning off hardware flow control", __func__); + dev_dbg(ddev, "%s Turning off hardware flow control\n", __func__); if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), FTDI_SIO_SET_FLOW_CTRL_REQUEST, FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, 0, priv->interface, NULL, 0, WDR_TIMEOUT) < 0) { - dev_err(&port->dev, - "urb failed to clear flow control\n"); + dev_err(ddev, "urb failed to clear flow control\n"); } } - } } -static int ftdi_tiocmget(struct tty_struct *tty, struct file *file) +/* + * Get modem-control status. + * + * Returns the number of status bytes retrieved (device dependant), or + * negative error code. + */ +static int ftdi_get_modem_status(struct usb_serial_port *port, + unsigned char status[2]) { - struct usb_serial_port *port = tty->driver_data; struct ftdi_private *priv = usb_get_serial_port_data(port); unsigned char *buf; int len; int ret; - dbg("%s TIOCMGET", __func__); - buf = kmalloc(2, GFP_KERNEL); if (!buf) return -ENOMEM; @@ -2139,6 +2370,8 @@ static int ftdi_tiocmget(struct tty_struct *tty, struct file *file) case FT232RL: case FT2232H: case FT4232H: + case FT232H: + case FTX: len = 2; break; default: @@ -2152,34 +2385,58 @@ static int ftdi_tiocmget(struct tty_struct *tty, struct file *file) FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE, 0, priv->interface, buf, len, WDR_TIMEOUT); - if (ret < 0) + if (ret < 0) { + dev_err(&port->dev, "failed to get modem status: %d\n", ret); + ret = usb_translate_errors(ret); goto out; + } - ret = (buf[0] & FTDI_SIO_DSR_MASK ? TIOCM_DSR : 0) | - (buf[0] & FTDI_SIO_CTS_MASK ? TIOCM_CTS : 0) | - (buf[0] & FTDI_SIO_RI_MASK ? TIOCM_RI : 0) | - (buf[0] & FTDI_SIO_RLSD_MASK ? TIOCM_CD : 0) | - priv->last_dtr_rts; + status[0] = buf[0]; + if (ret > 1) + status[1] = buf[1]; + else + status[1] = 0; + + dev_dbg(&port->dev, "%s - 0x%02x%02x\n", __func__, status[0], + status[1]); out: kfree(buf); + + return ret; +} + +static int ftdi_tiocmget(struct tty_struct *tty) +{ + struct usb_serial_port *port = tty->driver_data; + struct ftdi_private *priv = usb_get_serial_port_data(port); + unsigned char buf[2]; + int ret; + + ret = ftdi_get_modem_status(port, buf); + if (ret < 0) + return ret; + + ret = (buf[0] & FTDI_SIO_DSR_MASK ? TIOCM_DSR : 0) | + (buf[0] & FTDI_SIO_CTS_MASK ? TIOCM_CTS : 0) | + (buf[0] & FTDI_SIO_RI_MASK ? TIOCM_RI : 0) | + (buf[0] & FTDI_SIO_RLSD_MASK ? TIOCM_CD : 0) | + priv->last_dtr_rts; + return ret; } -static int ftdi_tiocmset(struct tty_struct *tty, struct file *file, +static int ftdi_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) { struct usb_serial_port *port = tty->driver_data; - dbg("%s TIOCMSET", __func__); + return update_mctrl(port, set, clear); } -static int ftdi_ioctl(struct tty_struct *tty, struct file *file, +static int ftdi_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { struct usb_serial_port *port = tty->driver_data; - struct ftdi_private *priv = usb_get_serial_port_data(port); - - dbg("%s cmd 0x%04x", __func__, cmd); /* Based on code from acm.c and others */ switch (cmd) { @@ -2191,110 +2448,21 @@ static int ftdi_ioctl(struct tty_struct *tty, struct file *file, case TIOCSSERIAL: /* sets serial port data */ return set_serial_info(tty, port, (struct serial_struct __user *) arg); - - /* - * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change - * - mask passed in arg for lines of interest - * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) - * Caller should use TIOCGICOUNT to see which one it was. - * (except that the driver doesn't support it !) - * - * This code is borrowed from linux/drivers/char/serial.c - */ - case TIOCMIWAIT: - while (priv != NULL) { - interruptible_sleep_on(&priv->delta_msr_wait); - /* see if a signal did it */ - if (signal_pending(current)) - return -ERESTARTSYS; - else { - char diff = priv->diff_status; - - if (diff == 0) - return -EIO; /* no change => error */ - - /* Consume all events */ - priv->diff_status = 0; - - /* Return 0 if caller wanted to know about - these bits */ - if (((arg & TIOCM_RNG) && (diff & FTDI_RS0_RI)) || - ((arg & TIOCM_DSR) && (diff & FTDI_RS0_DSR)) || - ((arg & TIOCM_CD) && (diff & FTDI_RS0_RLSD)) || - ((arg & TIOCM_CTS) && (diff & FTDI_RS0_CTS))) { - return 0; - } - /* - * Otherwise caller can't care less about what - * happened,and so we continue to wait for more - * events. - */ - } - } - return 0; + case TIOCSERGETLSR: + return get_lsr_info(port, (struct serial_struct __user *)arg); + break; default: break; } - /* This is not necessarily an error - turns out the higher layers - * will do some ioctls themselves (see comment above) - */ - dbg("%s arg not supported - it was 0x%04x - check /usr/include/asm/ioctls.h", __func__, cmd); - return -ENOIOCTLCMD; -} -static int __init ftdi_init(void) -{ - int retval; - - dbg("%s", __func__); - if (vendor > 0 && product > 0) { - /* Add user specified VID/PID to reserved element of table. */ - int i; - for (i = 0; id_table_combined[i].idVendor; i++) - ; - id_table_combined[i].match_flags = USB_DEVICE_ID_MATCH_DEVICE; - id_table_combined[i].idVendor = vendor; - id_table_combined[i].idProduct = product; - } - retval = usb_serial_register(&ftdi_sio_device); - if (retval) - goto failed_sio_register; - retval = usb_register(&ftdi_driver); - if (retval) - goto failed_usb_register; - - printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" - DRIVER_DESC "\n"); - return 0; -failed_usb_register: - usb_serial_deregister(&ftdi_sio_device); -failed_sio_register: - return retval; -} - -static void __exit ftdi_exit(void) -{ - dbg("%s", __func__); - - usb_deregister(&ftdi_driver); - usb_serial_deregister(&ftdi_sio_device); + return -ENOIOCTLCMD; } - -module_init(ftdi_init); -module_exit(ftdi_exit); +module_usb_serial_driver(serial_drivers, id_table_combined); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); -module_param(vendor, ushort, 0); -MODULE_PARM_DESC(vendor, "User specified vendor ID (default=" - __MODULE_STRING(FTDI_VID)")"); -module_param(product, ushort, 0); -MODULE_PARM_DESC(product, "User specified product ID"); - module_param(ndi_latency_timer, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(ndi_latency_timer, "NDI device latency timer override"); diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h index 213fe3d6128..ed58c6fa8db 100644 --- a/drivers/usb/serial/ftdi_sio.h +++ b/drivers/usb/serial/ftdi_sio.h @@ -156,7 +156,9 @@ enum ftdi_chip_type { FT2232C = 4, FT232RL = 5, FT2232H = 6, - FT4232H = 7 + FT4232H = 7, + FT232H = 8, + FTX = 9, }; enum ftdi_sio_baudrate { diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 263f6255119..c4777bc6aee 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -2,7 +2,7 @@ * vendor/product IDs (VID/PID) of devices using FTDI USB serial converters. * Please keep numerically sorted within individual areas, thanks! * - * Philipp Gühring - pg@futureware.at - added the Device ID of the USB relais + * Philipp Gühring - pg@futureware.at - added the Device ID of the USB relais * from Rudolf Gugler * */ @@ -22,12 +22,16 @@ #define FTDI_8U232AM_ALT_PID 0x6006 /* FTDI's alternate PID for above */ #define FTDI_8U2232C_PID 0x6010 /* Dual channel device */ #define FTDI_4232H_PID 0x6011 /* Quad channel hi-speed device */ +#define FTDI_232H_PID 0x6014 /* Single channel hi-speed device */ +#define FTDI_FTX_PID 0x6015 /* FT-X series (FT201X, FT230X, FT231X, etc) */ #define FTDI_SIO_PID 0x8372 /* Product Id SIO application of 8U100AX */ #define FTDI_232RL_PID 0xFBFA /* Product ID for FT232RL */ /*** third-party PIDs (using FTDI_VID) ***/ +#define FTDI_LUMEL_PD12_PID 0x6002 + /* * Marvell OpenRD Base, Client * http://www.open-rd.org @@ -38,7 +42,15 @@ /* www.candapter.com Ewert Energy Systems CANdapter device */ #define FTDI_CANDAPTER_PID 0x9F80 /* Product Id */ +/* + * Texas Instruments XDS100v2 JTAG / BeagleBone A3 + * http://processors.wiki.ti.com/index.php/XDS100 + * http://beagleboard.org/bone + */ +#define TI_XDS100V2_PID 0xa6d0 + #define FTDI_NXTCAM_PID 0xABB8 /* NXTCam for Mindstorms NXT */ +#define FTDI_EV3CON_PID 0xABB9 /* Mindstorms EV3 Console Adapter */ /* US Interface Navigator (http://www.usinterface.com/) */ #define FTDI_USINT_CAT_PID 0xb810 /* Navigator CAT and 2nd PTT lines */ @@ -53,6 +65,7 @@ /* FTDI 2332C Dual channel device, side A=245 FIFO (JTAG), Side B=RS232 UART */ #define LMI_LM3S_DEVEL_BOARD_PID 0xbcd8 #define LMI_LM3S_EVAL_BOARD_PID 0xbcd9 +#define LMI_LM3S_ICDI_BOARD_PID 0xbcda #define FTDI_TURTELIZER_PID 0xBDC8 /* JTAG/RS-232 adapter by egnite GmbH */ @@ -62,6 +75,10 @@ #define FTDI_OPENDCC_THROTTLE_PID 0xBFDA #define FTDI_OPENDCC_GATEWAY_PID 0xBFDB #define FTDI_OPENDCC_GBM_PID 0xBFDC +#define FTDI_OPENDCC_GBM_BOOST_PID 0xBFDD + +/* NZR SEM 16+ USB (http://www.nzr.de) */ +#define FTDI_NZR_SEM_USB_PID 0xC1E0 /* NZR SEM-LOG16+ */ /* * RR-CirKits LocoBuffer USB (http://www.rr-cirkits.com) @@ -76,7 +93,7 @@ */ #define FTDI_ASK_RDR400_PID 0xC991 /* ASK RDR 400 series card reader */ -/* www.starting-point-systems.com µChameleon device */ +/* www.starting-point-systems.com µChameleon device */ #define FTDI_MICRO_CHAMELEON_PID 0xCAA0 /* Product Id */ /* @@ -88,6 +105,8 @@ #define FTDI_TACTRIX_OPENPORT_13S_PID 0xCC49 /* OpenPort 1.3 Subaru */ #define FTDI_TACTRIX_OPENPORT_13U_PID 0xCC4A /* OpenPort 1.3 Universal */ +#define FTDI_DISTORTEC_JTAG_LOCK_PICK_PID 0xCFF8 + /* SCS HF Radio Modems PID's (http://www.scs-ptc.com) */ /* the VID is the standard ftdi vid (FTDI_VID) */ #define FTDI_SCS_DEVICE_0_PID 0xD010 /* SCS PTC-IIusb */ @@ -110,10 +129,14 @@ /* Propox devices */ #define FTDI_PROPOX_JTAGCABLEII_PID 0xD738 +#define FTDI_PROPOX_ISPCABLEIII_PID 0xD739 /* Lenz LI-USB Computer Interface. */ #define FTDI_LENZ_LIUSB_PID 0xD780 +/* Vardaan Enterprises Serial Interface VEUSB422R3 */ +#define FTDI_VARDAAN_PID 0xF070 + /* * Xsens Technologies BV products (http://www.xsens.com). */ @@ -126,6 +149,11 @@ #define XSENS_CONVERTER_6_PID 0xD38E #define XSENS_CONVERTER_7_PID 0xD38F +/** + * Zolix (www.zolix.com.cb) product ids + */ +#define FTDI_OMNI1509 0xD491 /* Omni1509 embedded USB-serial */ + /* * NDI (www.ndigital.com) product ids */ @@ -183,7 +211,7 @@ /* * ELV USB devices submitted by Christian Abt of ELV (www.elv.de). - * All of these devices use FTDI's vendor ID (0x0403). + * Almost all of these devices use FTDI's vendor ID (0x0403). * Further IDs taken from ELV Windows .inf file. * * The previously included PID for the UO 100 module was incorrect. @@ -191,6 +219,8 @@ * * Armin Laeuger originally sent the PID for the UM 100 module. */ +#define FTDI_ELV_VID 0x1B1F /* ELV AG */ +#define FTDI_ELV_WS300_PID 0xC006 /* eQ3 WS 300 PC II */ #define FTDI_ELV_USR_PID 0xE000 /* ELV Universal-Sound-Recorder */ #define FTDI_ELV_MSM1_PID 0xE001 /* ELV Mini-Sound-Modul */ #define FTDI_ELV_KL100_PID 0xE002 /* ELV Kfz-Leistungsmesser KL 100 */ @@ -285,7 +315,7 @@ /* * Teratronik product ids. - * Submitted by O. Wölfelschneider. + * Submitted by O. Wƶlfelschneider. */ #define FTDI_TERATRONIK_VCP_PID 0xEC88 /* Teratronik device (preferring VCP driver on windows) */ #define FTDI_TERATRONIK_D2XX_PID 0xEC89 /* Teratronik device (preferring D2XX driver on windows) */ @@ -297,6 +327,8 @@ * Hameg HO820 and HO870 interface (using VID 0x0403) */ #define HAMEG_HO820_PID 0xed74 +#define HAMEG_HO730_PID 0xed73 +#define HAMEG_HO720_PID 0xed72 #define HAMEG_HO870_PID 0xed71 /* @@ -332,6 +364,12 @@ /* Sprog II (Andrew Crosland's SprogII DCC interface) */ #define FTDI_SPROG_II 0xF0C8 +/* + * Two of the Tagsys RFID Readers + */ +#define FTDI_TAGSYS_LP101_PID 0xF0E9 /* Tagsys L-P101 RFID*/ +#define FTDI_TAGSYS_P200X_PID 0xF0EE /* Tagsys Medio P200x RFID*/ + /* an infrared receiver for user access control with IR tags */ #define FTDI_PIEGROUP_PID 0xF208 /* Product Id */ @@ -346,6 +384,7 @@ */ #define FTDI_4N_GALAXY_DE_1_PID 0xF3C0 #define FTDI_4N_GALAXY_DE_2_PID 0xF3C1 +#define FTDI_4N_GALAXY_DE_3_PID 0xF3C2 /* * Linx Technologies product ids @@ -413,9 +452,11 @@ #define PROTEGO_SPECIAL_4 0xFC73 /* special/unknown device */ /* - * DSS-20 Sync Station for Sony Ericsson P800 + * Sony Ericsson product ids */ -#define FTDI_DSS20_PID 0xFC82 +#define FTDI_DSS20_PID 0xFC82 /* DSS-20 Sync Station for Sony Ericsson P800 */ +#define FTDI_URBAN_0_PID 0xFC8A /* Sony Ericsson Urban, uart #0 */ +#define FTDI_URBAN_1_PID 0xFC8B /* Sony Ericsson Urban, uart #1 */ /* www.irtrans.de device */ #define FTDI_IRTRANS_PID 0xFC60 /* Product Id */ @@ -486,6 +527,21 @@ /* www.canusb.com Lawicel CANUSB device (FTDI_VID) */ #define FTDI_CANUSB_PID 0xFFA8 /* Product Id */ +/* + * TavIR AVR product ids (FTDI_VID) + */ +#define FTDI_TAVIR_STK500_PID 0xFA33 /* STK500 AVR programmer */ + +/* + * TIAO product ids (FTDI_VID) + * http://www.tiaowiki.com/w/Main_Page + */ +#define FTDI_TIAO_UMPA_PID 0x8a98 /* TIAO/DIYGADGET USB Multi-Protocol Adapter */ + +/* + * NovaTech product ids (FTDI_VID) + */ +#define FTDI_NT_ORIONLXM_PID 0x7c90 /* OrionLXm Substation Automation Platform */ /********************************/ @@ -509,12 +565,37 @@ #define ADI_GNICEPLUS_PID 0xF001 /* + * Microchip Technology, Inc. + * + * MICROCHIP_VID (0x04D8) and MICROCHIP_USB_BOARD_PID (0x000A) are + * used by single function CDC ACM class based firmware demo + * applications. The VID/PID has also been used in firmware + * emulating FTDI serial chips by: + * Hornby Elite - Digital Command Control Console + * http://www.hornby.com/hornby-dcc/controllers/ + */ +#define MICROCHIP_VID 0x04D8 +#define MICROCHIP_USB_BOARD_PID 0x000A /* CDC RS-232 Emulation Demo */ + +/* * RATOC REX-USB60F */ #define RATOC_VENDOR_ID 0x0584 #define RATOC_PRODUCT_ID_USB60F 0xb020 /* + * Infineon Technologies + */ +#define INFINEON_VID 0x058b +#define INFINEON_TRIBOARD_PID 0x0028 /* DAS JTAG TriBoard TC1798 V1.0 */ + +/* + * Acton Research Corp. + */ +#define ACTON_VID 0x0647 /* Vendor ID */ +#define ACTON_SPECTRAPRO_PID 0x0100 + +/* * Contec products (http://www.contec.com) * Submitted by Daniel Sangorrin */ @@ -522,6 +603,13 @@ #define CONTEC_COM1USBH_PID 0x8311 /* COM-1(USB)H */ /* + * Mitsubishi Electric Corp. (http://www.meau.com) + * Submitted by Konstantin Holoborodko + */ +#define MITSUBISHI_VID 0x06D3 +#define MITSUBISHI_FXUSB_PID 0x0284 /* USB/RS422 converters: FX-USB-AW/-BD */ + +/* * Definitions for B&B Electronics products. */ #define BANDB_VID 0x0856 /* B&B Electronics Vendor ID */ @@ -563,14 +651,27 @@ /* Note: OCT US101 is also rebadged as Dick Smith Electronics (NZ) XH6381 */ /* Also rebadged as Dick Smith Electronics (Aus) XH6451 */ /* Also rebadged as SIIG Inc. model US2308 hardware version 1 */ +#define OCT_DK201_PID 0x0103 /* OCT DK201 USB docking station */ #define OCT_US101_PID 0x0421 /* OCT US101 USB to RS-232 */ /* - * Icom ID-1 digital transceiver + * Definitions for Icom Inc. devices */ - -#define ICOM_ID1_VID 0x0C26 -#define ICOM_ID1_PID 0x0004 +#define ICOM_VID 0x0C26 /* Icom vendor ID */ +/* Note: ID-1 is a communications tranceiver for HAM-radio operators */ +#define ICOM_ID_1_PID 0x0004 /* ID-1 USB to RS-232 */ +/* Note: OPC is an Optional cable to connect an Icom Tranceiver */ +#define ICOM_OPC_U_UC_PID 0x0018 /* OPC-478UC, OPC-1122U cloning cable */ +/* Note: ID-RP* devices are Icom Repeater Devices for HAM-radio */ +#define ICOM_ID_RP2C1_PID 0x0009 /* ID-RP2C Asset 1 to RS-232 */ +#define ICOM_ID_RP2C2_PID 0x000A /* ID-RP2C Asset 2 to RS-232 */ +#define ICOM_ID_RP2D_PID 0x000B /* ID-RP2D configuration port*/ +#define ICOM_ID_RP2VT_PID 0x000C /* ID-RP2V Transmit config port */ +#define ICOM_ID_RP2VR_PID 0x000D /* ID-RP2V Receive config port */ +#define ICOM_ID_RP4KVT_PID 0x0010 /* ID-RP4000V Transmit config port */ +#define ICOM_ID_RP4KVR_PID 0x0011 /* ID-RP4000V Receive config port */ +#define ICOM_ID_RP2KVT_PID 0x0012 /* ID-RP2000V Transmit config port */ +#define ICOM_ID_RP2KVR_PID 0x0013 /* ID-RP2000V Receive config port */ /* * GN Otometrics (http://www.otometrics.com) @@ -632,6 +733,10 @@ #define SEALEVEL_2803_6_PID 0X2863 /* SeaLINK+8 (2803) Port 6 */ #define SEALEVEL_2803_7_PID 0X2873 /* SeaLINK+8 (2803) Port 7 */ #define SEALEVEL_2803_8_PID 0X2883 /* SeaLINK+8 (2803) Port 8 */ +#define SEALEVEL_2803R_1_PID 0Xa02a /* SeaLINK+8 (2803-ROHS) Port 1+2 */ +#define SEALEVEL_2803R_2_PID 0Xa02b /* SeaLINK+8 (2803-ROHS) Port 3+4 */ +#define SEALEVEL_2803R_3_PID 0Xa02c /* SeaLINK+8 (2803-ROHS) Port 5+6 */ +#define SEALEVEL_2803R_4_PID 0Xa02d /* SeaLINK+8 (2803-ROHS) Port 7+8 */ /* * JETI SPECTROMETER SPECBOS 1201 @@ -680,6 +785,14 @@ #define TTI_VID 0x103E /* Vendor Id */ #define TTI_QL355P_PID 0x03E8 /* TTi QL355P power supply */ +/* + * Newport Cooperation (www.newport.com) + */ +#define NEWPORT_VID 0x104D +#define NEWPORT_AGILIS_PID 0x3000 +#define NEWPORT_CONEX_CC_PID 0x3002 +#define NEWPORT_CONEX_AGP_PID 0x3006 + /* Interbiometrics USB I/O Board */ /* Developed for Interbiometrics by Rudolf Gugler */ #define INTERBIOMETRICS_VID 0x1209 @@ -691,7 +804,8 @@ * Submitted by Colin Leroy */ #define TESTO_VID 0x128D -#define TESTO_USB_INTERFACE_PID 0x0001 +#define TESTO_1_PID 0x0001 +#define TESTO_3_PID 0x0003 /* * Mobility Electronics products. @@ -709,6 +823,7 @@ /* Olimex */ #define OLIMEX_VID 0x15BA #define OLIMEX_ARM_USB_OCD_PID 0x0003 +#define OLIMEX_ARM_USB_OCD_H_PID 0x002b /* * Telldus Technologies @@ -719,8 +834,68 @@ /* * RT Systems programming cables for various ham radios */ -#define RTSYSTEMS_VID 0x2100 /* Vendor ID */ -#define RTSYSTEMS_SERIAL_VX7_PID 0x9e52 /* Serial converter for VX-7 Radios using FT232RL */ +#define RTSYSTEMS_VID 0x2100 /* Vendor ID */ +#define RTSYSTEMS_USB_S03_PID 0x9001 /* RTS-03 USB to Serial Adapter */ +#define RTSYSTEMS_USB_59_PID 0x9e50 /* USB-59 USB to 8 pin plug */ +#define RTSYSTEMS_USB_57A_PID 0x9e51 /* USB-57A USB to 4pin 3.5mm plug */ +#define RTSYSTEMS_USB_57B_PID 0x9e52 /* USB-57B USB to extended 4pin 3.5mm plug */ +#define RTSYSTEMS_USB_29A_PID 0x9e53 /* USB-29A USB to 3.5mm stereo plug */ +#define RTSYSTEMS_USB_29B_PID 0x9e54 /* USB-29B USB to 6 pin mini din */ +#define RTSYSTEMS_USB_29F_PID 0x9e55 /* USB-29F USB to 6 pin modular plug */ +#define RTSYSTEMS_USB_62B_PID 0x9e56 /* USB-62B USB to 8 pin mini din plug*/ +#define RTSYSTEMS_USB_S01_PID 0x9e57 /* USB-RTS01 USB to 3.5 mm stereo plug*/ +#define RTSYSTEMS_USB_63_PID 0x9e58 /* USB-63 USB to 9 pin female*/ +#define RTSYSTEMS_USB_29C_PID 0x9e59 /* USB-29C USB to 4 pin modular plug*/ +#define RTSYSTEMS_USB_81B_PID 0x9e5A /* USB-81 USB to 8 pin mini din plug*/ +#define RTSYSTEMS_USB_82B_PID 0x9e5B /* USB-82 USB to 2.5 mm stereo plug*/ +#define RTSYSTEMS_USB_K5D_PID 0x9e5C /* USB-K5D USB to 8 pin modular plug*/ +#define RTSYSTEMS_USB_K4Y_PID 0x9e5D /* USB-K4Y USB to 2.5/3.5 mm plugs*/ +#define RTSYSTEMS_USB_K5G_PID 0x9e5E /* USB-K5G USB to 8 pin modular plug*/ +#define RTSYSTEMS_USB_S05_PID 0x9e5F /* USB-RTS05 USB to 2.5 mm stereo plug*/ +#define RTSYSTEMS_USB_60_PID 0x9e60 /* USB-60 USB to 6 pin din*/ +#define RTSYSTEMS_USB_61_PID 0x9e61 /* USB-61 USB to 6 pin mini din*/ +#define RTSYSTEMS_USB_62_PID 0x9e62 /* USB-62 USB to 8 pin mini din*/ +#define RTSYSTEMS_USB_63B_PID 0x9e63 /* USB-63 USB to 9 pin female*/ +#define RTSYSTEMS_USB_64_PID 0x9e64 /* USB-64 USB to 9 pin male*/ +#define RTSYSTEMS_USB_65_PID 0x9e65 /* USB-65 USB to 9 pin female null modem*/ +#define RTSYSTEMS_USB_92_PID 0x9e66 /* USB-92 USB to 12 pin plug*/ +#define RTSYSTEMS_USB_92D_PID 0x9e67 /* USB-92D USB to 12 pin plug data*/ +#define RTSYSTEMS_USB_W5R_PID 0x9e68 /* USB-W5R USB to 8 pin modular plug*/ +#define RTSYSTEMS_USB_A5R_PID 0x9e69 /* USB-A5R USB to 8 pin modular plug*/ +#define RTSYSTEMS_USB_PW1_PID 0x9e6A /* USB-PW1 USB to 8 pin modular plug*/ + +/* + * Physik Instrumente + * http://www.physikinstrumente.com/en/products/ + */ +/* These two devices use the VID of FTDI */ +#define PI_C865_PID 0xe0a0 /* PI C-865 Piezomotor Controller */ +#define PI_C857_PID 0xe0a1 /* PI Encoder Trigger Box */ + +#define PI_VID 0x1a72 /* Vendor ID */ +#define PI_C866_PID 0x1000 /* PI C-866 Piezomotor Controller */ +#define PI_C663_PID 0x1001 /* PI C-663 Mercury-Step */ +#define PI_C725_PID 0x1002 /* PI C-725 Piezomotor Controller */ +#define PI_E517_PID 0x1005 /* PI E-517 Digital Piezo Controller Operation Module */ +#define PI_C863_PID 0x1007 /* PI C-863 */ +#define PI_E861_PID 0x1008 /* PI E-861 Piezomotor Controller */ +#define PI_C867_PID 0x1009 /* PI C-867 Piezomotor Controller */ +#define PI_E609_PID 0x100D /* PI E-609 Digital Piezo Controller */ +#define PI_E709_PID 0x100E /* PI E-709 Digital Piezo Controller */ +#define PI_100F_PID 0x100F /* PI Digital Piezo Controller */ +#define PI_1011_PID 0x1011 /* PI Digital Piezo Controller */ +#define PI_1012_PID 0x1012 /* PI Motion Controller */ +#define PI_1013_PID 0x1013 /* PI Motion Controller */ +#define PI_1014_PID 0x1014 /* PI Device */ +#define PI_1015_PID 0x1015 /* PI Device */ +#define PI_1016_PID 0x1016 /* PI Digital Servo Module */ + +/* + * Kondo Kagaku Co.Ltd. + * http://www.kondo-robot.com/EN + */ +#define KONDO_VID 0x165c +#define KONDO_USB_SERIAL_PID 0x0002 /* * Bayer Ascensia Contour blood glucose meter USB-converter cable. @@ -1018,6 +1193,13 @@ #define WHT_PID 0x0004 /* Wireless Handheld Terminal */ /* + * STMicroelectonics + */ +#define ST_VID 0x0483 +#define ST_STMCLT_2232_PID 0x3746 +#define ST_STMCLT_4232_PID 0x3747 + +/* * Papouch products (http://www.papouch.com/) * Submitted by Folkert van Heusden */ @@ -1077,6 +1259,11 @@ #define MJSG_HD_RADIO_PID 0x937C /* + * D.O.Tec products (http://www.directout.eu) + */ +#define FTDI_DOTEC_PID 0x9868 + +/* * Xverve Signalyzer tools (http://www.signalyzer.com/) */ #define XVERVE_SIGNALYZER_ST_PID 0xBCA0 @@ -1107,3 +1294,84 @@ #define QIHARDWARE_VID 0x20B7 #define MILKYMISTONE_JTAGSERIAL_PID 0x0713 +/* + * CTI GmbH RS485 Converter http://www.cti-lean.com/ + */ +/* USB-485-Mini*/ +#define FTDI_CTI_MINI_PID 0xF608 +/* USB-Nano-485*/ +#define FTDI_CTI_NANO_PID 0xF60B + +/* + * ZeitControl cardsystems GmbH rfid-readers http://zeitconrol.de + */ +/* TagTracer MIFARE*/ +#define FTDI_ZEITCONTROL_TAGTRACE_MIFARE_PID 0xF7C0 + +/* + * Rainforest Automation + */ +/* ZigBee controller */ +#define FTDI_RF_R106 0x8A28 + +/* + * Product: HCP HIT GPRS modem + * Manufacturer: HCP d.o.o. + * ATI command output: Cinterion MC55i + */ +#define FTDI_CINTERION_MC55I_PID 0xA951 + +/* + * Product: Comet Caller ID decoder + * Manufacturer: Crucible Technologies + */ +#define FTDI_CT_COMET_PID 0x8e08 + +/* + * Product: Z3X Box + * Manufacturer: Smart GSM Team + */ +#define FTDI_Z3X_PID 0x0011 + +/* + * Product: Cressi PC Interface + * Manufacturer: Cressi + */ +#define FTDI_CRESSI_PID 0x87d0 + +/* + * Brainboxes devices + */ +#define BRAINBOXES_VID 0x05d1 +#define BRAINBOXES_VX_001_PID 0x1001 /* VX-001 ExpressCard 1 Port RS232 */ +#define BRAINBOXES_VX_012_PID 0x1002 /* VX-012 ExpressCard 2 Port RS232 */ +#define BRAINBOXES_VX_023_PID 0x1003 /* VX-023 ExpressCard 1 Port RS422/485 */ +#define BRAINBOXES_VX_034_PID 0x1004 /* VX-034 ExpressCard 2 Port RS422/485 */ +#define BRAINBOXES_US_101_PID 0x1011 /* US-101 1xRS232 */ +#define BRAINBOXES_US_324_PID 0x1013 /* US-324 1xRS422/485 1Mbaud */ +#define BRAINBOXES_US_606_1_PID 0x2001 /* US-606 6 Port RS232 Serial Port 1 and 2 */ +#define BRAINBOXES_US_606_2_PID 0x2002 /* US-606 6 Port RS232 Serial Port 3 and 4 */ +#define BRAINBOXES_US_606_3_PID 0x2003 /* US-606 6 Port RS232 Serial Port 4 and 6 */ +#define BRAINBOXES_US_701_1_PID 0x2011 /* US-701 4xRS232 1Mbaud Port 1 and 2 */ +#define BRAINBOXES_US_701_2_PID 0x2012 /* US-701 4xRS422 1Mbaud Port 3 and 4 */ +#define BRAINBOXES_US_279_1_PID 0x2021 /* US-279 8xRS422 1Mbaud Port 1 and 2 */ +#define BRAINBOXES_US_279_2_PID 0x2022 /* US-279 8xRS422 1Mbaud Port 3 and 4 */ +#define BRAINBOXES_US_279_3_PID 0x2023 /* US-279 8xRS422 1Mbaud Port 5 and 6 */ +#define BRAINBOXES_US_279_4_PID 0x2024 /* US-279 8xRS422 1Mbaud Port 7 and 8 */ +#define BRAINBOXES_US_346_1_PID 0x3011 /* US-346 4xRS422/485 1Mbaud Port 1 and 2 */ +#define BRAINBOXES_US_346_2_PID 0x3012 /* US-346 4xRS422/485 1Mbaud Port 3 and 4 */ +#define BRAINBOXES_US_257_PID 0x5001 /* US-257 2xRS232 1Mbaud */ +#define BRAINBOXES_US_313_PID 0x6001 /* US-313 2xRS422/485 1Mbaud */ +#define BRAINBOXES_US_357_PID 0x7001 /* US_357 1xRS232/422/485 */ +#define BRAINBOXES_US_842_1_PID 0x8001 /* US-842 8xRS422/485 1Mbaud Port 1 and 2 */ +#define BRAINBOXES_US_842_2_PID 0x8002 /* US-842 8xRS422/485 1Mbaud Port 3 and 4 */ +#define BRAINBOXES_US_842_3_PID 0x8003 /* US-842 8xRS422/485 1Mbaud Port 5 and 6 */ +#define BRAINBOXES_US_842_4_PID 0x8004 /* US-842 8xRS422/485 1Mbaud Port 7 and 8 */ +#define BRAINBOXES_US_160_1_PID 0x9001 /* US-160 16xRS232 1Mbaud Port 1 and 2 */ +#define BRAINBOXES_US_160_2_PID 0x9002 /* US-160 16xRS232 1Mbaud Port 3 and 4 */ +#define BRAINBOXES_US_160_3_PID 0x9003 /* US-160 16xRS232 1Mbaud Port 5 and 6 */ +#define BRAINBOXES_US_160_4_PID 0x9004 /* US-160 16xRS232 1Mbaud Port 7 and 8 */ +#define BRAINBOXES_US_160_5_PID 0x9005 /* US-160 16xRS232 1Mbaud Port 9 and 10 */ +#define BRAINBOXES_US_160_6_PID 0x9006 /* US-160 16xRS232 1Mbaud Port 11 and 12 */ +#define BRAINBOXES_US_160_7_PID 0x9007 /* US-160 16xRS232 1Mbaud Port 13 and 14 */ +#define BRAINBOXES_US_160_8_PID 0x9008 /* US-160 16xRS232 1Mbaud Port 15 and 16 */ diff --git a/drivers/usb/serial/funsoft.c b/drivers/usb/serial/funsoft.c deleted file mode 100644 index e21ce9ddfc6..00000000000 --- a/drivers/usb/serial/funsoft.c +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Funsoft Serial USB driver - * - * Copyright (C) 2006 Greg Kroah-Hartman <gregkh@suse.de> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - */ - -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/tty.h> -#include <linux/module.h> -#include <linux/usb.h> -#include <linux/usb/serial.h> -#include <linux/uaccess.h> - -static int debug; - -static const struct usb_device_id id_table[] = { - { USB_DEVICE(0x1404, 0xcddc) }, - { }, -}; -MODULE_DEVICE_TABLE(usb, id_table); - -static struct usb_driver funsoft_driver = { - .name = "funsoft", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, - .no_dynamic_id = 1, -}; - -static struct usb_serial_driver funsoft_device = { - .driver = { - .owner = THIS_MODULE, - .name = "funsoft", - }, - .id_table = id_table, - .usb_driver = &funsoft_driver, - .num_ports = 1, -}; - -static int __init funsoft_init(void) -{ - int retval; - - retval = usb_serial_register(&funsoft_device); - if (retval) - return retval; - retval = usb_register(&funsoft_driver); - if (retval) - usb_serial_deregister(&funsoft_device); - return retval; -} - -static void __exit funsoft_exit(void) -{ - usb_deregister(&funsoft_driver); - usb_serial_deregister(&funsoft_device); -} - -module_init(funsoft_init); -module_exit(funsoft_exit); -MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c index 26710b18991..db591d19d41 100644 --- a/drivers/usb/serial/garmin_gps.c +++ b/drivers/usb/serial/garmin_gps.c @@ -1,7 +1,7 @@ /* * Garmin GPS driver * - * Copyright (C) 2006-2009 Hermann Kneissel herkne@users.sourceforge.net + * Copyright (C) 2006-2011 Hermann Kneissel herkne@gmx.de * * The latest version of the driver can be found at * http://sourceforge.net/projects/garmin-gps/ @@ -25,7 +25,6 @@ #include <linux/kernel.h> #include <linux/errno.h> -#include <linux/init.h> #include <linux/slab.h> #include <linux/timer.h> #include <linux/tty.h> @@ -34,16 +33,13 @@ #include <linux/module.h> #include <linux/spinlock.h> #include <linux/uaccess.h> -#include <asm/atomic.h> +#include <linux/atomic.h> #include <linux/usb.h> #include <linux/usb/serial.h> /* the mode to be set when the port ist opened */ static int initial_mode = 1; -/* debug flag */ -static int debug; - #define GARMIN_VENDOR_ID 0x091E /* @@ -51,7 +47,7 @@ static int debug; */ #define VERSION_MAJOR 0 -#define VERSION_MINOR 33 +#define VERSION_MINOR 36 #define _STR(s) #s #define _DRIVER_VERSION(a, b) "v" _STR(a) "." _STR(b) @@ -216,17 +212,8 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(GARMIN_VENDOR_ID, 3) }, { } /* Terminating entry */ }; - MODULE_DEVICE_TABLE(usb, id_table); -static struct usb_driver garmin_driver = { - .name = "garmin_gps", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, - .no_dynamic_id = 1, -}; - static inline int getLayerId(const __u8 *usbPacket) { @@ -264,17 +251,11 @@ static inline int isAbortTrfCmnd(const unsigned char *buf) static void send_to_tty(struct usb_serial_port *port, char *data, unsigned int actual_length) { - struct tty_struct *tty = tty_port_tty_get(&port->port); - - if (tty && actual_length) { - - usb_serial_debug_data(debug, &port->dev, - __func__, actual_length, data); - - tty_insert_flip_string(tty, data, actual_length); - tty_flip_buffer_push(tty); + if (actual_length) { + usb_serial_debug_data(&port->dev, __func__, actual_length, data); + tty_insert_flip_string(&port->port, data, actual_length); + tty_flip_buffer_push(&port->port); } - tty_kref_put(tty); } @@ -293,14 +274,13 @@ static int pkt_add(struct garmin_data *garmin_data_p, unsigned long flags; struct garmin_packet *pkt; - /* process only packets containg data ... */ + /* process only packets containing data ... */ if (data_length) { pkt = kmalloc(sizeof(struct garmin_packet)+data_length, GFP_ATOMIC); - if (pkt == NULL) { - dev_err(&garmin_data_p->port->dev, "out of memory\n"); + if (!pkt) return 0; - } + pkt->size = data_length; memcpy(pkt->data, data, data_length); @@ -312,8 +292,9 @@ static int pkt_add(struct garmin_data *garmin_data_p, state = garmin_data_p->state; spin_unlock_irqrestore(&garmin_data_p->lock, flags); - dbg("%s - added: pkt: %d - %d bytes", - __func__, pkt->seq, data_length); + dev_dbg(&garmin_data_p->port->dev, + "%s - added: pkt: %d - %d bytes\n", __func__, + pkt->seq, data_length); /* in serial mode, if someone is waiting for data from the device, convert and send the next packet to tty. */ @@ -346,8 +327,6 @@ static void pkt_clear(struct garmin_data *garmin_data_p) unsigned long flags; struct garmin_packet *result = NULL; - dbg("%s", __func__); - spin_lock_irqsave(&garmin_data_p->lock, flags); while (!list_empty(&garmin_data_p->pktlist)) { result = (struct garmin_packet *)garmin_data_p->pktlist.next; @@ -370,7 +349,8 @@ static int gsp_send_ack(struct garmin_data *garmin_data_p, __u8 pkt_id) __u8 *ptr = pkt; unsigned l = 0; - dbg("%s - pkt-id: 0x%X.", __func__, 0xFF & pkt_id); + dev_dbg(&garmin_data_p->port->dev, "%s - pkt-id: 0x%X.\n", __func__, + 0xFF & pkt_id); *ptr++ = DLE; *ptr++ = ACK; @@ -410,19 +390,20 @@ static int gsp_send_ack(struct garmin_data *garmin_data_p, __u8 pkt_id) */ static int gsp_rec_packet(struct garmin_data *garmin_data_p, int count) { + struct device *dev = &garmin_data_p->port->dev; + unsigned long flags; const __u8 *recpkt = garmin_data_p->inbuffer+GSP_INITIAL_OFFSET; __le32 *usbdata = (__le32 *) garmin_data_p->inbuffer; - int cksum = 0; int n = 0; int pktid = recpkt[0]; int size = recpkt[1]; - usb_serial_debug_data(debug, &garmin_data_p->port->dev, - __func__, count-GSP_INITIAL_OFFSET, recpkt); + usb_serial_debug_data(&garmin_data_p->port->dev, __func__, + count-GSP_INITIAL_OFFSET, recpkt); if (size != (count-GSP_INITIAL_OFFSET-3)) { - dbg("%s - invalid size, expected %d bytes, got %d", + dev_dbg(dev, "%s - invalid size, expected %d bytes, got %d\n", __func__, size, (count-GSP_INITIAL_OFFSET-3)); return -EINVPKT; } @@ -432,8 +413,8 @@ static int gsp_rec_packet(struct garmin_data *garmin_data_p, int count) /* sanity check, remove after test ... */ if ((__u8 *)&(usbdata[3]) != recpkt) { - dbg("%s - ptr mismatch %p - %p", - __func__, &(usbdata[4]), recpkt); + dev_dbg(dev, "%s - ptr mismatch %p - %p\n", __func__, + &(usbdata[4]), recpkt); return -EINVPKT; } @@ -443,7 +424,7 @@ static int gsp_rec_packet(struct garmin_data *garmin_data_p, int count) } if ((0xff & (cksum + *recpkt)) != 0) { - dbg("%s - invalid checksum, expected %02x, got %02x", + dev_dbg(dev, "%s - invalid checksum, expected %02x, got %02x\n", __func__, 0xff & -cksum, 0xff & *recpkt); return -EINVPKT; } @@ -458,7 +439,9 @@ static int gsp_rec_packet(struct garmin_data *garmin_data_p, int count) /* if this was an abort-transfer command, flush all queued data. */ if (isAbortTrfCmnd(garmin_data_p->inbuffer)) { + spin_lock_irqsave(&garmin_data_p->lock, flags); garmin_data_p->flags |= FLAGS_DROP_DATA; + spin_unlock_irqrestore(&garmin_data_p->lock, flags); pkt_clear(garmin_data_p); } @@ -488,6 +471,7 @@ static int gsp_rec_packet(struct garmin_data *garmin_data_p, int count) static int gsp_receive(struct garmin_data *garmin_data_p, const unsigned char *buf, int count) { + struct device *dev = &garmin_data_p->port->dev; unsigned long flags; int offs = 0; int ack_or_nak_seen = 0; @@ -508,7 +492,7 @@ static int gsp_receive(struct garmin_data *garmin_data_p, skip = garmin_data_p->flags & FLAGS_GSP_SKIP; spin_unlock_irqrestore(&garmin_data_p->lock, flags); - /* dbg("%s - dle=%d skip=%d size=%d count=%d", + /* dev_dbg(dev, "%s - dle=%d skip=%d size=%d count=%d\n", __func__, dleSeen, skip, size, count); */ if (size == 0) @@ -538,12 +522,12 @@ static int gsp_receive(struct garmin_data *garmin_data_p, if (data == ACK) { ack_or_nak_seen = ACK; - dbg("ACK packet complete."); + dev_dbg(dev, "ACK packet complete.\n"); } else if (data == NAK) { ack_or_nak_seen = NAK; - dbg("NAK packet complete."); + dev_dbg(dev, "NAK packet complete.\n"); } else { - dbg("packet complete - id=0x%X.", + dev_dbg(dev, "packet complete - id=0x%X.\n", 0xFF & data); gsp_rec_packet(garmin_data_p, size); } @@ -565,7 +549,7 @@ static int gsp_receive(struct garmin_data *garmin_data_p, } if (size >= GPS_IN_BUFSIZ) { - dbg("%s - packet too large.", __func__); + dev_dbg(dev, "%s - packet too large.\n", __func__); skip = 1; size = GSP_INITIAL_OFFSET; dleSeen = 0; @@ -610,6 +594,7 @@ static int gsp_receive(struct garmin_data *garmin_data_p, static int gsp_send(struct garmin_data *garmin_data_p, const unsigned char *buf, int count) { + struct device *dev = &garmin_data_p->port->dev; const unsigned char *src; unsigned char *dst; int pktid = 0; @@ -618,12 +603,12 @@ static int gsp_send(struct garmin_data *garmin_data_p, int i = 0; int k; - dbg("%s - state %d - %d bytes.", __func__, - garmin_data_p->state, count); + dev_dbg(dev, "%s - state %d - %d bytes.\n", __func__, + garmin_data_p->state, count); k = garmin_data_p->outsize; if ((k+count) > GPS_OUT_BUFSIZ) { - dbg("packet too large"); + dev_dbg(dev, "packet too large\n"); garmin_data_p->outsize = 0; return -4; } @@ -642,28 +627,28 @@ static int gsp_send(struct garmin_data *garmin_data_p, return 0; } - dbg("%s - %d bytes in buffer, %d bytes in pkt.", __func__, k, i); + dev_dbg(dev, "%s - %d bytes in buffer, %d bytes in pkt.\n", __func__, k, i); /* garmin_data_p->outbuffer now contains a complete packet */ - usb_serial_debug_data(debug, &garmin_data_p->port->dev, - __func__, k, garmin_data_p->outbuffer); + usb_serial_debug_data(&garmin_data_p->port->dev, __func__, k, + garmin_data_p->outbuffer); garmin_data_p->outsize = 0; if (GARMIN_LAYERID_APPL != getLayerId(garmin_data_p->outbuffer)) { - dbg("not an application packet (%d)", + dev_dbg(dev, "not an application packet (%d)\n", getLayerId(garmin_data_p->outbuffer)); return -1; } if (pktid > 255) { - dbg("packet-id %d too large", pktid); + dev_dbg(dev, "packet-id %d too large\n", pktid); return -2; } if (datalen > 255) { - dbg("packet-size %d too large", datalen); + dev_dbg(dev, "packet-size %d too large\n", datalen); return -3; } @@ -730,7 +715,7 @@ static int gsp_next_packet(struct garmin_data *garmin_data_p) struct garmin_packet *pkt = NULL; while ((pkt = pkt_pop(garmin_data_p)) != NULL) { - dbg("%s - next pkt: %d", __func__, pkt->seq); + dev_dbg(&garmin_data_p->port->dev, "%s - next pkt: %d\n", __func__, pkt->seq); result = gsp_send(garmin_data_p, pkt->data, pkt->size); if (result > 0) { kfree(pkt); @@ -776,7 +761,9 @@ static int nat_receive(struct garmin_data *garmin_data_p, if (len >= GPS_IN_BUFSIZ) { /* seems to be an invalid packet, ignore rest of input */ - dbg("%s - packet size too large: %d", __func__, len); + dev_dbg(&garmin_data_p->port->dev, + "%s - packet size too large: %d\n", + __func__, len); garmin_data_p->insize = 0; count = 0; result = -EINVPKT; @@ -857,10 +844,10 @@ static int process_resetdev_request(struct usb_serial_port *port) spin_unlock_irqrestore(&garmin_data_p->lock, flags); usb_kill_urb(port->interrupt_in_urb); - dbg("%s - usb_reset_device", __func__); + dev_dbg(&port->dev, "%s - usb_reset_device\n", __func__); status = usb_reset_device(port->serial->dev); if (status) - dbg("%s - usb_reset_device failed: %d", + dev_dbg(&port->dev, "%s - usb_reset_device failed: %d\n", __func__, status); return status; } @@ -897,8 +884,7 @@ static int garmin_init_session(struct usb_serial_port *port) if (status == 0) { usb_kill_urb(port->interrupt_in_urb); - dbg("%s - adding interrupt input", __func__); - port->interrupt_in_urb->dev = serial->dev; + dev_dbg(&serial->dev->dev, "%s - adding interrupt input\n", __func__); status = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); if (status) dev_err(&serial->dev->dev, @@ -911,7 +897,7 @@ static int garmin_init_session(struct usb_serial_port *port) * gpsbabel/jeeps/gpslibusb.c gusb_reset_toggles() */ if (status == 0) { - dbg("%s - starting session ...", __func__); + dev_dbg(&serial->dev->dev, "%s - starting session ...\n", __func__); garmin_data_p->state = STATE_ACTIVE; for (i = 0; i < 3; i++) { @@ -938,12 +924,10 @@ static int garmin_open(struct tty_struct *tty, struct usb_serial_port *port) int status = 0; struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); - dbg("%s - port %d", __func__, port->number); - spin_lock_irqsave(&garmin_data_p->lock, flags); garmin_data_p->mode = initial_mode; garmin_data_p->count = 0; - garmin_data_p->flags = 0; + garmin_data_p->flags &= FLAGS_SESSION_REPLY1_SEEN; spin_unlock_irqrestore(&garmin_data_p->lock, flags); /* shutdown any bulk reads that might be going on */ @@ -960,20 +944,13 @@ static int garmin_open(struct tty_struct *tty, struct usb_serial_port *port) static void garmin_close(struct usb_serial_port *port) { - struct usb_serial *serial = port->serial; struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); - dbg("%s - port %d - mode=%d state=%d flags=0x%X", __func__, - port->number, garmin_data_p->mode, - garmin_data_p->state, garmin_data_p->flags); + dev_dbg(&port->dev, "%s - mode=%d state=%d flags=0x%X\n", + __func__, garmin_data_p->mode, garmin_data_p->state, + garmin_data_p->flags); - if (!serial) - return; - - mutex_lock(&port->serial->disc_mutex); - - if (!port->serial->disconnected) - garmin_clear(garmin_data_p); + garmin_clear(garmin_data_p); /* shutdown our urbs */ usb_kill_urb(port->read_urb); @@ -982,8 +959,6 @@ static void garmin_close(struct usb_serial_port *port) /* keep reset state so we know that we must start a new session */ if (garmin_data_p->state != STATE_RESET) garmin_data_p->state = STATE_DISCONNECTED; - - mutex_unlock(&port->serial->disc_mutex); } @@ -995,8 +970,6 @@ static void garmin_write_bulk_callback(struct urb *urb) struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); - dbg("%s - port %d", __func__, port->number); - if (GARMIN_LAYERID_APPL == getLayerId(urb->transfer_buffer)) { if (garmin_data_p->mode == MODE_GARMIN_SERIAL) { @@ -1026,29 +999,23 @@ static int garmin_write_bulk(struct usb_serial_port *port, unsigned char *buffer; int status; - dbg("%s - port %d, state %d", __func__, port->number, - garmin_data_p->state); - spin_lock_irqsave(&garmin_data_p->lock, flags); garmin_data_p->flags &= ~FLAGS_DROP_DATA; spin_unlock_irqrestore(&garmin_data_p->lock, flags); buffer = kmalloc(count, GFP_ATOMIC); - if (!buffer) { - dev_err(&port->dev, "out of memory\n"); + if (!buffer) return -ENOMEM; - } urb = usb_alloc_urb(0, GFP_ATOMIC); if (!urb) { - dev_err(&port->dev, "no more free urbs\n"); kfree(buffer); return -ENOMEM; } memcpy(buffer, buf, count); - usb_serial_debug_data(debug, &port->dev, __func__, count, buffer); + usb_serial_debug_data(&port->dev, __func__, count, buffer); usb_fill_bulk_urb(urb, serial->dev, usb_sndbulkpipe(serial->dev, @@ -1089,11 +1056,12 @@ static int garmin_write_bulk(struct usb_serial_port *port, static int garmin_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count) { + struct device *dev = &port->dev; int pktid, pktsiz, len; struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); __le32 *privpkt = (__le32 *)garmin_data_p->privpkt; - usb_serial_debug_data(debug, &port->dev, __func__, count, buf); + usb_serial_debug_data(dev, __func__, count, buf); if (garmin_data_p->state == STATE_RESET) return -EIO; @@ -1113,27 +1081,18 @@ static int garmin_write(struct tty_struct *tty, struct usb_serial_port *port, && GARMIN_LAYERID_PRIVATE == getLayerId(garmin_data_p->privpkt)) { - dbg("%s - processing private request %d", + dev_dbg(dev, "%s - processing private request %d\n", __func__, pktid); /* drop all unfinished transfers */ garmin_clear(garmin_data_p); switch (pktid) { - - case PRIV_PKTID_SET_DEBUG: - if (pktsiz != 4) - return -EINVPKT; - debug = __le32_to_cpu(privpkt[3]); - dbg("%s - debug level set to 0x%X", - __func__, debug); - break; - case PRIV_PKTID_SET_MODE: if (pktsiz != 4) return -EINVPKT; garmin_data_p->mode = __le32_to_cpu(privpkt[3]); - dbg("%s - mode set to %d", + dev_dbg(dev, "%s - mode set to %d\n", __func__, garmin_data_p->mode); break; @@ -1149,7 +1108,7 @@ static int garmin_write(struct tty_struct *tty, struct usb_serial_port *port, if (pktsiz != 4) return -EINVPKT; initial_mode = __le32_to_cpu(privpkt[3]); - dbg("%s - initial_mode set to %d", + dev_dbg(dev, "%s - initial_mode set to %d\n", __func__, garmin_data_p->mode); break; @@ -1178,13 +1137,14 @@ static int garmin_write_room(struct tty_struct *tty) static void garmin_read_process(struct garmin_data *garmin_data_p, - unsigned char *data, unsigned data_length) + unsigned char *data, unsigned data_length, + int bulk_data) { unsigned long flags; if (garmin_data_p->flags & FLAGS_DROP_DATA) { - /* abort-transfer cmd is actice */ - dbg("%s - pkt dropped", __func__); + /* abort-transfer cmd is active */ + dev_dbg(&garmin_data_p->port->dev, "%s - pkt dropped\n", __func__); } else if (garmin_data_p->state != STATE_DISCONNECTED && garmin_data_p->state != STATE_RESET) { @@ -1193,7 +1153,8 @@ static void garmin_read_process(struct garmin_data *garmin_data_p, send it directly to the tty port */ if (garmin_data_p->flags & FLAGS_QUEUING) { pkt_add(garmin_data_p, data, data_length); - } else if (getLayerId(data) == GARMIN_LAYERID_APPL) { + } else if (bulk_data || + getLayerId(data) == GARMIN_LAYERID_APPL) { spin_lock_irqsave(&garmin_data_p->lock, flags); garmin_data_p->flags |= APP_RESP_SEEN; @@ -1215,29 +1176,20 @@ static void garmin_read_bulk_callback(struct urb *urb) { unsigned long flags; struct usb_serial_port *port = urb->context; - struct usb_serial *serial = port->serial; struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); unsigned char *data = urb->transfer_buffer; int status = urb->status; int retval; - dbg("%s - port %d", __func__, port->number); - - if (!serial) { - dbg("%s - bad serial pointer, exiting", __func__); - return; - } - if (status) { - dbg("%s - nonzero read bulk status received: %d", + dev_dbg(&urb->dev->dev, "%s - nonzero read bulk status received: %d\n", __func__, status); return; } - usb_serial_debug_data(debug, &port->dev, - __func__, urb->actual_length, data); + usb_serial_debug_data(&port->dev, __func__, urb->actual_length, data); - garmin_read_process(garmin_data_p, data, urb->actual_length); + garmin_read_process(garmin_data_p, data, urb->actual_length, 1); if (urb->actual_length == 0 && 0 != (garmin_data_p->flags & FLAGS_BULK_IN_RESTART)) { @@ -1255,11 +1207,11 @@ static void garmin_read_bulk_callback(struct urb *urb) retval = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (retval) dev_err(&port->dev, - "%s - failed resubmitting read urb, " - "error %d\n", __func__, retval); + "%s - failed resubmitting read urb, error %d\n", + __func__, retval); } } else { - dbg("%s - end of bulk data", __func__); + dev_dbg(&port->dev, "%s - end of bulk data\n", __func__); spin_lock_irqsave(&garmin_data_p->lock, flags); garmin_data_p->flags &= ~FLAGS_BULK_IN_ACTIVE; spin_unlock_irqrestore(&garmin_data_p->lock, flags); @@ -1272,7 +1224,6 @@ static void garmin_read_int_callback(struct urb *urb) unsigned long flags; int retval; struct usb_serial_port *port = urb->context; - struct usb_serial *serial = port->serial; struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); unsigned char *data = urb->transfer_buffer; int status = urb->status; @@ -1285,33 +1236,27 @@ static void garmin_read_int_callback(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", + dev_dbg(&urb->dev->dev, "%s - urb shutting down with status: %d\n", __func__, status); return; default: - dbg("%s - nonzero urb status received: %d", + dev_dbg(&urb->dev->dev, "%s - nonzero urb status received: %d\n", __func__, status); return; } - usb_serial_debug_data(debug, &port->dev, __func__, - urb->actual_length, urb->transfer_buffer); + usb_serial_debug_data(&port->dev, __func__, urb->actual_length, + urb->transfer_buffer); if (urb->actual_length == sizeof(GARMIN_BULK_IN_AVAIL_REPLY) && 0 == memcmp(data, GARMIN_BULK_IN_AVAIL_REPLY, sizeof(GARMIN_BULK_IN_AVAIL_REPLY))) { - dbg("%s - bulk data available.", __func__); + dev_dbg(&port->dev, "%s - bulk data available.\n", __func__); if (0 == (garmin_data_p->flags & FLAGS_BULK_IN_ACTIVE)) { /* bulk data available */ - usb_fill_bulk_urb(port->read_urb, serial->dev, - usb_rcvbulkpipe(serial->dev, - port->bulk_in_endpointAddress), - port->read_urb->transfer_buffer, - port->read_urb->transfer_buffer_length, - garmin_read_bulk_callback, port); retval = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (retval) { dev_err(&port->dev, @@ -1342,13 +1287,12 @@ static void garmin_read_int_callback(struct urb *urb) garmin_data_p->serial_num = __le32_to_cpup( (__le32 *)(data+GARMIN_PKTHDR_LENGTH)); - dbg("%s - start-of-session reply seen - serial %u.", + dev_dbg(&port->dev, "%s - start-of-session reply seen - serial %u.\n", __func__, garmin_data_p->serial_num); } - garmin_read_process(garmin_data_p, data, urb->actual_length); + garmin_read_process(garmin_data_p, data, urb->actual_length, 0); - port->interrupt_in_urb->dev = port->serial->dev; retval = usb_submit_urb(urb, GFP_ATOMIC); if (retval) dev_err(&urb->dev->dev, @@ -1389,7 +1333,6 @@ static void garmin_throttle(struct tty_struct *tty) struct usb_serial_port *port = tty->driver_data; struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); - dbg("%s - port %d", __func__, port->number); /* set flag, data received will be put into a queue for later processing */ spin_lock_irq(&garmin_data_p->lock); @@ -1404,7 +1347,6 @@ static void garmin_unthrottle(struct tty_struct *tty) struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); int status; - dbg("%s - port %d", __func__, port->number); spin_lock_irq(&garmin_data_p->lock); garmin_data_p->flags &= ~FLAGS_THROTTLED; spin_unlock_irq(&garmin_data_p->lock); @@ -1440,19 +1382,15 @@ static void timeout_handler(unsigned long data) -static int garmin_attach(struct usb_serial *serial) +static int garmin_port_probe(struct usb_serial_port *port) { - int status = 0; - struct usb_serial_port *port = serial->port[0]; - struct garmin_data *garmin_data_p = NULL; - - dbg("%s", __func__); + int status; + struct garmin_data *garmin_data_p; garmin_data_p = kzalloc(sizeof(struct garmin_data), GFP_KERNEL); - if (garmin_data_p == NULL) { - dev_err(&port->dev, "%s - Out of memory\n", __func__); + if (!garmin_data_p) return -ENOMEM; - } + init_timer(&garmin_data_p->timer); spin_lock_init(&garmin_data_p->lock); INIT_LIST_HEAD(&garmin_data_p->pktlist); @@ -1461,6 +1399,7 @@ static int garmin_attach(struct usb_serial *serial) garmin_data_p->timer.function = timeout_handler; garmin_data_p->port = port; garmin_data_p->state = 0; + garmin_data_p->flags = 0; garmin_data_p->count = 0; usb_set_serial_port_data(port, garmin_data_p); @@ -1470,26 +1409,14 @@ static int garmin_attach(struct usb_serial *serial) } -static void garmin_disconnect(struct usb_serial *serial) +static int garmin_port_remove(struct usb_serial_port *port) { - struct usb_serial_port *port = serial->port[0]; struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); - dbg("%s", __func__); - usb_kill_urb(port->interrupt_in_urb); del_timer_sync(&garmin_data_p->timer); -} - - -static void garmin_release(struct usb_serial *serial) -{ - struct usb_serial_port *port = serial->port[0]; - struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); - - dbg("%s", __func__); - kfree(garmin_data_p); + return 0; } @@ -1500,16 +1427,14 @@ static struct usb_serial_driver garmin_device = { .name = "garmin_gps", }, .description = "Garmin GPS usb/tty", - .usb_driver = &garmin_driver, .id_table = id_table, .num_ports = 1, .open = garmin_open, .close = garmin_close, .throttle = garmin_throttle, .unthrottle = garmin_unthrottle, - .attach = garmin_attach, - .disconnect = garmin_disconnect, - .release = garmin_release, + .port_probe = garmin_port_probe, + .port_remove = garmin_port_remove, .write = garmin_write, .write_room = garmin_write_room, .write_bulk_callback = garmin_write_bulk_callback, @@ -1517,47 +1442,15 @@ static struct usb_serial_driver garmin_device = { .read_int_callback = garmin_read_int_callback, }; +static struct usb_serial_driver * const serial_drivers[] = { + &garmin_device, NULL +}; - -static int __init garmin_init(void) -{ - int retval; - - retval = usb_serial_register(&garmin_device); - if (retval) - goto failed_garmin_register; - retval = usb_register(&garmin_driver); - if (retval) - goto failed_usb_register; - printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" - DRIVER_DESC "\n"); - - return 0; -failed_usb_register: - usb_serial_deregister(&garmin_device); -failed_garmin_register: - return retval; -} - - -static void __exit garmin_exit(void) -{ - usb_deregister(&garmin_driver); - usb_serial_deregister(&garmin_device); -} - - - - -module_init(garmin_init); -module_exit(garmin_exit); +module_usb_serial_driver(serial_drivers, id_table); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); -module_param(debug, bool, S_IWUSR | S_IRUGO); -MODULE_PARM_DESC(debug, "Debug enabled or not"); module_param(initial_mode, int, S_IRUGO); MODULE_PARM_DESC(initial_mode, "Initial mode"); - diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index e6833e216fc..1bd192290b0 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c @@ -1,13 +1,12 @@ /* * USB Serial Converter Generic functions * - * Copyright (C) 2010 Johan Hovold (jhovold@gmail.com) + * Copyright (C) 2010 - 2013 Johan Hovold (jhovold@gmail.com) * Copyright (C) 1999 - 2002 Greg Kroah-Hartman (greg@kroah.com) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version * 2 as published by the Free Software Foundation. - * */ #include <linux/kernel.h> @@ -24,13 +23,8 @@ #include <linux/kfifo.h> #include <linux/serial.h> -static int debug; - #ifdef CONFIG_USB_SERIAL_GENERIC -static int generic_probe(struct usb_interface *interface, - const struct usb_device_id *id); - static __u16 vendor = 0x05f9; static __u16 product = 0xffff; @@ -42,68 +36,36 @@ MODULE_PARM_DESC(product, "User specified USB idProduct"); static struct usb_device_id generic_device_ids[2]; /* Initially all zeroes. */ -/* we want to look at all devices, as the vendor/product id can change - * depending on the command line argument */ -static const struct usb_device_id generic_serial_ids[] = { - {.driver_info = 42}, - {} -}; - -static struct usb_driver generic_driver = { - .name = "usbserial_generic", - .probe = generic_probe, - .disconnect = usb_serial_disconnect, - .id_table = generic_serial_ids, - .no_dynamic_id = 1, -}; - -/* All of the device info needed for the Generic Serial Converter */ struct usb_serial_driver usb_serial_generic_device = { .driver = { .owner = THIS_MODULE, .name = "generic", }, .id_table = generic_device_ids, - .usb_driver = &generic_driver, .num_ports = 1, - .disconnect = usb_serial_generic_disconnect, - .release = usb_serial_generic_release, .throttle = usb_serial_generic_throttle, .unthrottle = usb_serial_generic_unthrottle, .resume = usb_serial_generic_resume, }; -static int generic_probe(struct usb_interface *interface, - const struct usb_device_id *id) -{ - const struct usb_device_id *id_pattern; +static struct usb_serial_driver * const serial_drivers[] = { + &usb_serial_generic_device, NULL +}; - id_pattern = usb_match_id(interface, generic_device_ids); - if (id_pattern != NULL) - return usb_serial_probe(interface, id); - return -ENODEV; -} #endif -int usb_serial_generic_register(int _debug) +int usb_serial_generic_register(void) { int retval = 0; - debug = _debug; #ifdef CONFIG_USB_SERIAL_GENERIC generic_device_ids[0].idVendor = vendor; generic_device_ids[0].idProduct = product; generic_device_ids[0].match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT; - /* register our generic driver with ourselves */ - retval = usb_serial_register(&usb_serial_generic_device); - if (retval) - goto exit; - retval = usb_register(&generic_driver); - if (retval) - usb_serial_deregister(&usb_serial_generic_device); -exit: + retval = usb_serial_register_drivers(serial_drivers, + "usbserial_generic", generic_device_ids); #endif return retval; } @@ -111,9 +73,7 @@ exit: void usb_serial_generic_deregister(void) { #ifdef CONFIG_USB_SERIAL_GENERIC - /* remove our generic driver */ - usb_deregister(&generic_driver); - usb_serial_deregister(&usb_serial_generic_device); + usb_serial_deregister_drivers(serial_drivers); #endif } @@ -122,50 +82,35 @@ int usb_serial_generic_open(struct tty_struct *tty, struct usb_serial_port *port int result = 0; unsigned long flags; - dbg("%s - port %d", __func__, port->number); - - /* clear the throttle flags */ spin_lock_irqsave(&port->lock, flags); port->throttled = 0; port->throttle_req = 0; spin_unlock_irqrestore(&port->lock, flags); - /* if we have a bulk endpoint, start reading from it */ if (port->bulk_in_size) - result = usb_serial_generic_submit_read_urb(port, GFP_KERNEL); + result = usb_serial_generic_submit_read_urbs(port, GFP_KERNEL); return result; } EXPORT_SYMBOL_GPL(usb_serial_generic_open); -static void generic_cleanup(struct usb_serial_port *port) +void usb_serial_generic_close(struct usb_serial_port *port) { - struct usb_serial *serial = port->serial; unsigned long flags; int i; - dbg("%s - port %d", __func__, port->number); - - if (serial->dev) { - /* shutdown any bulk transfers that might be going on */ - if (port->bulk_out_size) { - usb_kill_urb(port->write_urb); - for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) - usb_kill_urb(port->write_urbs[i]); + if (port->bulk_out_size) { + for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) + usb_kill_urb(port->write_urbs[i]); - spin_lock_irqsave(&port->lock, flags); - kfifo_reset_out(&port->write_fifo); - spin_unlock_irqrestore(&port->lock, flags); - } - if (port->bulk_in_size) - usb_kill_urb(port->read_urb); + spin_lock_irqsave(&port->lock, flags); + kfifo_reset_out(&port->write_fifo); + spin_unlock_irqrestore(&port->lock, flags); + } + if (port->bulk_in_size) { + for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) + usb_kill_urb(port->read_urbs[i]); } -} - -void usb_serial_generic_close(struct usb_serial_port *port) -{ - dbg("%s - port %d", __func__, port->number); - generic_cleanup(port); } EXPORT_SYMBOL_GPL(usb_serial_generic_close); @@ -176,12 +121,16 @@ int usb_serial_generic_prepare_write_buffer(struct usb_serial_port *port, } /** - * usb_serial_generic_write_start - kick off an URB write - * @port: Pointer to the &struct usb_serial_port data + * usb_serial_generic_write_start - start writing buffered data + * @port: usb-serial port + * @mem_flags: flags to use for memory allocations * - * Returns zero on success, or a negative errno value + * Serialised using USB_SERIAL_WRITE_BUSY flag. + * + * Return: Zero on success or if busy, otherwise a negative errno value. */ -static int usb_serial_generic_write_start(struct usb_serial_port *port) +int usb_serial_generic_write_start(struct usb_serial_port *port, + gfp_t mem_flags) { struct urb *urb; int count, result; @@ -206,16 +155,15 @@ retry: urb->transfer_buffer, port->bulk_out_size); urb->transfer_buffer_length = count; - usb_serial_debug_data(debug, &port->dev, __func__, count, - urb->transfer_buffer); + usb_serial_debug_data(&port->dev, __func__, count, urb->transfer_buffer); spin_lock_irqsave(&port->lock, flags); port->tx_bytes += count; spin_unlock_irqrestore(&port->lock, flags); clear_bit(i, &port->write_urbs_free); - result = usb_submit_urb(urb, GFP_ATOMIC); + result = usb_submit_urb(urb, mem_flags); if (result) { - dev_err(&port->dev, "%s - error submitting urb: %d\n", + dev_err_console(port, "%s - error submitting urb: %d\n", __func__, result); set_bit(i, &port->write_urbs_free); spin_lock_irqsave(&port->lock, flags); @@ -226,35 +174,25 @@ retry: return result; } - /* Try sending off another urb, unless in irq context (in which case - * there will be no free urb). */ - if (!in_irq()) - goto retry; - - clear_bit_unlock(USB_SERIAL_WRITE_BUSY, &port->flags); - - return 0; + goto retry; /* try sending off another urb */ } +EXPORT_SYMBOL_GPL(usb_serial_generic_write_start); /** - * usb_serial_generic_write - generic write function for serial USB devices - * @tty: Pointer to &struct tty_struct for the device - * @port: Pointer to the &usb_serial_port structure for the device - * @buf: Pointer to the data to write - * @count: Number of bytes to write + * usb_serial_generic_write - generic write function + * @tty: tty for the port + * @port: usb-serial port + * @buf: data to write + * @count: number of bytes to write * - * Returns the number of characters actually written, which may be anything - * from zero to @count. If an error occurs, it returns the negative errno - * value. + * Return: The number of characters buffered, which may be anything from + * zero to @count, or a negative errno value. */ int usb_serial_generic_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count) { int result; - dbg("%s - port %d", __func__, port->number); - - /* only do something if we have a bulk out endpoint */ if (!port->bulk_out_size) return -ENODEV; @@ -262,7 +200,7 @@ int usb_serial_generic_write(struct tty_struct *tty, return 0; count = kfifo_in_locked(&port->write_fifo, buf, count, &port->lock); - result = usb_serial_generic_write_start(port); + result = usb_serial_generic_write_start(port, GFP_ATOMIC); if (result) return result; @@ -276,8 +214,6 @@ int usb_serial_generic_write_room(struct tty_struct *tty) unsigned long flags; int room; - dbg("%s - port %d", __func__, port->number); - if (!port->bulk_out_size) return 0; @@ -285,7 +221,7 @@ int usb_serial_generic_write_room(struct tty_struct *tty) room = kfifo_avail(&port->write_fifo); spin_unlock_irqrestore(&port->lock, flags); - dbg("%s - returns %d", __func__, room); + dev_dbg(&port->dev, "%s - returns %d\n", __func__, room); return room; } @@ -295,8 +231,6 @@ int usb_serial_generic_chars_in_buffer(struct tty_struct *tty) unsigned long flags; int chars; - dbg("%s - port %d", __func__, port->number); - if (!port->bulk_out_size) return 0; @@ -304,51 +238,109 @@ int usb_serial_generic_chars_in_buffer(struct tty_struct *tty) chars = kfifo_len(&port->write_fifo) + port->tx_bytes; spin_unlock_irqrestore(&port->lock, flags); - dbg("%s - returns %d", __func__, chars); + dev_dbg(&port->dev, "%s - returns %d\n", __func__, chars); return chars; } +EXPORT_SYMBOL_GPL(usb_serial_generic_chars_in_buffer); -int usb_serial_generic_submit_read_urb(struct usb_serial_port *port, +void usb_serial_generic_wait_until_sent(struct tty_struct *tty, long timeout) +{ + struct usb_serial_port *port = tty->driver_data; + unsigned int bps; + unsigned long period; + unsigned long expire; + + bps = tty_get_baud_rate(tty); + if (!bps) + bps = 9600; /* B0 */ + /* + * Use a poll-period of roughly the time it takes to send one + * character or at least one jiffy. + */ + period = max_t(unsigned long, (10 * HZ / bps), 1); + period = min_t(unsigned long, period, timeout); + + dev_dbg(&port->dev, "%s - timeout = %u ms, period = %u ms\n", + __func__, jiffies_to_msecs(timeout), + jiffies_to_msecs(period)); + expire = jiffies + timeout; + while (!port->serial->type->tx_empty(port)) { + schedule_timeout_interruptible(period); + if (signal_pending(current)) + break; + if (time_after(jiffies, expire)) + break; + } +} +EXPORT_SYMBOL_GPL(usb_serial_generic_wait_until_sent); + +static int usb_serial_generic_submit_read_urb(struct usb_serial_port *port, + int index, gfp_t mem_flags) +{ + int res; + + if (!test_and_clear_bit(index, &port->read_urbs_free)) + return 0; + + dev_dbg(&port->dev, "%s - urb %d\n", __func__, index); + + res = usb_submit_urb(port->read_urbs[index], mem_flags); + if (res) { + if (res != -EPERM) { + dev_err(&port->dev, + "%s - usb_submit_urb failed: %d\n", + __func__, res); + } + set_bit(index, &port->read_urbs_free); + return res; + } + + return 0; +} + +int usb_serial_generic_submit_read_urbs(struct usb_serial_port *port, gfp_t mem_flags) { - int result; + int res; + int i; - result = usb_submit_urb(port->read_urb, mem_flags); - if (result && result != -EPERM) { - dev_err(&port->dev, "%s - error submitting urb: %d\n", - __func__, result); + for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) { + res = usb_serial_generic_submit_read_urb(port, i, mem_flags); + if (res) + goto err; } - return result; + + return 0; +err: + for (; i >= 0; --i) + usb_kill_urb(port->read_urbs[i]); + + return res; } -EXPORT_SYMBOL_GPL(usb_serial_generic_submit_read_urb); +EXPORT_SYMBOL_GPL(usb_serial_generic_submit_read_urbs); void usb_serial_generic_process_read_urb(struct urb *urb) { struct usb_serial_port *port = urb->context; - struct tty_struct *tty; char *ch = (char *)urb->transfer_buffer; int i; if (!urb->actual_length) return; - - tty = tty_port_tty_get(&port->port); - if (!tty) - return; - - /* The per character mucking around with sysrq path it too slow for - stuff like 3G modems, so shortcircuit it in the 99.9999999% of cases - where the USB serial is not a console anyway */ - if (!port->port.console || !port->sysrq) - tty_insert_flip_string(tty, ch, urb->actual_length); - else { + /* + * The per character mucking around with sysrq path it too slow for + * stuff like 3G modems, so shortcircuit it in the 99.9999999% of + * cases where the USB serial is not a console anyway. + */ + if (!port->port.console || !port->sysrq) { + tty_insert_flip_string(&port->port, ch, urb->actual_length); + } else { for (i = 0; i < urb->actual_length; i++, ch++) { if (!usb_serial_handle_sysrq_char(port, *ch)) - tty_insert_flip_char(tty, *ch, TTY_NORMAL); + tty_insert_flip_char(&port->port, *ch, TTY_NORMAL); } } - tty_flip_buffer_push(tty); - tty_kref_put(tty); + tty_flip_buffer_push(&port->port); } EXPORT_SYMBOL_GPL(usb_serial_generic_process_read_urb); @@ -356,29 +348,49 @@ void usb_serial_generic_read_bulk_callback(struct urb *urb) { struct usb_serial_port *port = urb->context; unsigned char *data = urb->transfer_buffer; - int status = urb->status; unsigned long flags; + int i; - dbg("%s - port %d", __func__, port->number); - - if (unlikely(status != 0)) { - dbg("%s - nonzero read bulk status received: %d", - __func__, status); + for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) { + if (urb == port->read_urbs[i]) + break; + } + set_bit(i, &port->read_urbs_free); + + dev_dbg(&port->dev, "%s - urb %d, len %d\n", __func__, i, + urb->actual_length); + switch (urb->status) { + case 0: + break; + case -ENOENT: + case -ECONNRESET: + case -ESHUTDOWN: + dev_dbg(&port->dev, "%s - urb stopped: %d\n", + __func__, urb->status); + return; + case -EPIPE: + dev_err(&port->dev, "%s - urb stopped: %d\n", + __func__, urb->status); return; + default: + dev_err(&port->dev, "%s - nonzero urb status: %d\n", + __func__, urb->status); + goto resubmit; } - usb_serial_debug_data(debug, &port->dev, __func__, - urb->actual_length, data); + usb_serial_debug_data(&port->dev, __func__, urb->actual_length, data); port->serial->type->process_read_urb(urb); +resubmit: /* Throttle the device if requested by tty */ spin_lock_irqsave(&port->lock, flags); port->throttled = port->throttle_req; if (!port->throttled) { spin_unlock_irqrestore(&port->lock, flags); - usb_serial_generic_submit_read_urb(port, GFP_ATOMIC); - } else + usb_serial_generic_submit_read_urb(port, i, GFP_ATOMIC); + } else { spin_unlock_irqrestore(&port->lock, flags); + } } EXPORT_SYMBOL_GPL(usb_serial_generic_read_bulk_callback); @@ -386,30 +398,38 @@ void usb_serial_generic_write_bulk_callback(struct urb *urb) { unsigned long flags; struct usb_serial_port *port = urb->context; - int status = urb->status; int i; - dbg("%s - port %d", __func__, port->number); - - for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) + for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) { if (port->write_urbs[i] == urb) break; - + } spin_lock_irqsave(&port->lock, flags); port->tx_bytes -= urb->transfer_buffer_length; set_bit(i, &port->write_urbs_free); spin_unlock_irqrestore(&port->lock, flags); - if (status) { - dbg("%s - non-zero urb status: %d", __func__, status); - - spin_lock_irqsave(&port->lock, flags); - kfifo_reset_out(&port->write_fifo); - spin_unlock_irqrestore(&port->lock, flags); - } else { - usb_serial_generic_write_start(port); + switch (urb->status) { + case 0: + break; + case -ENOENT: + case -ECONNRESET: + case -ESHUTDOWN: + dev_dbg(&port->dev, "%s - urb stopped: %d\n", + __func__, urb->status); + return; + case -EPIPE: + dev_err_console(port, "%s - urb stopped: %d\n", + __func__, urb->status); + return; + default: + dev_err_console(port, "%s - nonzero urb status: %d\n", + __func__, urb->status); + goto resubmit; } +resubmit: + usb_serial_generic_write_start(port, GFP_ATOMIC); usb_serial_port_softint(port); } EXPORT_SYMBOL_GPL(usb_serial_generic_write_bulk_callback); @@ -419,10 +439,6 @@ void usb_serial_generic_throttle(struct tty_struct *tty) struct usb_serial_port *port = tty->driver_data; unsigned long flags; - dbg("%s - port %d", __func__, port->number); - - /* Set the throttle request flag. It will be picked up - * by usb_serial_generic_read_bulk_callback(). */ spin_lock_irqsave(&port->lock, flags); port->throttle_req = 1; spin_unlock_irqrestore(&port->lock, flags); @@ -434,19 +450,92 @@ void usb_serial_generic_unthrottle(struct tty_struct *tty) struct usb_serial_port *port = tty->driver_data; int was_throttled; - dbg("%s - port %d", __func__, port->number); - - /* Clear the throttle flags */ spin_lock_irq(&port->lock); was_throttled = port->throttled; port->throttled = port->throttle_req = 0; spin_unlock_irq(&port->lock); if (was_throttled) - usb_serial_generic_submit_read_urb(port, GFP_KERNEL); + usb_serial_generic_submit_read_urbs(port, GFP_KERNEL); } EXPORT_SYMBOL_GPL(usb_serial_generic_unthrottle); +static bool usb_serial_generic_msr_changed(struct tty_struct *tty, + unsigned long arg, struct async_icount *cprev) +{ + struct usb_serial_port *port = tty->driver_data; + struct async_icount cnow; + unsigned long flags; + bool ret; + + /* + * Use tty-port initialised flag to detect all hangups including the + * one generated at USB-device disconnect. + */ + if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags)) + return true; + + spin_lock_irqsave(&port->lock, flags); + cnow = port->icount; /* atomic copy*/ + spin_unlock_irqrestore(&port->lock, flags); + + ret = ((arg & TIOCM_RNG) && (cnow.rng != cprev->rng)) || + ((arg & TIOCM_DSR) && (cnow.dsr != cprev->dsr)) || + ((arg & TIOCM_CD) && (cnow.dcd != cprev->dcd)) || + ((arg & TIOCM_CTS) && (cnow.cts != cprev->cts)); + + *cprev = cnow; + + return ret; +} + +int usb_serial_generic_tiocmiwait(struct tty_struct *tty, unsigned long arg) +{ + struct usb_serial_port *port = tty->driver_data; + struct async_icount cnow; + unsigned long flags; + int ret; + + spin_lock_irqsave(&port->lock, flags); + cnow = port->icount; /* atomic copy */ + spin_unlock_irqrestore(&port->lock, flags); + + ret = wait_event_interruptible(port->port.delta_msr_wait, + usb_serial_generic_msr_changed(tty, arg, &cnow)); + if (!ret && !test_bit(ASYNCB_INITIALIZED, &port->port.flags)) + ret = -EIO; + + return ret; +} +EXPORT_SYMBOL_GPL(usb_serial_generic_tiocmiwait); + +int usb_serial_generic_get_icount(struct tty_struct *tty, + struct serial_icounter_struct *icount) +{ + struct usb_serial_port *port = tty->driver_data; + struct async_icount cnow; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + cnow = port->icount; /* atomic copy */ + spin_unlock_irqrestore(&port->lock, flags); + + icount->cts = cnow.cts; + icount->dsr = cnow.dsr; + icount->rng = cnow.rng; + icount->dcd = cnow.dcd; + icount->tx = cnow.tx; + icount->rx = cnow.rx; + icount->frame = cnow.frame; + icount->parity = cnow.parity; + icount->overrun = cnow.overrun; + icount->brk = cnow.brk; + icount->buf_overrun = cnow.buf_overrun; + + return 0; +} +EXPORT_SYMBOL_GPL(usb_serial_generic_get_icount); + #ifdef CONFIG_MAGIC_SYSRQ int usb_serial_handle_sysrq_char(struct usb_serial_port *port, unsigned int ch) { @@ -479,6 +568,36 @@ int usb_serial_handle_break(struct usb_serial_port *port) } EXPORT_SYMBOL_GPL(usb_serial_handle_break); +/** + * usb_serial_handle_dcd_change - handle a change of carrier detect state + * @port: usb-serial port + * @tty: tty for the port + * @status: new carrier detect status, nonzero if active + */ +void usb_serial_handle_dcd_change(struct usb_serial_port *usb_port, + struct tty_struct *tty, unsigned int status) +{ + struct tty_port *port = &usb_port->port; + + dev_dbg(&usb_port->dev, "%s - status %d\n", __func__, status); + + if (tty) { + struct tty_ldisc *ld = tty_ldisc_ref(tty); + + if (ld) { + if (ld->ops->dcd_change) + ld->ops->dcd_change(tty, status); + tty_ldisc_deref(ld); + } + } + + if (status) + wake_up_interruptible(&port->open_wait); + else if (tty && !C_CLOCAL(tty)) + tty_hangup(tty); +} +EXPORT_SYMBOL_GPL(usb_serial_handle_dcd_change); + int usb_serial_generic_resume(struct usb_serial *serial) { struct usb_serial_port *port; @@ -489,14 +608,15 @@ int usb_serial_generic_resume(struct usb_serial *serial) if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags)) continue; - if (port->read_urb) { - r = usb_submit_urb(port->read_urb, GFP_NOIO); + if (port->bulk_in_size) { + r = usb_serial_generic_submit_read_urbs(port, + GFP_NOIO); if (r < 0) c++; } if (port->bulk_out_size) { - r = usb_serial_generic_write_start(port); + r = usb_serial_generic_write_start(port, GFP_NOIO); if (r < 0) c++; } @@ -505,20 +625,3 @@ int usb_serial_generic_resume(struct usb_serial *serial) return c ? -EIO : 0; } EXPORT_SYMBOL_GPL(usb_serial_generic_resume); - -void usb_serial_generic_disconnect(struct usb_serial *serial) -{ - int i; - - dbg("%s", __func__); - - /* stop reads and writes on all ports */ - for (i = 0; i < serial->num_ports; ++i) - generic_cleanup(serial->port[i]); -} -EXPORT_SYMBOL_GPL(usb_serial_generic_disconnect); - -void usb_serial_generic_release(struct usb_serial *serial) -{ - dbg("%s", __func__); -} diff --git a/drivers/usb/serial/hp4x.c b/drivers/usb/serial/hp4x.c deleted file mode 100644 index 809379159b0..00000000000 --- a/drivers/usb/serial/hp4x.c +++ /dev/null @@ -1,86 +0,0 @@ -/* - * HP4x Calculators Serial USB driver - * - * Copyright (C) 2005 Arthur Huillet (ahuillet@users.sf.net) - * Copyright (C) 2001-2005 Greg Kroah-Hartman (greg@kroah.com) - * - * 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. - * - * See Documentation/usb/usb-serial.txt for more information on using this - * driver - */ - -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/tty.h> -#include <linux/module.h> -#include <linux/usb.h> -#include <linux/usb/serial.h> - -/* - * Version Information - */ -#define DRIVER_VERSION "v1.00" -#define DRIVER_DESC "HP4x (48/49) Generic Serial driver" - -#define HP_VENDOR_ID 0x03f0 -#define HP49GP_PRODUCT_ID 0x0121 - -static const struct usb_device_id id_table[] = { - { USB_DEVICE(HP_VENDOR_ID, HP49GP_PRODUCT_ID) }, - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(usb, id_table); - -static struct usb_driver hp49gp_driver = { - .name = "hp4X", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, - .no_dynamic_id = 1, -}; - -static struct usb_serial_driver hp49gp_device = { - .driver = { - .owner = THIS_MODULE, - .name = "hp4X", - }, - .id_table = id_table, - .usb_driver = &hp49gp_driver, - .num_ports = 1, -}; - -static int __init hp49gp_init(void) -{ - int retval; - retval = usb_serial_register(&hp49gp_device); - if (retval) - goto failed_usb_serial_register; - retval = usb_register(&hp49gp_driver); - if (retval) - goto failed_usb_register; - printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" - DRIVER_DESC "\n"); - return 0; -failed_usb_register: - usb_serial_deregister(&hp49gp_device); -failed_usb_serial_register: - return retval; -} - -static void __exit hp49gp_exit(void) -{ - usb_deregister(&hp49gp_driver); - usb_serial_deregister(&hp49gp_device); -} - -module_init(hp49gp_init); -module_exit(hp49gp_exit); - -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_VERSION(DRIVER_VERSION); -MODULE_LICENSE("GPL"); diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index cd769ef24f8..c0866971db2 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -32,7 +32,6 @@ #include <linux/kernel.h> #include <linux/jiffies.h> #include <linux/errno.h> -#include <linux/init.h> #include <linux/slab.h> #include <linux/tty.h> #include <linux/tty_driver.h> @@ -51,18 +50,12 @@ #include "io_ionsp.h" /* info for the iosp messages */ #include "io_16654.h" /* 16654 UART defines */ -/* - * Version Information - */ -#define DRIVER_VERSION "v2.7" #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com> and David Iacovelli" #define DRIVER_DESC "Edgeport USB Serial Driver" #define MAX_NAME_LEN 64 -#define CHASE_TIMEOUT (5*HZ) /* 5 seconds */ #define OPEN_TIMEOUT (5*HZ) /* 5 seconds */ -#define COMMAND_TIMEOUT (5*HZ) /* 5 seconds */ /* receive port state */ enum RXSTATE { @@ -114,9 +107,7 @@ struct edgeport_port { wait_queue_head_t wait_chase; /* for handling sleeping while waiting for chase to finish */ wait_queue_head_t wait_open; /* for handling sleeping while waiting for open to finish */ wait_queue_head_t wait_command; /* for handling sleeping while waiting for command to finish */ - wait_queue_head_t delta_msr_wait; /* for handling sleeping while waiting for msr change to happen */ - struct async_icount icount; struct usb_serial_port *port; /* loop back to the owner of this object */ }; @@ -190,10 +181,8 @@ static const struct divisor_table_entry divisor_table[] = { { 230400, 1}, }; -/* local variables */ -static int debug; - -static atomic_t CmdUrbs; /* Number of outstanding Command Write Urbs */ +/* Number of outstanding Command Write Urbs */ +static atomic_t CmdUrbs = ATOMIC_INIT(0); /* local function prototypes */ @@ -216,17 +205,17 @@ static void edge_unthrottle(struct tty_struct *tty); static void edge_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios); -static int edge_ioctl(struct tty_struct *tty, struct file *file, +static int edge_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg); static void edge_break(struct tty_struct *tty, int break_state); -static int edge_tiocmget(struct tty_struct *tty, struct file *file); -static int edge_tiocmset(struct tty_struct *tty, struct file *file, +static int edge_tiocmget(struct tty_struct *tty); +static int edge_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear); -static int edge_get_icount(struct tty_struct *tty, - struct serial_icounter_struct *icount); static int edge_startup(struct usb_serial *serial); static void edge_disconnect(struct usb_serial *serial); static void edge_release(struct usb_serial *serial); +static int edge_port_probe(struct usb_serial_port *port); +static int edge_port_remove(struct usb_serial_port *port); #include "io_tables.h" /* all of the devices that this driver supports */ @@ -236,14 +225,14 @@ static void process_rcvd_data(struct edgeport_serial *edge_serial, unsigned char *buffer, __u16 bufferLength); static void process_rcvd_status(struct edgeport_serial *edge_serial, __u8 byte2, __u8 byte3); -static void edge_tty_recv(struct device *dev, struct tty_struct *tty, - unsigned char *data, int length); +static void edge_tty_recv(struct usb_serial_port *port, unsigned char *data, + int length); static void handle_new_msr(struct edgeport_port *edge_port, __u8 newMsr); static void handle_new_lsr(struct edgeport_port *edge_port, __u8 lsrData, __u8 lsr, __u8 data); static int send_iosp_ext_cmd(struct edgeport_port *edge_port, __u8 command, __u8 param); -static int calc_baud_rate_divisor(int baud_rate, int *divisor); +static int calc_baud_rate_divisor(struct device *dev, int baud_rate, int *divisor); static int send_cmd_write_baud_rate(struct edgeport_port *edge_port, int baudRate); static void change_port_settings(struct tty_struct *tty, @@ -285,6 +274,7 @@ static void unicode_to_ascii(char *string, int buflen, ************************************************************************/ static void update_edgeport_E2PROM(struct edgeport_serial *edge_serial) { + struct device *dev = &edge_serial->serial->dev->dev; __u32 BootCurVer; __u32 BootNewVer; __u8 BootMajorVersion; @@ -310,7 +300,7 @@ static void update_edgeport_E2PROM(struct edgeport_serial *edge_serial) response = request_ihex_firmware(&fw, fw_name, &edge_serial->serial->dev->dev); if (response) { - printk(KERN_ERR "Failed to load image \"%s\" err %d\n", + dev_err(dev, "Failed to load image \"%s\" err %d\n", fw_name, response); return; } @@ -329,20 +319,20 @@ static void update_edgeport_E2PROM(struct edgeport_serial *edge_serial) (BootMinorVersion << 16) + BootBuildNumber; - dbg("Current Boot Image version %d.%d.%d", + dev_dbg(dev, "Current Boot Image version %d.%d.%d\n", edge_serial->boot_descriptor.MajorVersion, edge_serial->boot_descriptor.MinorVersion, le16_to_cpu(edge_serial->boot_descriptor.BuildNumber)); if (BootNewVer > BootCurVer) { - dbg("**Update Boot Image from %d.%d.%d to %d.%d.%d", + dev_dbg(dev, "**Update Boot Image from %d.%d.%d to %d.%d.%d\n", edge_serial->boot_descriptor.MajorVersion, edge_serial->boot_descriptor.MinorVersion, le16_to_cpu(edge_serial->boot_descriptor.BuildNumber), BootMajorVersion, BootMinorVersion, BootBuildNumber); - dbg("Downloading new Boot Image"); + dev_dbg(dev, "Downloading new Boot Image\n"); for (rec = ihex_next_binrec(rec); rec; rec = ihex_next_binrec(rec)) { @@ -361,7 +351,7 @@ static void update_edgeport_E2PROM(struct edgeport_serial *edge_serial) } } } else { - dbg("Boot Image -- already up to date"); + dev_dbg(dev, "Boot Image -- already up to date\n"); } release_firmware(fw); } @@ -378,7 +368,7 @@ static int get_string_desc(struct usb_device *dev, int Id, struct usb_string_descriptor StringDesc; struct usb_string_descriptor *pStringDesc; - dbg("%s - USB String ID = %d", __func__, Id); + dev_dbg(&dev->dev, "%s - USB String ID = %d\n", __func__, Id); if (!usb_get_descriptor(dev, USB_DT_STRING, Id, &StringDesc, sizeof(StringDesc))) @@ -399,34 +389,39 @@ static int get_string_desc(struct usb_device *dev, int Id, } #endif -static void dump_product_info(struct edgeport_product_info *product_info) +static void dump_product_info(struct edgeport_serial *edge_serial, + struct edgeport_product_info *product_info) { + struct device *dev = &edge_serial->serial->dev->dev; + /* Dump Product Info structure */ - dbg("**Product Information:"); - dbg(" ProductId %x", product_info->ProductId); - dbg(" NumPorts %d", product_info->NumPorts); - dbg(" ProdInfoVer %d", product_info->ProdInfoVer); - dbg(" IsServer %d", product_info->IsServer); - dbg(" IsRS232 %d", product_info->IsRS232); - dbg(" IsRS422 %d", product_info->IsRS422); - dbg(" IsRS485 %d", product_info->IsRS485); - dbg(" RomSize %d", product_info->RomSize); - dbg(" RamSize %d", product_info->RamSize); - dbg(" CpuRev %x", product_info->CpuRev); - dbg(" BoardRev %x", product_info->BoardRev); - dbg(" BootMajorVersion %d.%d.%d", product_info->BootMajorVersion, - product_info->BootMinorVersion, - le16_to_cpu(product_info->BootBuildNumber)); - dbg(" FirmwareMajorVersion %d.%d.%d", - product_info->FirmwareMajorVersion, - product_info->FirmwareMinorVersion, - le16_to_cpu(product_info->FirmwareBuildNumber)); - dbg(" ManufactureDescDate %d/%d/%d", - product_info->ManufactureDescDate[0], - product_info->ManufactureDescDate[1], - product_info->ManufactureDescDate[2]+1900); - dbg(" iDownloadFile 0x%x", product_info->iDownloadFile); - dbg(" EpicVer %d", product_info->EpicVer); + dev_dbg(dev, "**Product Information:\n"); + dev_dbg(dev, " ProductId %x\n", product_info->ProductId); + dev_dbg(dev, " NumPorts %d\n", product_info->NumPorts); + dev_dbg(dev, " ProdInfoVer %d\n", product_info->ProdInfoVer); + dev_dbg(dev, " IsServer %d\n", product_info->IsServer); + dev_dbg(dev, " IsRS232 %d\n", product_info->IsRS232); + dev_dbg(dev, " IsRS422 %d\n", product_info->IsRS422); + dev_dbg(dev, " IsRS485 %d\n", product_info->IsRS485); + dev_dbg(dev, " RomSize %d\n", product_info->RomSize); + dev_dbg(dev, " RamSize %d\n", product_info->RamSize); + dev_dbg(dev, " CpuRev %x\n", product_info->CpuRev); + dev_dbg(dev, " BoardRev %x\n", product_info->BoardRev); + dev_dbg(dev, " BootMajorVersion %d.%d.%d\n", + product_info->BootMajorVersion, + product_info->BootMinorVersion, + le16_to_cpu(product_info->BootBuildNumber)); + dev_dbg(dev, " FirmwareMajorVersion %d.%d.%d\n", + product_info->FirmwareMajorVersion, + product_info->FirmwareMinorVersion, + le16_to_cpu(product_info->FirmwareBuildNumber)); + dev_dbg(dev, " ManufactureDescDate %d/%d/%d\n", + product_info->ManufactureDescDate[0], + product_info->ManufactureDescDate[1], + product_info->ManufactureDescDate[2]+1900); + dev_dbg(dev, " iDownloadFile 0x%x\n", + product_info->iDownloadFile); + dev_dbg(dev, " EpicVer %d\n", product_info->EpicVer); } static void get_product_info(struct edgeport_serial *edge_serial) @@ -461,7 +456,7 @@ static void get_product_info(struct edgeport_serial *edge_serial) product_info->iDownloadFile = EDGE_DOWNLOAD_FILE_80251; else product_info->iDownloadFile = EDGE_DOWNLOAD_FILE_I930; - + /* Determine Product type and set appropriate flags */ switch (DEVICE_ID_FROM_USB_PRODUCT_ID(product_info->ProductId)) { case ION_DEVICE_ID_EDGEPORT_COMPATIBLE: @@ -489,7 +484,7 @@ static void get_product_info(struct edgeport_serial *edge_serial) break; } - dump_product_info(product_info); + dump_product_info(edge_serial, product_info); } static int get_epic_descriptor(struct edgeport_serial *ep) @@ -499,6 +494,7 @@ static int get_epic_descriptor(struct edgeport_serial *ep) struct edgeport_product_info *product_info = &ep->product_info; struct edge_compatibility_descriptor *epic = &ep->epic_descriptor; struct edge_compatibility_bits *bits; + struct device *dev = &serial->dev->dev; ep->is_epic = 0; result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), @@ -508,8 +504,6 @@ static int get_epic_descriptor(struct edgeport_serial *ep) sizeof(struct edge_compatibility_descriptor), 300); - dbg("%s result = %d", __func__, result); - if (result > 0) { ep->is_epic = 1; memset(product_info, 0, sizeof(struct edgeport_product_info)); @@ -523,23 +517,23 @@ static int get_epic_descriptor(struct edgeport_serial *ep) product_info->EpicVer = epic->EpicVer; product_info->Epic = epic->Supports; product_info->ProductId = ION_DEVICE_ID_EDGEPORT_COMPATIBLE; - dump_product_info(product_info); + dump_product_info(ep, product_info); bits = &ep->epic_descriptor.Supports; - dbg("**EPIC descriptor:"); - dbg(" VendEnableSuspend: %s", bits->VendEnableSuspend ? "TRUE": "FALSE"); - dbg(" IOSPOpen : %s", bits->IOSPOpen ? "TRUE": "FALSE"); - dbg(" IOSPClose : %s", bits->IOSPClose ? "TRUE": "FALSE"); - dbg(" IOSPChase : %s", bits->IOSPChase ? "TRUE": "FALSE"); - dbg(" IOSPSetRxFlow : %s", bits->IOSPSetRxFlow ? "TRUE": "FALSE"); - dbg(" IOSPSetTxFlow : %s", bits->IOSPSetTxFlow ? "TRUE": "FALSE"); - dbg(" IOSPSetXChar : %s", bits->IOSPSetXChar ? "TRUE": "FALSE"); - dbg(" IOSPRxCheck : %s", bits->IOSPRxCheck ? "TRUE": "FALSE"); - dbg(" IOSPSetClrBreak : %s", bits->IOSPSetClrBreak ? "TRUE": "FALSE"); - dbg(" IOSPWriteMCR : %s", bits->IOSPWriteMCR ? "TRUE": "FALSE"); - dbg(" IOSPWriteLCR : %s", bits->IOSPWriteLCR ? "TRUE": "FALSE"); - dbg(" IOSPSetBaudRate : %s", bits->IOSPSetBaudRate ? "TRUE": "FALSE"); - dbg(" TrueEdgeport : %s", bits->TrueEdgeport ? "TRUE": "FALSE"); + dev_dbg(dev, "**EPIC descriptor:\n"); + dev_dbg(dev, " VendEnableSuspend: %s\n", bits->VendEnableSuspend ? "TRUE": "FALSE"); + dev_dbg(dev, " IOSPOpen : %s\n", bits->IOSPOpen ? "TRUE": "FALSE"); + dev_dbg(dev, " IOSPClose : %s\n", bits->IOSPClose ? "TRUE": "FALSE"); + dev_dbg(dev, " IOSPChase : %s\n", bits->IOSPChase ? "TRUE": "FALSE"); + dev_dbg(dev, " IOSPSetRxFlow : %s\n", bits->IOSPSetRxFlow ? "TRUE": "FALSE"); + dev_dbg(dev, " IOSPSetTxFlow : %s\n", bits->IOSPSetTxFlow ? "TRUE": "FALSE"); + dev_dbg(dev, " IOSPSetXChar : %s\n", bits->IOSPSetXChar ? "TRUE": "FALSE"); + dev_dbg(dev, " IOSPRxCheck : %s\n", bits->IOSPRxCheck ? "TRUE": "FALSE"); + dev_dbg(dev, " IOSPSetClrBreak : %s\n", bits->IOSPSetClrBreak ? "TRUE": "FALSE"); + dev_dbg(dev, " IOSPWriteMCR : %s\n", bits->IOSPWriteMCR ? "TRUE": "FALSE"); + dev_dbg(dev, " IOSPWriteLCR : %s\n", bits->IOSPWriteLCR ? "TRUE": "FALSE"); + dev_dbg(dev, " IOSPSetBaudRate : %s\n", bits->IOSPSetBaudRate ? "TRUE": "FALSE"); + dev_dbg(dev, " TrueEdgeport : %s\n", bits->TrueEdgeport ? "TRUE": "FALSE"); } return result; @@ -560,10 +554,10 @@ static int get_epic_descriptor(struct edgeport_serial *ep) *****************************************************************************/ static void edge_interrupt_callback(struct urb *urb) { - struct edgeport_serial *edge_serial = urb->context; + struct edgeport_serial *edge_serial = urb->context; + struct device *dev; struct edgeport_port *edge_port; struct usb_serial_port *port; - struct tty_struct *tty; unsigned char *data = urb->transfer_buffer; int length = urb->actual_length; int bytes_avail; @@ -573,8 +567,6 @@ static void edge_interrupt_callback(struct urb *urb) int result; int status = urb->status; - dbg("%s", __func__); - switch (status) { case 0: /* success */ @@ -583,37 +575,42 @@ static void edge_interrupt_callback(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", - __func__, status); + dev_dbg(&urb->dev->dev, "%s - urb shutting down with status: %d\n", __func__, status); return; default: - dbg("%s - nonzero urb status received: %d", __func__, status); + dev_dbg(&urb->dev->dev, "%s - nonzero urb status received: %d\n", __func__, status); goto exit; } + dev = &edge_serial->serial->dev->dev; + /* process this interrupt-read even if there are no ports open */ if (length) { - usb_serial_debug_data(debug, &edge_serial->serial->dev->dev, - __func__, length, data); + usb_serial_debug_data(dev, __func__, length, data); if (length > 1) { bytes_avail = data[0] | (data[1] << 8); if (bytes_avail) { spin_lock(&edge_serial->es_lock); edge_serial->rxBytesAvail += bytes_avail; - dbg("%s - bytes_avail=%d, rxBytesAvail=%d, read_in_progress=%d", __func__, bytes_avail, edge_serial->rxBytesAvail, edge_serial->read_in_progress); + dev_dbg(dev, + "%s - bytes_avail=%d, rxBytesAvail=%d, read_in_progress=%d\n", + __func__, bytes_avail, + edge_serial->rxBytesAvail, + edge_serial->read_in_progress); if (edge_serial->rxBytesAvail > 0 && !edge_serial->read_in_progress) { - dbg("%s - posting a read", __func__); + dev_dbg(dev, "%s - posting a read\n", __func__); edge_serial->read_in_progress = true; /* we have pending bytes on the bulk in pipe, send a request */ - edge_serial->read_urb->dev = edge_serial->serial->dev; result = usb_submit_urb(edge_serial->read_urb, GFP_ATOMIC); if (result) { - dev_err(&edge_serial->serial->dev->dev, "%s - usb_submit_urb(read bulk) failed with result = %d\n", __func__, result); + dev_err(dev, + "%s - usb_submit_urb(read bulk) failed with result = %d\n", + __func__, result); edge_serial->read_in_progress = false; } } @@ -633,18 +630,13 @@ static void edge_interrupt_callback(struct urb *urb) spin_lock(&edge_port->ep_lock); edge_port->txCredits += txCredits; spin_unlock(&edge_port->ep_lock); - dbg("%s - txcredits for port%d = %d", - __func__, portNumber, - edge_port->txCredits); + dev_dbg(dev, "%s - txcredits for port%d = %d\n", + __func__, portNumber, + edge_port->txCredits); /* tell the tty driver that something has changed */ - tty = tty_port_tty_get( - &edge_port->port->port); - if (tty) { - tty_wakeup(tty); - tty_kref_put(tty); - } + tty_port_tty_wakeup(&edge_port->port->port); /* Since we have more credit, check if more data can be sent */ send_more_port_data(edge_serial, @@ -673,50 +665,48 @@ exit: static void edge_bulk_in_callback(struct urb *urb) { struct edgeport_serial *edge_serial = urb->context; + struct device *dev; unsigned char *data = urb->transfer_buffer; int retval; __u16 raw_data_length; int status = urb->status; - dbg("%s", __func__); - if (status) { - dbg("%s - nonzero read bulk status received: %d", - __func__, status); + dev_dbg(&urb->dev->dev, "%s - nonzero read bulk status received: %d\n", + __func__, status); edge_serial->read_in_progress = false; return; } if (urb->actual_length == 0) { - dbg("%s - read bulk callback with no data", __func__); + dev_dbg(&urb->dev->dev, "%s - read bulk callback with no data\n", __func__); edge_serial->read_in_progress = false; return; } + dev = &edge_serial->serial->dev->dev; raw_data_length = urb->actual_length; - usb_serial_debug_data(debug, &edge_serial->serial->dev->dev, - __func__, raw_data_length, data); + usb_serial_debug_data(dev, __func__, raw_data_length, data); spin_lock(&edge_serial->es_lock); /* decrement our rxBytes available by the number that we just got */ edge_serial->rxBytesAvail -= raw_data_length; - dbg("%s - Received = %d, rxBytesAvail %d", __func__, - raw_data_length, edge_serial->rxBytesAvail); + dev_dbg(dev, "%s - Received = %d, rxBytesAvail %d\n", __func__, + raw_data_length, edge_serial->rxBytesAvail); process_rcvd_data(edge_serial, data, urb->actual_length); /* check to see if there's any more data for us to read */ if (edge_serial->rxBytesAvail > 0) { - dbg("%s - posting a read", __func__); - edge_serial->read_urb->dev = edge_serial->serial->dev; + dev_dbg(dev, "%s - posting a read\n", __func__); retval = usb_submit_urb(edge_serial->read_urb, GFP_ATOMIC); if (retval) { - dev_err(&urb->dev->dev, - "%s - usb_submit_urb(read bulk) failed, " - "retval = %d\n", __func__, retval); + dev_err(dev, + "%s - usb_submit_urb(read bulk) failed, retval = %d\n", + __func__, retval); edge_serial->read_in_progress = false; } } else { @@ -735,24 +725,16 @@ static void edge_bulk_in_callback(struct urb *urb) static void edge_bulk_out_data_callback(struct urb *urb) { struct edgeport_port *edge_port = urb->context; - struct tty_struct *tty; int status = urb->status; - dbg("%s", __func__); - if (status) { - dbg("%s - nonzero write bulk status received: %d", - __func__, status); + dev_dbg(&urb->dev->dev, + "%s - nonzero write bulk status received: %d\n", + __func__, status); } - tty = tty_port_tty_get(&edge_port->port->port); - - if (tty && edge_port->open) { - /* let the tty driver wakeup if it has a special - write_wakeup function */ - tty_wakeup(tty); - } - tty_kref_put(tty); + if (edge_port->open) + tty_port_tty_wakeup(&edge_port->port->port); /* Release the Write URB */ edge_port->write_in_progress = false; @@ -771,14 +753,11 @@ static void edge_bulk_out_data_callback(struct urb *urb) static void edge_bulk_out_cmd_callback(struct urb *urb) { struct edgeport_port *edge_port = urb->context; - struct tty_struct *tty; int status = urb->status; - dbg("%s", __func__); - atomic_dec(&CmdUrbs); - dbg("%s - FREE URB %p (outstanding %d)", __func__, - urb, atomic_read(&CmdUrbs)); + dev_dbg(&urb->dev->dev, "%s - FREE URB %p (outstanding %d)\n", + __func__, urb, atomic_read(&CmdUrbs)); /* clean up the transfer buffer */ @@ -788,18 +767,15 @@ static void edge_bulk_out_cmd_callback(struct urb *urb) usb_free_urb(urb); if (status) { - dbg("%s - nonzero write bulk status received: %d", - __func__, status); + dev_dbg(&urb->dev->dev, + "%s - nonzero write bulk status received: %d\n", + __func__, status); return; } - /* Get pointer to tty */ - tty = tty_port_tty_get(&edge_port->port->port); - /* tell the tty driver that something has changed */ - if (tty && edge_port->open) - tty_wakeup(tty); - tty_kref_put(tty); + if (edge_port->open) + tty_port_tty_wakeup(&edge_port->port->port); /* we have completed the command */ edge_port->commandPending = false; @@ -820,12 +796,11 @@ static void edge_bulk_out_cmd_callback(struct urb *urb) static int edge_open(struct tty_struct *tty, struct usb_serial_port *port) { struct edgeport_port *edge_port = usb_get_serial_port_data(port); + struct device *dev = &port->dev; struct usb_serial *serial; struct edgeport_serial *edge_serial; int response; - dbg("%s - port %d", __func__, port->number); - if (edge_port == NULL) return -ENODEV; @@ -876,21 +851,16 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port) response = usb_submit_urb(edge_serial->interrupt_read_urb, GFP_KERNEL); if (response) { - dev_err(&port->dev, - "%s - Error %d submitting control urb\n", - __func__, response); + dev_err(dev, "%s - Error %d submitting control urb\n", + __func__, response); } } /* initialize our wait queues */ init_waitqueue_head(&edge_port->wait_open); init_waitqueue_head(&edge_port->wait_chase); - init_waitqueue_head(&edge_port->delta_msr_wait); init_waitqueue_head(&edge_port->wait_command); - /* initialize our icount structure */ - memset(&(edge_port->icount), 0x00, sizeof(edge_port->icount)); - /* initialize our port settings */ edge_port->txCredits = 0; /* Can't send any data yet */ /* Must always set this bit to enable ints! */ @@ -903,8 +873,7 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port) response = send_iosp_ext_cmd(edge_port, IOSP_CMD_OPEN_PORT, 0); if (response < 0) { - dev_err(&port->dev, "%s - error sending open port command\n", - __func__); + dev_err(dev, "%s - error sending open port command\n", __func__); edge_port->openPending = false; return -ENODEV; } @@ -915,7 +884,7 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port) if (!edge_port->open) { /* open timed out */ - dbg("%s - open timedout", __func__); + dev_dbg(dev, "%s - open timedout\n", __func__); edge_port->openPending = false; return -ENODEV; } @@ -928,7 +897,6 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port) edge_port->txfifo.fifo = kmalloc(edge_port->maxTxCredits, GFP_KERNEL); if (!edge_port->txfifo.fifo) { - dbg("%s - no memory", __func__); edge_close(port); return -ENOMEM; } @@ -938,15 +906,12 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port) edge_port->write_in_progress = false; if (!edge_port->write_urb) { - dbg("%s - no memory", __func__); edge_close(port); return -ENOMEM; } - dbg("%s(%d) - Initialize TX fifo to %d bytes", - __func__, port->number, edge_port->maxTxCredits); - - dbg("%s exited", __func__); + dev_dbg(dev, "%s - Initialize TX fifo to %d bytes\n", + __func__, edge_port->maxTxCredits); return 0; } @@ -964,6 +929,7 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port) ************************************************************************/ static void block_until_chase_response(struct edgeport_port *edge_port) { + struct device *dev = &edge_port->port->dev; DEFINE_WAIT(wait); __u16 lastCredits; int timeout = 1*HZ; @@ -975,11 +941,11 @@ static void block_until_chase_response(struct edgeport_port *edge_port) /* Did we get our Chase response */ if (!edge_port->chaseResponsePending) { - dbg("%s - Got Chase Response", __func__); + dev_dbg(dev, "%s - Got Chase Response\n", __func__); /* did we get all of our credit back? */ if (edge_port->txCredits == edge_port->maxTxCredits) { - dbg("%s - Got all credits", __func__); + dev_dbg(dev, "%s - Got all credits\n", __func__); return; } } @@ -995,12 +961,12 @@ static void block_until_chase_response(struct edgeport_port *edge_port) loop--; if (loop == 0) { edge_port->chaseResponsePending = false; - dbg("%s - Chase TIMEOUT", __func__); + dev_dbg(dev, "%s - Chase TIMEOUT\n", __func__); return; } } else { /* Reset timeout value back to 10 seconds */ - dbg("%s - Last %d, Current %d", __func__, + dev_dbg(dev, "%s - Last %d, Current %d\n", __func__, lastCredits, edge_port->txCredits); loop = 10; } @@ -1020,6 +986,7 @@ static void block_until_chase_response(struct edgeport_port *edge_port) ************************************************************************/ static void block_until_tx_empty(struct edgeport_port *edge_port) { + struct device *dev = &edge_port->port->dev; DEFINE_WAIT(wait); struct TxFifo *fifo = &edge_port->txfifo; __u32 lastCount; @@ -1032,7 +999,7 @@ static void block_until_tx_empty(struct edgeport_port *edge_port) /* Is the Edgeport Buffer empty? */ if (lastCount == 0) { - dbg("%s - TX Buffer Empty", __func__); + dev_dbg(dev, "%s - TX Buffer Empty\n", __func__); return; } @@ -1042,13 +1009,13 @@ static void block_until_tx_empty(struct edgeport_port *edge_port) schedule_timeout(timeout); finish_wait(&edge_port->wait_chase, &wait); - dbg("%s wait", __func__); + dev_dbg(dev, "%s wait\n", __func__); if (lastCount == fifo->count) { /* No activity.. count down. */ loop--; if (loop == 0) { - dbg("%s - TIMEOUT", __func__); + dev_dbg(dev, "%s - TIMEOUT\n", __func__); return; } } else { @@ -1069,8 +1036,6 @@ static void edge_close(struct usb_serial_port *port) struct edgeport_port *edge_port; int status; - dbg("%s - port %d", __func__, port->number); - edge_serial = usb_get_serial_data(port->serial); edge_port = usb_get_serial_port_data(port); if (edge_serial == NULL || edge_port == NULL) @@ -1087,7 +1052,7 @@ static void edge_close(struct usb_serial_port *port) /* flush and chase */ edge_port->chaseResponsePending = true; - dbg("%s - Sending IOSP_CMD_CHASE_PORT", __func__); + dev_dbg(&port->dev, "%s - Sending IOSP_CMD_CHASE_PORT\n", __func__); status = send_iosp_ext_cmd(edge_port, IOSP_CMD_CHASE_PORT, 0); if (status == 0) /* block until chase finished */ @@ -1100,7 +1065,7 @@ static void edge_close(struct usb_serial_port *port) ((edge_serial->is_epic) && (edge_serial->epic_descriptor.Supports.IOSPClose))) { /* close the port */ - dbg("%s - Sending IOSP_CMD_CLOSE_PORT", __func__); + dev_dbg(&port->dev, "%s - Sending IOSP_CMD_CLOSE_PORT\n", __func__); send_iosp_ext_cmd(edge_port, IOSP_CMD_CLOSE_PORT, 0); } @@ -1120,8 +1085,6 @@ static void edge_close(struct usb_serial_port *port) } kfree(edge_port->txfifo.fifo); edge_port->txfifo.fifo = NULL; - - dbg("%s exited", __func__); } /***************************************************************************** @@ -1142,8 +1105,6 @@ static int edge_write(struct tty_struct *tty, struct usb_serial_port *port, int secondhalf; unsigned long flags; - dbg("%s - port %d", __func__, port->number); - if (edge_port == NULL) return -ENODEV; @@ -1156,14 +1117,13 @@ static int edge_write(struct tty_struct *tty, struct usb_serial_port *port, copySize = min((unsigned int)count, (edge_port->txCredits - fifo->count)); - dbg("%s(%d) of %d byte(s) Fifo room %d -- will copy %d bytes", - __func__, port->number, count, - edge_port->txCredits - fifo->count, copySize); + dev_dbg(&port->dev, "%s of %d byte(s) Fifo room %d -- will copy %d bytes\n", + __func__, count, edge_port->txCredits - fifo->count, copySize); /* catch writes of 0 bytes which the tty driver likes to give us, and when txCredits is empty */ if (copySize == 0) { - dbg("%s - copySize = Zero", __func__); + dev_dbg(&port->dev, "%s - copySize = Zero\n", __func__); goto finish_write; } @@ -1176,13 +1136,12 @@ static int edge_write(struct tty_struct *tty, struct usb_serial_port *port, */ bytesleft = fifo->size - fifo->head; firsthalf = min(bytesleft, copySize); - dbg("%s - copy %d bytes of %d into fifo ", __func__, - firsthalf, bytesleft); + dev_dbg(&port->dev, "%s - copy %d bytes of %d into fifo \n", __func__, + firsthalf, bytesleft); /* now copy our data */ memcpy(&fifo->fifo[fifo->head], data, firsthalf); - usb_serial_debug_data(debug, &port->dev, __func__, - firsthalf, &fifo->fifo[fifo->head]); + usb_serial_debug_data(&port->dev, __func__, firsthalf, &fifo->fifo[fifo->head]); /* update the index and size */ fifo->head += firsthalf; @@ -1195,10 +1154,9 @@ static int edge_write(struct tty_struct *tty, struct usb_serial_port *port, secondhalf = copySize-firsthalf; if (secondhalf) { - dbg("%s - copy rest of data %d", __func__, secondhalf); + dev_dbg(&port->dev, "%s - copy rest of data %d\n", __func__, secondhalf); memcpy(&fifo->fifo[fifo->head], &data[firsthalf], secondhalf); - usb_serial_debug_data(debug, &port->dev, __func__, - secondhalf, &fifo->fifo[fifo->head]); + usb_serial_debug_data(&port->dev, __func__, secondhalf, &fifo->fifo[fifo->head]); /* update the index and size */ fifo->count += secondhalf; fifo->head += secondhalf; @@ -1213,8 +1171,8 @@ finish_write: send_more_port_data((struct edgeport_serial *) usb_get_serial_data(port->serial), edge_port); - dbg("%s wrote %d byte(s) TxCredits %d, Fifo %d", __func__, - copySize, edge_port->txCredits, fifo->count); + dev_dbg(&port->dev, "%s wrote %d byte(s) TxCredits %d, Fifo %d\n", + __func__, copySize, edge_port->txCredits, fifo->count); return copySize; } @@ -1237,6 +1195,7 @@ static void send_more_port_data(struct edgeport_serial *edge_serial, struct edgeport_port *edge_port) { struct TxFifo *fifo = &edge_port->txfifo; + struct device *dev = &edge_port->port->dev; struct urb *urb; unsigned char *buffer; int status; @@ -1246,16 +1205,13 @@ static void send_more_port_data(struct edgeport_serial *edge_serial, int secondhalf; unsigned long flags; - dbg("%s(%d)", __func__, edge_port->port->number); - spin_lock_irqsave(&edge_port->ep_lock, flags); if (edge_port->write_in_progress || !edge_port->open || (fifo->count == 0)) { - dbg("%s(%d) EXIT - fifo %d, PendingWrite = %d", - __func__, edge_port->port->number, - fifo->count, edge_port->write_in_progress); + dev_dbg(dev, "%s EXIT - fifo %d, PendingWrite = %d\n", + __func__, fifo->count, edge_port->write_in_progress); goto exit_send; } @@ -1267,9 +1223,8 @@ static void send_more_port_data(struct edgeport_serial *edge_serial, * it's better to wait for more credits so we can do a larger write. */ if (edge_port->txCredits < EDGE_FW_GET_TX_CREDITS_SEND_THRESHOLD(edge_port->maxTxCredits, EDGE_FW_BULK_MAX_PACKET_SIZE)) { - dbg("%s(%d) Not enough credit - fifo %d TxCredit %d", - __func__, edge_port->port->number, fifo->count, - edge_port->txCredits); + dev_dbg(dev, "%s Not enough credit - fifo %d TxCredit %d\n", + __func__, fifo->count, edge_port->txCredits); goto exit_send; } @@ -1287,16 +1242,12 @@ static void send_more_port_data(struct edgeport_serial *edge_serial, to send out */ count = fifo->count; buffer = kmalloc(count+2, GFP_ATOMIC); - if (buffer == NULL) { - dev_err(&edge_port->port->dev, - "%s - no more kernel memory...\n", __func__); + if (!buffer) { edge_port->write_in_progress = false; goto exit_send; } - buffer[0] = IOSP_BUILD_DATA_HDR1(edge_port->port->number - - edge_port->port->serial->minor, count); - buffer[1] = IOSP_BUILD_DATA_HDR2(edge_port->port->number - - edge_port->port->serial->minor, count); + buffer[0] = IOSP_BUILD_DATA_HDR1(edge_port->port->port_number, count); + buffer[1] = IOSP_BUILD_DATA_HDR2(edge_port->port->port_number, count); /* now copy our data */ bytesleft = fifo->size - fifo->tail; @@ -1316,8 +1267,7 @@ static void send_more_port_data(struct edgeport_serial *edge_serial, } if (count) - usb_serial_debug_data(debug, &edge_port->port->dev, - __func__, count, &buffer[2]); + usb_serial_debug_data(&edge_port->port->dev, __func__, count, &buffer[2]); /* fill up the urb with all of our data and submit it */ usb_fill_bulk_urb(urb, edge_serial->serial->dev, @@ -1328,23 +1278,22 @@ static void send_more_port_data(struct edgeport_serial *edge_serial, /* decrement the number of credits we have by the number we just sent */ edge_port->txCredits -= count; - edge_port->icount.tx += count; + edge_port->port->icount.tx += count; - urb->dev = edge_serial->serial->dev; status = usb_submit_urb(urb, GFP_ATOMIC); if (status) { /* something went wrong */ - dev_err(&edge_port->port->dev, + dev_err_console(edge_port->port, "%s - usb_submit_urb(write bulk) failed, status = %d, data lost\n", __func__, status); edge_port->write_in_progress = false; /* revert the credits as something bad happened. */ edge_port->txCredits += count; - edge_port->icount.tx -= count; + edge_port->port->icount.tx -= count; } - dbg("%s wrote %d byte(s) TxCredit %d, Fifo %d", - __func__, count, edge_port->txCredits, fifo->count); + dev_dbg(dev, "%s wrote %d byte(s) TxCredit %d, Fifo %d\n", + __func__, count, edge_port->txCredits, fifo->count); exit_send: spin_unlock_irqrestore(&edge_port->ep_lock, flags); @@ -1365,17 +1314,13 @@ static int edge_write_room(struct tty_struct *tty) int room; unsigned long flags; - dbg("%s", __func__); - if (edge_port == NULL) return 0; if (edge_port->closePending) return 0; - dbg("%s - port %d", __func__, port->number); - if (!edge_port->open) { - dbg("%s - port not opened", __func__); + dev_dbg(&port->dev, "%s - port not opened\n", __func__); return 0; } @@ -1384,7 +1329,7 @@ static int edge_write_room(struct tty_struct *tty) room = edge_port->txCredits - edge_port->txfifo.count; spin_unlock_irqrestore(&edge_port->ep_lock, flags); - dbg("%s - returns %d", __func__, room); + dev_dbg(&port->dev, "%s - returns %d\n", __func__, room); return room; } @@ -1405,15 +1350,13 @@ static int edge_chars_in_buffer(struct tty_struct *tty) int num_chars; unsigned long flags; - dbg("%s", __func__); - if (edge_port == NULL) return 0; if (edge_port->closePending) return 0; if (!edge_port->open) { - dbg("%s - port not opened", __func__); + dev_dbg(&port->dev, "%s - port not opened\n", __func__); return 0; } @@ -1422,8 +1365,7 @@ static int edge_chars_in_buffer(struct tty_struct *tty) edge_port->txfifo.count; spin_unlock_irqrestore(&edge_port->ep_lock, flags); if (num_chars) { - dbg("%s(port %d) - returns %d", __func__, - port->number, num_chars); + dev_dbg(&port->dev, "%s - returns %d\n", __func__, num_chars); } return num_chars; @@ -1441,13 +1383,11 @@ static void edge_throttle(struct tty_struct *tty) struct edgeport_port *edge_port = usb_get_serial_port_data(port); int status; - dbg("%s - port %d", __func__, port->number); - if (edge_port == NULL) return; if (!edge_port->open) { - dbg("%s - port not opened", __func__); + dev_dbg(&port->dev, "%s - port not opened\n", __func__); return; } @@ -1460,7 +1400,7 @@ static void edge_throttle(struct tty_struct *tty) } /* if we are implementing RTS/CTS, toggle that line */ - if (tty->termios->c_cflag & CRTSCTS) { + if (tty->termios.c_cflag & CRTSCTS) { edge_port->shadowMCR &= ~MCR_RTS; status = send_cmd_write_uart_register(edge_port, MCR, edge_port->shadowMCR); @@ -1481,13 +1421,11 @@ static void edge_unthrottle(struct tty_struct *tty) struct edgeport_port *edge_port = usb_get_serial_port_data(port); int status; - dbg("%s - port %d", __func__, port->number); - if (edge_port == NULL) return; if (!edge_port->open) { - dbg("%s - port not opened", __func__); + dev_dbg(&port->dev, "%s - port not opened\n", __func__); return; } @@ -1499,7 +1437,7 @@ static void edge_unthrottle(struct tty_struct *tty) return; } /* if we are implementing RTS/CTS, toggle that line */ - if (tty->termios->c_cflag & CRTSCTS) { + if (tty->termios.c_cflag & CRTSCTS) { edge_port->shadowMCR |= MCR_RTS; send_cmd_write_uart_register(edge_port, MCR, edge_port->shadowMCR); @@ -1518,19 +1456,15 @@ static void edge_set_termios(struct tty_struct *tty, struct edgeport_port *edge_port = usb_get_serial_port_data(port); unsigned int cflag; - cflag = tty->termios->c_cflag; - dbg("%s - clfag %08x iflag %08x", __func__, - tty->termios->c_cflag, tty->termios->c_iflag); - dbg("%s - old clfag %08x old iflag %08x", __func__, - old_termios->c_cflag, old_termios->c_iflag); - - dbg("%s - port %d", __func__, port->number); + cflag = tty->termios.c_cflag; + dev_dbg(&port->dev, "%s - clfag %08x iflag %08x\n", __func__, tty->termios.c_cflag, tty->termios.c_iflag); + dev_dbg(&port->dev, "%s - old clfag %08x old iflag %08x\n", __func__, old_termios->c_cflag, old_termios->c_iflag); if (edge_port == NULL) return; if (!edge_port->open) { - dbg("%s - port not opened", __func__); + dev_dbg(&port->dev, "%s - port not opened\n", __func__); return; } @@ -1558,7 +1492,7 @@ static int get_lsr_info(struct edgeport_port *edge_port, spin_lock_irqsave(&edge_port->ep_lock, flags); if (edge_port->maxTxCredits == edge_port->txCredits && edge_port->txfifo.count == 0) { - dbg("%s -- Empty", __func__); + dev_dbg(&edge_port->port->dev, "%s -- Empty\n", __func__); result = TIOCSER_TEMT; } spin_unlock_irqrestore(&edge_port->ep_lock, flags); @@ -1568,15 +1502,13 @@ static int get_lsr_info(struct edgeport_port *edge_port, return 0; } -static int edge_tiocmset(struct tty_struct *tty, struct file *file, +static int edge_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) { struct usb_serial_port *port = tty->driver_data; struct edgeport_port *edge_port = usb_get_serial_port_data(port); unsigned int mcr; - dbg("%s - port %d", __func__, port->number); - mcr = edge_port->shadowMCR; if (set & TIOCM_RTS) mcr |= MCR_RTS; @@ -1599,7 +1531,7 @@ static int edge_tiocmset(struct tty_struct *tty, struct file *file, return 0; } -static int edge_tiocmget(struct tty_struct *tty, struct file *file) +static int edge_tiocmget(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; struct edgeport_port *edge_port = usb_get_serial_port_data(port); @@ -1607,8 +1539,6 @@ static int edge_tiocmget(struct tty_struct *tty, struct file *file) unsigned int msr; unsigned int mcr; - dbg("%s - port %d", __func__, port->number); - msr = edge_port->shadowMSR; mcr = edge_port->shadowMCR; result = ((mcr & MCR_DTR) ? TIOCM_DTR: 0) /* 0x002 */ @@ -1618,37 +1548,9 @@ static int edge_tiocmget(struct tty_struct *tty, struct file *file) | ((msr & EDGEPORT_MSR_RI) ? TIOCM_RI: 0) /* 0x080 */ | ((msr & EDGEPORT_MSR_DSR) ? TIOCM_DSR: 0); /* 0x100 */ - - dbg("%s -- %x", __func__, result); - return result; } -static int edge_get_icount(struct tty_struct *tty, - struct serial_icounter_struct *icount) -{ - struct usb_serial_port *port = tty->driver_data; - struct edgeport_port *edge_port = usb_get_serial_port_data(port); - struct async_icount cnow; - cnow = edge_port->icount; - - icount->cts = cnow.cts; - icount->dsr = cnow.dsr; - icount->rng = cnow.rng; - icount->dcd = cnow.dcd; - icount->rx = cnow.rx; - icount->tx = cnow.tx; - icount->frame = cnow.frame; - icount->overrun = cnow.overrun; - icount->parity = cnow.parity; - icount->brk = cnow.brk; - icount->buf_overrun = cnow.buf_overrun; - - dbg("%s (%d) TIOCGICOUNT RX=%d, TX=%d", - __func__, port->number, icount->rx, icount->tx); - return 0; -} - static int get_serial_info(struct edgeport_port *edge_port, struct serial_struct __user *retinfo) { @@ -1660,8 +1562,8 @@ static int get_serial_info(struct edgeport_port *edge_port, memset(&tmp, 0, sizeof(tmp)); tmp.type = PORT_16550A; - tmp.line = edge_port->port->serial->minor; - tmp.port = edge_port->port->number; + tmp.line = edge_port->port->minor; + tmp.port = edge_port->port->port_number; tmp.irq = 0; tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ; tmp.xmit_fifo_size = edge_port->maxTxCredits; @@ -1679,52 +1581,21 @@ static int get_serial_info(struct edgeport_port *edge_port, * SerialIoctl * this function handles any ioctl calls to the driver *****************************************************************************/ -static int edge_ioctl(struct tty_struct *tty, struct file *file, +static int edge_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { struct usb_serial_port *port = tty->driver_data; DEFINE_WAIT(wait); struct edgeport_port *edge_port = usb_get_serial_port_data(port); - struct async_icount cnow; - struct async_icount cprev; - - dbg("%s - port %d, cmd = 0x%x", __func__, port->number, cmd); switch (cmd) { case TIOCSERGETLSR: - dbg("%s (%d) TIOCSERGETLSR", __func__, port->number); + dev_dbg(&port->dev, "%s TIOCSERGETLSR\n", __func__); return get_lsr_info(edge_port, (unsigned int __user *) arg); case TIOCGSERIAL: - dbg("%s (%d) TIOCGSERIAL", __func__, port->number); + dev_dbg(&port->dev, "%s TIOCGSERIAL\n", __func__); return get_serial_info(edge_port, (struct serial_struct __user *) arg); - - case TIOCMIWAIT: - dbg("%s (%d) TIOCMIWAIT", __func__, port->number); - cprev = edge_port->icount; - while (1) { - prepare_to_wait(&edge_port->delta_msr_wait, - &wait, TASK_INTERRUPTIBLE); - schedule(); - finish_wait(&edge_port->delta_msr_wait, &wait); - /* see if a signal did it */ - if (signal_pending(current)) - return -ERESTARTSYS; - cnow = edge_port->icount; - if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && - cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) - return -EIO; /* no change => error */ - if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || - ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || - ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || - ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) { - return 0; - } - cprev = cnow; - } - /* NOTREACHED */ - break; - } return -ENOIOCTLCMD; } @@ -1747,7 +1618,7 @@ static void edge_break(struct tty_struct *tty, int break_state) /* flush and chase */ edge_port->chaseResponsePending = true; - dbg("%s - Sending IOSP_CMD_CHASE_PORT", __func__); + dev_dbg(&port->dev, "%s - Sending IOSP_CMD_CHASE_PORT\n", __func__); status = send_iosp_ext_cmd(edge_port, IOSP_CMD_CHASE_PORT, 0); if (status == 0) { /* block until chase finished */ @@ -1761,16 +1632,16 @@ static void edge_break(struct tty_struct *tty, int break_state) ((edge_serial->is_epic) && (edge_serial->epic_descriptor.Supports.IOSPSetClrBreak))) { if (break_state == -1) { - dbg("%s - Sending IOSP_CMD_SET_BREAK", __func__); + dev_dbg(&port->dev, "%s - Sending IOSP_CMD_SET_BREAK\n", __func__); status = send_iosp_ext_cmd(edge_port, IOSP_CMD_SET_BREAK, 0); } else { - dbg("%s - Sending IOSP_CMD_CLEAR_BREAK", __func__); + dev_dbg(&port->dev, "%s - Sending IOSP_CMD_CLEAR_BREAK\n", __func__); status = send_iosp_ext_cmd(edge_port, IOSP_CMD_CLEAR_BREAK, 0); } if (status) - dbg("%s - error sending break set/clear command.", + dev_dbg(&port->dev, "%s - error sending break set/clear command.\n", __func__); } } @@ -1783,20 +1654,18 @@ static void edge_break(struct tty_struct *tty, int break_state) static void process_rcvd_data(struct edgeport_serial *edge_serial, unsigned char *buffer, __u16 bufferLength) { + struct device *dev = &edge_serial->serial->dev->dev; struct usb_serial_port *port; struct edgeport_port *edge_port; - struct tty_struct *tty; __u16 lastBufferLength; __u16 rxLen; - dbg("%s", __func__); - lastBufferLength = bufferLength + 1; while (bufferLength > 0) { /* failsafe incase we get a message that we don't understand */ if (lastBufferLength == bufferLength) { - dbg("%s - stuck in loop, exiting it.", __func__); + dev_dbg(dev, "%s - stuck in loop, exiting it.\n", __func__); break; } lastBufferLength = bufferLength; @@ -1817,8 +1686,8 @@ static void process_rcvd_data(struct edgeport_serial *edge_serial, ++buffer; --bufferLength; - dbg("%s - Hdr1=%02X Hdr2=%02X", __func__, - edge_serial->rxHeader1, edge_serial->rxHeader2); + dev_dbg(dev, "%s - Hdr1=%02X Hdr2=%02X\n", __func__, + edge_serial->rxHeader1, edge_serial->rxHeader2); /* Process depending on whether this header is * data or status */ @@ -1857,10 +1726,10 @@ static void process_rcvd_data(struct edgeport_serial *edge_serial, IOSP_GET_HDR_DATA_LEN( edge_serial->rxHeader1, edge_serial->rxHeader2); - dbg("%s - Data for Port %u Len %u", - __func__, - edge_serial->rxPort, - edge_serial->rxBytesRemaining); + dev_dbg(dev, "%s - Data for Port %u Len %u\n", + __func__, + edge_serial->rxPort, + edge_serial->rxBytesRemaining); /* ASSERT(DevExt->RxPort < DevExt->NumPorts); * ASSERT(DevExt->RxBytesRemaining < @@ -1895,15 +1764,12 @@ static void process_rcvd_data(struct edgeport_serial *edge_serial, edge_serial->rxPort]; edge_port = usb_get_serial_port_data(port); if (edge_port->open) { - tty = tty_port_tty_get( - &edge_port->port->port); - if (tty) { - dbg("%s - Sending %d bytes to TTY for port %d", - __func__, rxLen, edge_serial->rxPort); - edge_tty_recv(&edge_serial->serial->dev->dev, tty, buffer, rxLen); - tty_kref_put(tty); - } - edge_port->icount.rx += rxLen; + dev_dbg(dev, "%s - Sending %d bytes to TTY for port %d\n", + __func__, rxLen, + edge_serial->rxPort); + edge_tty_recv(edge_port->port, buffer, + rxLen); + edge_port->port->icount.rx += rxLen; } buffer += rxLen; } @@ -1937,6 +1803,7 @@ static void process_rcvd_status(struct edgeport_serial *edge_serial, struct usb_serial_port *port; struct edgeport_port *edge_port; struct tty_struct *tty; + struct device *dev; __u8 code = edge_serial->rxStatusCode; /* switch the port pointer to the one being currently talked about */ @@ -1948,16 +1815,15 @@ static void process_rcvd_status(struct edgeport_serial *edge_serial, __func__, edge_serial->rxPort); return; } - - dbg("%s - port %d", __func__, edge_serial->rxPort); + dev = &port->dev; if (code == IOSP_EXT_STATUS) { switch (byte2) { case IOSP_EXT_STATUS_CHASE_RSP: /* we want to do EXT status regardless of port * open/closed */ - dbg("%s - Port %u EXT CHASE_RSP Data = %02x", - __func__, edge_serial->rxPort, byte3); + dev_dbg(dev, "%s - Port %u EXT CHASE_RSP Data = %02x\n", + __func__, edge_serial->rxPort, byte3); /* Currently, the only EXT_STATUS is Chase, so process * here instead of one more call to one more subroutine * If/when more EXT_STATUS, there'll be more work to do @@ -1972,7 +1838,8 @@ static void process_rcvd_status(struct edgeport_serial *edge_serial, return; case IOSP_EXT_STATUS_RX_CHECK_RSP: - dbg("%s ========== Port %u CHECK_RSP Sequence = %02x =============", __func__, edge_serial->rxPort, byte3); + dev_dbg(dev, "%s ========== Port %u CHECK_RSP Sequence = %02x =============\n", + __func__, edge_serial->rxPort, byte3); /* Port->RxCheckRsp = true; */ return; } @@ -1981,7 +1848,8 @@ static void process_rcvd_status(struct edgeport_serial *edge_serial, if (code == IOSP_STATUS_OPEN_RSP) { edge_port->txCredits = GET_TX_BUFFER_SIZE(byte3); edge_port->maxTxCredits = edge_port->txCredits; - dbg("%s - Port %u Open Response Inital MSR = %02x TxBufferSize = %d", __func__, edge_serial->rxPort, byte2, edge_port->txCredits); + dev_dbg(dev, "%s - Port %u Open Response Initial MSR = %02x TxBufferSize = %d\n", + __func__, edge_serial->rxPort, byte2, edge_port->txCredits); handle_new_msr(edge_port, byte2); /* send the current line settings to the port so we are @@ -1989,7 +1857,7 @@ static void process_rcvd_status(struct edgeport_serial *edge_serial, tty = tty_port_tty_get(&edge_port->port->port); if (tty) { change_port_settings(tty, - edge_port, tty->termios); + edge_port, &tty->termios); tty_kref_put(tty); } @@ -2010,27 +1878,27 @@ static void process_rcvd_status(struct edgeport_serial *edge_serial, switch (code) { /* Not currently sent by Edgeport */ case IOSP_STATUS_LSR: - dbg("%s - Port %u LSR Status = %02x", - __func__, edge_serial->rxPort, byte2); + dev_dbg(dev, "%s - Port %u LSR Status = %02x\n", + __func__, edge_serial->rxPort, byte2); handle_new_lsr(edge_port, false, byte2, 0); break; case IOSP_STATUS_LSR_DATA: - dbg("%s - Port %u LSR Status = %02x, Data = %02x", - __func__, edge_serial->rxPort, byte2, byte3); + dev_dbg(dev, "%s - Port %u LSR Status = %02x, Data = %02x\n", + __func__, edge_serial->rxPort, byte2, byte3); /* byte2 is LSR Register */ /* byte3 is broken data byte */ handle_new_lsr(edge_port, true, byte2, byte3); break; /* * case IOSP_EXT_4_STATUS: - * dbg("%s - Port %u LSR Status = %02x Data = %02x", + * dev_dbg(dev, "%s - Port %u LSR Status = %02x Data = %02x\n", * __func__, edge_serial->rxPort, byte2, byte3); * break; */ case IOSP_STATUS_MSR: - dbg("%s - Port %u MSR Status = %02x", - __func__, edge_serial->rxPort, byte2); + dev_dbg(dev, "%s - Port %u MSR Status = %02x\n", + __func__, edge_serial->rxPort, byte2); /* * Process this new modem status and generate appropriate * events, etc, based on the new status. This routine @@ -2040,7 +1908,7 @@ static void process_rcvd_status(struct edgeport_serial *edge_serial, break; default: - dbg("%s - Unrecognized IOSP status code %u", __func__, code); + dev_dbg(dev, "%s - Unrecognized IOSP status code %u\n", __func__, code); break; } } @@ -2050,20 +1918,20 @@ static void process_rcvd_status(struct edgeport_serial *edge_serial, * edge_tty_recv * this function passes data on to the tty flip buffer *****************************************************************************/ -static void edge_tty_recv(struct device *dev, struct tty_struct *tty, - unsigned char *data, int length) +static void edge_tty_recv(struct usb_serial_port *port, unsigned char *data, + int length) { int cnt; - cnt = tty_insert_flip_string(tty, data, length); + cnt = tty_insert_flip_string(&port->port, data, length); if (cnt < length) { - dev_err(dev, "%s - dropping data, %d bytes lost\n", + dev_err(&port->dev, "%s - dropping data, %d bytes lost\n", __func__, length - cnt); } data += cnt; length -= cnt; - tty_flip_buffer_push(tty); + tty_flip_buffer_push(&port->port); } @@ -2075,11 +1943,9 @@ static void handle_new_msr(struct edgeport_port *edge_port, __u8 newMsr) { struct async_icount *icount; - dbg("%s %02x", __func__, newMsr); - if (newMsr & (EDGEPORT_MSR_DELTA_CTS | EDGEPORT_MSR_DELTA_DSR | EDGEPORT_MSR_DELTA_RI | EDGEPORT_MSR_DELTA_CD)) { - icount = &edge_port->icount; + icount = &edge_port->port->icount; /* update input line counters */ if (newMsr & EDGEPORT_MSR_DELTA_CTS) @@ -2090,7 +1956,7 @@ static void handle_new_msr(struct edgeport_port *edge_port, __u8 newMsr) icount->dcd++; if (newMsr & EDGEPORT_MSR_DELTA_RI) icount->rng++; - wake_up_interruptible(&edge_port->delta_msr_wait); + wake_up_interruptible(&edge_port->port->port.delta_msr_wait); } /* Save the new modem status */ @@ -2109,8 +1975,6 @@ static void handle_new_lsr(struct edgeport_port *edge_port, __u8 lsrData, (LSR_OVER_ERR | LSR_PAR_ERR | LSR_FRM_ERR | LSR_BREAK)); struct async_icount *icount; - dbg("%s - %02x", __func__, newLsr); - edge_port->shadowLSR = lsr; if (newLsr & LSR_BREAK) { @@ -2123,16 +1987,11 @@ static void handle_new_lsr(struct edgeport_port *edge_port, __u8 lsrData, } /* Place LSR data byte into Rx buffer */ - if (lsrData) { - struct tty_struct *tty = - tty_port_tty_get(&edge_port->port->port); - if (tty) { - edge_tty_recv(&edge_port->port->dev, tty, &data, 1); - tty_kref_put(tty); - } - } + if (lsrData) + edge_tty_recv(edge_port->port, &data, 1); + /* update input line counters */ - icount = &edge_port->icount; + icount = &edge_port->port->icount; if (newLsr & LSR_BREAK) icount->brk++; if (newLsr & LSR_OVER_ERR) @@ -2158,14 +2017,11 @@ static int sram_write(struct usb_serial *serial, __u16 extAddr, __u16 addr, __u16 current_length; unsigned char *transfer_buffer; - dbg("%s - %x, %x, %d", __func__, extAddr, addr, length); + dev_dbg(&serial->dev->dev, "%s - %x, %x, %d\n", __func__, extAddr, addr, length); transfer_buffer = kmalloc(64, GFP_KERNEL); - if (!transfer_buffer) { - dev_err(&serial->dev->dev, "%s - kmalloc(%d) failed.\n", - __func__, 64); + if (!transfer_buffer) return -ENOMEM; - } /* need to split these writes up into 64 byte chunks */ result = 0; @@ -2175,8 +2031,7 @@ static int sram_write(struct usb_serial *serial, __u16 extAddr, __u16 addr, else current_length = length; -/* dbg("%s - writing %x, %x, %d", __func__, - extAddr, addr, current_length); */ +/* dev_dbg(&serial->dev->dev, "%s - writing %x, %x, %d\n", __func__, extAddr, addr, current_length); */ memcpy(transfer_buffer, data, current_length); result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), @@ -2209,14 +2064,9 @@ static int rom_write(struct usb_serial *serial, __u16 extAddr, __u16 addr, __u16 current_length; unsigned char *transfer_buffer; -/* dbg("%s - %x, %x, %d", __func__, extAddr, addr, length); */ - transfer_buffer = kmalloc(64, GFP_KERNEL); - if (!transfer_buffer) { - dev_err(&serial->dev->dev, "%s - kmalloc(%d) failed.\n", - __func__, 64); + if (!transfer_buffer) return -ENOMEM; - } /* need to split these writes up into 64 byte chunks */ result = 0; @@ -2225,8 +2075,6 @@ static int rom_write(struct usb_serial *serial, __u16 extAddr, __u16 addr, current_length = 64; else current_length = length; -/* dbg("%s - writing %x, %x, %d", __func__, - extAddr, addr, current_length); */ memcpy(transfer_buffer, data, current_length); result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), @@ -2259,14 +2107,9 @@ static int rom_read(struct usb_serial *serial, __u16 extAddr, __u16 current_length; unsigned char *transfer_buffer; - dbg("%s - %x, %x, %d", __func__, extAddr, addr, length); - transfer_buffer = kmalloc(64, GFP_KERNEL); - if (!transfer_buffer) { - dev_err(&serial->dev->dev, - "%s - kmalloc(%d) failed.\n", __func__, 64); + if (!transfer_buffer) return -ENOMEM; - } /* need to split these reads up into 64 byte chunks */ result = 0; @@ -2275,8 +2118,6 @@ static int rom_read(struct usb_serial *serial, __u16 extAddr, current_length = 64; else current_length = length; -/* dbg("%s - %x, %x, %d", __func__, - extAddr, addr, current_length); */ result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), USB_REQUEST_ION_READ_ROM, @@ -2307,20 +2148,14 @@ static int send_iosp_ext_cmd(struct edgeport_port *edge_port, int length = 0; int status = 0; - dbg("%s - %d, %d", __func__, command, param); - buffer = kmalloc(10, GFP_ATOMIC); - if (!buffer) { - dev_err(&edge_port->port->dev, - "%s - kmalloc(%d) failed.\n", __func__, 10); + if (!buffer) return -ENOMEM; - } currentCommand = buffer; - MAKE_CMD_EXT_CMD(¤tCommand, &length, - edge_port->port->number - edge_port->port->serial->minor, - command, param); + MAKE_CMD_EXT_CMD(¤tCommand, &length, edge_port->port->port_number, + command, param); status = write_cmd_usb(edge_port, buffer, length); if (status) { @@ -2341,12 +2176,11 @@ static int write_cmd_usb(struct edgeport_port *edge_port, { struct edgeport_serial *edge_serial = usb_get_serial_data(edge_port->port->serial); + struct device *dev = &edge_port->port->dev; int status = 0; struct urb *urb; - int timeout; - usb_serial_debug_data(debug, &edge_port->port->dev, - __func__, length, buffer); + usb_serial_debug_data(dev, __func__, length, buffer); /* Allocate our next urb */ urb = usb_alloc_urb(0, GFP_ATOMIC); @@ -2354,8 +2188,8 @@ static int write_cmd_usb(struct edgeport_port *edge_port, return -ENOMEM; atomic_inc(&CmdUrbs); - dbg("%s - ALLOCATE URB %p (outstanding %d)", - __func__, urb, atomic_read(&CmdUrbs)); + dev_dbg(dev, "%s - ALLOCATE URB %p (outstanding %d)\n", + __func__, urb, atomic_read(&CmdUrbs)); usb_fill_bulk_urb(urb, edge_serial->serial->dev, usb_sndbulkpipe(edge_serial->serial->dev, @@ -2367,23 +2201,20 @@ static int write_cmd_usb(struct edgeport_port *edge_port, if (status) { /* something went wrong */ - dev_err(&edge_port->port->dev, - "%s - usb_submit_urb(write command) failed, status = %d\n", - __func__, status); + dev_err(dev, "%s - usb_submit_urb(write command) failed, status = %d\n", + __func__, status); usb_kill_urb(urb); usb_free_urb(urb); atomic_dec(&CmdUrbs); return status; } - /* wait for command to finish */ - timeout = COMMAND_TIMEOUT; #if 0 wait_event(&edge_port->wait_command, !edge_port->commandPending); if (edge_port->commandPending) { /* command timed out */ - dbg("%s - command timed out", __func__); + dev_dbg(dev, "%s - command timed out\n", __func__); status = -EINVAL; } #endif @@ -2401,38 +2232,34 @@ static int send_cmd_write_baud_rate(struct edgeport_port *edge_port, { struct edgeport_serial *edge_serial = usb_get_serial_data(edge_port->port->serial); + struct device *dev = &edge_port->port->dev; unsigned char *cmdBuffer; unsigned char *currCmd; int cmdLen = 0; int divisor; int status; - unsigned char number = - edge_port->port->number - edge_port->port->serial->minor; + u32 number = edge_port->port->port_number; if (edge_serial->is_epic && !edge_serial->epic_descriptor.Supports.IOSPSetBaudRate) { - dbg("SendCmdWriteBaudRate - NOT Setting baud rate for port = %d, baud = %d", - edge_port->port->number, baudRate); + dev_dbg(dev, "SendCmdWriteBaudRate - NOT Setting baud rate for port, baud = %d\n", + baudRate); return 0; } - dbg("%s - port = %d, baud = %d", __func__, - edge_port->port->number, baudRate); + dev_dbg(dev, "%s - baud = %d\n", __func__, baudRate); - status = calc_baud_rate_divisor(baudRate, &divisor); + status = calc_baud_rate_divisor(dev, baudRate, &divisor); if (status) { - dev_err(&edge_port->port->dev, "%s - bad baud rate\n", - __func__); + dev_err(dev, "%s - bad baud rate\n", __func__); return status; } /* Alloc memory for the string of commands. */ cmdBuffer = kmalloc(0x100, GFP_ATOMIC); - if (!cmdBuffer) { - dev_err(&edge_port->port->dev, - "%s - kmalloc(%d) failed.\n", __func__, 0x100); + if (!cmdBuffer) return -ENOMEM; - } + currCmd = cmdBuffer; /* Enable access to divisor latch */ @@ -2461,14 +2288,11 @@ static int send_cmd_write_baud_rate(struct edgeport_port *edge_port, * this function calculates the proper baud rate divisor for the specified * baud rate. *****************************************************************************/ -static int calc_baud_rate_divisor(int baudrate, int *divisor) +static int calc_baud_rate_divisor(struct device *dev, int baudrate, int *divisor) { int i; __u16 custom; - - dbg("%s - %d", __func__, baudrate); - for (i = 0; i < ARRAY_SIZE(divisor_table); i++) { if (divisor_table[i].BaudRate == baudrate) { *divisor = divisor_table[i].Divisor; @@ -2485,7 +2309,7 @@ static int calc_baud_rate_divisor(int baudrate, int *divisor) *divisor = custom; - dbg("%s - Baud %d = %d", __func__, baudrate, custom); + dev_dbg(dev, "%s - Baud %d = %d\n", __func__, baudrate, custom); return 0; } @@ -2502,25 +2326,26 @@ static int send_cmd_write_uart_register(struct edgeport_port *edge_port, { struct edgeport_serial *edge_serial = usb_get_serial_data(edge_port->port->serial); + struct device *dev = &edge_port->port->dev; unsigned char *cmdBuffer; unsigned char *currCmd; unsigned long cmdLen = 0; int status; - dbg("%s - write to %s register 0x%02x", - (regNum == MCR) ? "MCR" : "LCR", __func__, regValue); + dev_dbg(dev, "%s - write to %s register 0x%02x\n", + (regNum == MCR) ? "MCR" : "LCR", __func__, regValue); if (edge_serial->is_epic && !edge_serial->epic_descriptor.Supports.IOSPWriteMCR && regNum == MCR) { - dbg("SendCmdWriteUartReg - Not writing to MCR Register"); + dev_dbg(dev, "SendCmdWriteUartReg - Not writing to MCR Register\n"); return 0; } if (edge_serial->is_epic && !edge_serial->epic_descriptor.Supports.IOSPWriteLCR && regNum == LCR) { - dbg("SendCmdWriteUartReg - Not writing to LCR Register"); + dev_dbg(dev, "SendCmdWriteUartReg - Not writing to LCR Register\n"); return 0; } @@ -2532,9 +2357,8 @@ static int send_cmd_write_uart_register(struct edgeport_port *edge_port, currCmd = cmdBuffer; /* Build a cmd in the buffer to write the given register */ - MAKE_CMD_WRITE_REG(&currCmd, &cmdLen, - edge_port->port->number - edge_port->port->serial->minor, - regNum, regValue); + MAKE_CMD_WRITE_REG(&currCmd, &cmdLen, edge_port->port->port_number, + regNum, regValue); status = write_cmd_usb(edge_port, cmdBuffer, cmdLen); if (status) { @@ -2555,6 +2379,7 @@ static int send_cmd_write_uart_register(struct edgeport_port *edge_port, static void change_port_settings(struct tty_struct *tty, struct edgeport_port *edge_port, struct ktermios *old_termios) { + struct device *dev = &edge_port->port->dev; struct edgeport_serial *edge_serial = usb_get_serial_data(edge_port->port->serial); int baud; @@ -2567,33 +2392,31 @@ static void change_port_settings(struct tty_struct *tty, __u8 txFlow; int status; - dbg("%s - port %d", __func__, edge_port->port->number); - if (!edge_port->open && !edge_port->openPending) { - dbg("%s - port not opened", __func__); + dev_dbg(dev, "%s - port not opened\n", __func__); return; } - cflag = tty->termios->c_cflag; + cflag = tty->termios.c_cflag; switch (cflag & CSIZE) { case CS5: lData = LCR_BITS_5; mask = 0x1f; - dbg("%s - data bits = 5", __func__); + dev_dbg(dev, "%s - data bits = 5\n", __func__); break; case CS6: lData = LCR_BITS_6; mask = 0x3f; - dbg("%s - data bits = 6", __func__); + dev_dbg(dev, "%s - data bits = 6\n", __func__); break; case CS7: lData = LCR_BITS_7; mask = 0x7f; - dbg("%s - data bits = 7", __func__); + dev_dbg(dev, "%s - data bits = 7\n", __func__); break; default: case CS8: lData = LCR_BITS_8; - dbg("%s - data bits = 8", __func__); + dev_dbg(dev, "%s - data bits = 8\n", __func__); break; } @@ -2602,28 +2425,28 @@ static void change_port_settings(struct tty_struct *tty, if (cflag & CMSPAR) { if (cflag & PARODD) { lParity = LCR_PAR_MARK; - dbg("%s - parity = mark", __func__); + dev_dbg(dev, "%s - parity = mark\n", __func__); } else { lParity = LCR_PAR_SPACE; - dbg("%s - parity = space", __func__); + dev_dbg(dev, "%s - parity = space\n", __func__); } } else if (cflag & PARODD) { lParity = LCR_PAR_ODD; - dbg("%s - parity = odd", __func__); + dev_dbg(dev, "%s - parity = odd\n", __func__); } else { lParity = LCR_PAR_EVEN; - dbg("%s - parity = even", __func__); + dev_dbg(dev, "%s - parity = even\n", __func__); } } else { - dbg("%s - parity = none", __func__); + dev_dbg(dev, "%s - parity = none\n", __func__); } if (cflag & CSTOPB) { lStop = LCR_STOP_2; - dbg("%s - stop bits = 2", __func__); + dev_dbg(dev, "%s - stop bits = 2\n", __func__); } else { lStop = LCR_STOP_1; - dbg("%s - stop bits = 1", __func__); + dev_dbg(dev, "%s - stop bits = 1\n", __func__); } /* figure out the flow control settings */ @@ -2631,9 +2454,9 @@ static void change_port_settings(struct tty_struct *tty, if (cflag & CRTSCTS) { rxFlow |= IOSP_RX_FLOW_RTS; txFlow |= IOSP_TX_FLOW_CTS; - dbg("%s - RTS/CTS is enabled", __func__); + dev_dbg(dev, "%s - RTS/CTS is enabled\n", __func__); } else { - dbg("%s - RTS/CTS is disabled", __func__); + dev_dbg(dev, "%s - RTS/CTS is disabled\n", __func__); } /* if we are implementing XON/XOFF, set the start and stop character @@ -2654,19 +2477,19 @@ static void change_port_settings(struct tty_struct *tty, /* if we are implementing INBOUND XON/XOFF */ if (I_IXOFF(tty)) { rxFlow |= IOSP_RX_FLOW_XON_XOFF; - dbg("%s - INBOUND XON/XOFF is enabled, XON = %2x, XOFF = %2x", - __func__, start_char, stop_char); + dev_dbg(dev, "%s - INBOUND XON/XOFF is enabled, XON = %2x, XOFF = %2x\n", + __func__, start_char, stop_char); } else { - dbg("%s - INBOUND XON/XOFF is disabled", __func__); + dev_dbg(dev, "%s - INBOUND XON/XOFF is disabled\n", __func__); } /* if we are implementing OUTBOUND XON/XOFF */ if (I_IXON(tty)) { txFlow |= IOSP_TX_FLOW_XON_XOFF; - dbg("%s - OUTBOUND XON/XOFF is enabled, XON = %2x, XOFF = %2x", - __func__, start_char, stop_char); + dev_dbg(dev, "%s - OUTBOUND XON/XOFF is enabled, XON = %2x, XOFF = %2x\n", + __func__, start_char, stop_char); } else { - dbg("%s - OUTBOUND XON/XOFF is disabled", __func__); + dev_dbg(dev, "%s - OUTBOUND XON/XOFF is disabled\n", __func__); } } @@ -2709,7 +2532,7 @@ static void change_port_settings(struct tty_struct *tty, baud = 9600; } - dbg("%s - baud rate = %d", __func__, baud); + dev_dbg(dev, "%s - baud rate = %d\n", __func__, baud); status = send_cmd_write_baud_rate(edge_port, baud); if (status == -1) { /* Speed change was not possible - put back the old speed */ @@ -2751,9 +2574,10 @@ static void unicode_to_ascii(char *string, int buflen, ****************************************************************************/ static void get_manufacturing_desc(struct edgeport_serial *edge_serial) { + struct device *dev = &edge_serial->serial->dev->dev; int response; - dbg("getting manufacturer descriptor"); + dev_dbg(dev, "getting manufacturer descriptor\n"); response = rom_read(edge_serial->serial, (EDGE_MANUF_DESC_ADDR & 0xffff0000) >> 16, @@ -2762,42 +2586,41 @@ static void get_manufacturing_desc(struct edgeport_serial *edge_serial) (__u8 *)(&edge_serial->manuf_descriptor)); if (response < 1) - dev_err(&edge_serial->serial->dev->dev, - "error in getting manufacturer descriptor\n"); + dev_err(dev, "error in getting manufacturer descriptor\n"); else { char string[30]; - dbg("**Manufacturer Descriptor"); - dbg(" RomSize: %dK", + dev_dbg(dev, "**Manufacturer Descriptor\n"); + dev_dbg(dev, " RomSize: %dK\n", edge_serial->manuf_descriptor.RomSize); - dbg(" RamSize: %dK", + dev_dbg(dev, " RamSize: %dK\n", edge_serial->manuf_descriptor.RamSize); - dbg(" CpuRev: %d", + dev_dbg(dev, " CpuRev: %d\n", edge_serial->manuf_descriptor.CpuRev); - dbg(" BoardRev: %d", + dev_dbg(dev, " BoardRev: %d\n", edge_serial->manuf_descriptor.BoardRev); - dbg(" NumPorts: %d", + dev_dbg(dev, " NumPorts: %d\n", edge_serial->manuf_descriptor.NumPorts); - dbg(" DescDate: %d/%d/%d", + dev_dbg(dev, " DescDate: %d/%d/%d\n", edge_serial->manuf_descriptor.DescDate[0], edge_serial->manuf_descriptor.DescDate[1], edge_serial->manuf_descriptor.DescDate[2]+1900); unicode_to_ascii(string, sizeof(string), edge_serial->manuf_descriptor.SerialNumber, edge_serial->manuf_descriptor.SerNumLength/2); - dbg(" SerialNumber: %s", string); + dev_dbg(dev, " SerialNumber: %s\n", string); unicode_to_ascii(string, sizeof(string), edge_serial->manuf_descriptor.AssemblyNumber, edge_serial->manuf_descriptor.AssemblyNumLength/2); - dbg(" AssemblyNumber: %s", string); + dev_dbg(dev, " AssemblyNumber: %s\n", string); unicode_to_ascii(string, sizeof(string), edge_serial->manuf_descriptor.OemAssyNumber, edge_serial->manuf_descriptor.OemAssyNumLength/2); - dbg(" OemAssyNumber: %s", string); - dbg(" UartType: %d", + dev_dbg(dev, " OemAssyNumber: %s\n", string); + dev_dbg(dev, " UartType: %d\n", edge_serial->manuf_descriptor.UartType); - dbg(" IonPid: %d", + dev_dbg(dev, " IonPid: %d\n", edge_serial->manuf_descriptor.IonPid); - dbg(" IonConfig: %d", + dev_dbg(dev, " IonConfig: %d\n", edge_serial->manuf_descriptor.IonConfig); } } @@ -2810,9 +2633,10 @@ static void get_manufacturing_desc(struct edgeport_serial *edge_serial) ****************************************************************************/ static void get_boot_desc(struct edgeport_serial *edge_serial) { + struct device *dev = &edge_serial->serial->dev->dev; int response; - dbg("getting boot descriptor"); + dev_dbg(dev, "getting boot descriptor\n"); response = rom_read(edge_serial->serial, (EDGE_BOOT_DESC_ADDR & 0xffff0000) >> 16, @@ -2821,23 +2645,22 @@ static void get_boot_desc(struct edgeport_serial *edge_serial) (__u8 *)(&edge_serial->boot_descriptor)); if (response < 1) - dev_err(&edge_serial->serial->dev->dev, - "error in getting boot descriptor\n"); + dev_err(dev, "error in getting boot descriptor\n"); else { - dbg("**Boot Descriptor:"); - dbg(" BootCodeLength: %d", - le16_to_cpu(edge_serial->boot_descriptor.BootCodeLength)); - dbg(" MajorVersion: %d", + dev_dbg(dev, "**Boot Descriptor:\n"); + dev_dbg(dev, " BootCodeLength: %d\n", + le16_to_cpu(edge_serial->boot_descriptor.BootCodeLength)); + dev_dbg(dev, " MajorVersion: %d\n", edge_serial->boot_descriptor.MajorVersion); - dbg(" MinorVersion: %d", + dev_dbg(dev, " MinorVersion: %d\n", edge_serial->boot_descriptor.MinorVersion); - dbg(" BuildNumber: %d", + dev_dbg(dev, " BuildNumber: %d\n", le16_to_cpu(edge_serial->boot_descriptor.BuildNumber)); - dbg(" Capabilities: 0x%x", + dev_dbg(dev, " Capabilities: 0x%x\n", le16_to_cpu(edge_serial->boot_descriptor.Capabilities)); - dbg(" UConfig0: %d", + dev_dbg(dev, " UConfig0: %d\n", edge_serial->boot_descriptor.UConfig0); - dbg(" UConfig1: %d", + dev_dbg(dev, " UConfig1: %d\n", edge_serial->boot_descriptor.UConfig1); } } @@ -2849,6 +2672,7 @@ static void get_boot_desc(struct edgeport_serial *edge_serial) ****************************************************************************/ static void load_application_firmware(struct edgeport_serial *edge_serial) { + struct device *dev = &edge_serial->serial->dev->dev; const struct ihex_binrec *rec; const struct firmware *fw; const char *fw_name; @@ -2869,7 +2693,7 @@ static void load_application_firmware(struct edgeport_serial *edge_serial) break; case EDGE_DOWNLOAD_FILE_NONE: - dbg("No download file specified, skipping download"); + dev_dbg(dev, "No download file specified, skipping download\n"); return; default: @@ -2879,7 +2703,7 @@ static void load_application_firmware(struct edgeport_serial *edge_serial) response = request_ihex_firmware(&fw, fw_name, &edge_serial->serial->dev->dev); if (response) { - printk(KERN_ERR "Failed to load image \"%s\" err %d\n", + dev_err(dev, "Failed to load image \"%s\" err %d\n", fw_name, response); return; } @@ -2887,10 +2711,10 @@ static void load_application_firmware(struct edgeport_serial *edge_serial) rec = (const struct ihex_binrec *)fw->data; build = (rec->data[2] << 8) | rec->data[3]; - dbg("%s %d.%d.%d", fw_info, rec->data[0], rec->data[1], build); + dev_dbg(dev, "%s %d.%d.%d\n", fw_info, rec->data[0], rec->data[1], build); - edge_serial->product_info.FirmwareMajorVersion = fw->data[0]; - edge_serial->product_info.FirmwareMinorVersion = fw->data[1]; + edge_serial->product_info.FirmwareMajorVersion = rec->data[0]; + edge_serial->product_info.FirmwareMinorVersion = rec->data[1]; edge_serial->product_info.FirmwareBuildNumber = cpu_to_le16(build); for (rec = ihex_next_binrec(rec); rec; @@ -2910,10 +2734,10 @@ static void load_application_firmware(struct edgeport_serial *edge_serial) } } - dbg("sending exec_dl_code"); - response = usb_control_msg (edge_serial->serial->dev, - usb_sndctrlpipe(edge_serial->serial->dev, 0), - USB_REQUEST_ION_EXEC_DL_CODE, + dev_dbg(dev, "sending exec_dl_code\n"); + response = usb_control_msg (edge_serial->serial->dev, + usb_sndctrlpipe(edge_serial->serial->dev, 0), + USB_REQUEST_ION_EXEC_DL_CODE, 0x40, 0x4000, 0x0001, NULL, 0, 3000); release_firmware(fw); @@ -2926,9 +2750,9 @@ static void load_application_firmware(struct edgeport_serial *edge_serial) static int edge_startup(struct usb_serial *serial) { struct edgeport_serial *edge_serial; - struct edgeport_port *edge_port; struct usb_device *dev; - int i, j; + struct device *ddev = &serial->dev->dev; + int i; int response; bool interrupt_in_found; bool bulk_in_found; @@ -2941,10 +2765,9 @@ static int edge_startup(struct usb_serial *serial) /* create our private serial structure */ edge_serial = kzalloc(sizeof(struct edgeport_serial), GFP_KERNEL); - if (edge_serial == NULL) { - dev_err(&serial->dev->dev, "%s - Out of memory\n", __func__); + if (!edge_serial) return -ENOMEM; - } + spin_lock_init(&edge_serial->es_lock); edge_serial->serial = serial; usb_set_serial_data(serial, edge_serial); @@ -2979,32 +2802,31 @@ static int edge_startup(struct usb_serial *serial) /* serial->num_ports = serial->product_info.NumPorts; */ if ((!edge_serial->is_epic) && (edge_serial->product_info.NumPorts != serial->num_ports)) { - dev_warn(&serial->dev->dev, "Device Reported %d serial ports " - "vs. core thinking we have %d ports, email " - "greg@kroah.com this information.\n", + dev_warn(ddev, + "Device Reported %d serial ports vs. core thinking we have %d ports, email greg@kroah.com this information.\n", edge_serial->product_info.NumPorts, serial->num_ports); } - dbg("%s - time 1 %ld", __func__, jiffies); + dev_dbg(ddev, "%s - time 1 %ld\n", __func__, jiffies); /* If not an EPiC device */ if (!edge_serial->is_epic) { /* now load the application firmware into this device */ load_application_firmware(edge_serial); - dbg("%s - time 2 %ld", __func__, jiffies); + dev_dbg(ddev, "%s - time 2 %ld\n", __func__, jiffies); /* Check current Edgeport EEPROM and update if necessary */ update_edgeport_E2PROM(edge_serial); - dbg("%s - time 3 %ld", __func__, jiffies); + dev_dbg(ddev, "%s - time 3 %ld\n", __func__, jiffies); /* set the configuration to use #1 */ -/* dbg("set_configuration 1"); */ +/* dev_dbg(ddev, "set_configuration 1\n"); */ /* usb_set_configuration (dev, 1); */ } - dbg(" FirmwareMajorVersion %d.%d.%d", + dev_dbg(ddev, " FirmwareMajorVersion %d.%d.%d\n", edge_serial->product_info.FirmwareMajorVersion, edge_serial->product_info.FirmwareMinorVersion, le16_to_cpu(edge_serial->product_info.FirmwareBuildNumber)); @@ -3012,26 +2834,6 @@ static int edge_startup(struct usb_serial *serial) /* we set up the pointers to the endpoints in the edge_open function, * as the structures aren't created yet. */ - /* set up our port private structures */ - for (i = 0; i < serial->num_ports; ++i) { - edge_port = kzalloc(sizeof(struct edgeport_port), GFP_KERNEL); - if (edge_port == NULL) { - dev_err(&serial->dev->dev, "%s - Out of memory\n", - __func__); - for (j = 0; j < i; ++j) { - kfree(usb_get_serial_port_data(serial->port[j])); - usb_set_serial_port_data(serial->port[j], - NULL); - } - usb_set_serial_data(serial, NULL); - kfree(edge_serial); - return -ENOMEM; - } - spin_lock_init(&edge_port->ep_lock); - edge_port->port = serial->port[i]; - usb_set_serial_port_data(serial->port[i], edge_port); - } - response = 0; if (edge_serial->is_epic) { @@ -3045,23 +2847,21 @@ static int edge_startup(struct usb_serial *serial) endpoint = &serial->interface->altsetting[0]. endpoint[i].desc; - buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); + buffer_size = usb_endpoint_maxp(endpoint); if (!interrupt_in_found && (usb_endpoint_is_int_in(endpoint))) { /* we found a interrupt in endpoint */ - dbg("found interrupt in"); + dev_dbg(ddev, "found interrupt in\n"); /* not set up yet, so do it now */ edge_serial->interrupt_read_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!edge_serial->interrupt_read_urb) { - dev_err(&dev->dev, "out of memory\n"); + if (!edge_serial->interrupt_read_urb) return -ENOMEM; - } + edge_serial->interrupt_in_buffer = kmalloc(buffer_size, GFP_KERNEL); if (!edge_serial->interrupt_in_buffer) { - dev_err(&dev->dev, "out of memory\n"); usb_free_urb(edge_serial->interrupt_read_urb); return -ENOMEM; } @@ -3086,19 +2886,17 @@ static int edge_startup(struct usb_serial *serial) if (!bulk_in_found && (usb_endpoint_is_bulk_in(endpoint))) { /* we found a bulk in endpoint */ - dbg("found bulk in"); + dev_dbg(ddev, "found bulk in\n"); /* not set up yet, so do it now */ edge_serial->read_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!edge_serial->read_urb) { - dev_err(&dev->dev, "out of memory\n"); + if (!edge_serial->read_urb) return -ENOMEM; - } + edge_serial->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL); if (!edge_serial->bulk_in_buffer) { - dev_err(&dev->dev, "out of memory\n"); usb_free_urb(edge_serial->read_urb); return -ENOMEM; } @@ -3110,7 +2908,7 @@ static int edge_startup(struct usb_serial *serial) usb_rcvbulkpipe(dev, endpoint->bEndpointAddress), edge_serial->bulk_in_buffer, - le16_to_cpu(endpoint->wMaxPacketSize), + usb_endpoint_maxp(endpoint), edge_bulk_in_callback, edge_serial); bulk_in_found = true; @@ -3119,7 +2917,7 @@ static int edge_startup(struct usb_serial *serial) if (!bulk_out_found && (usb_endpoint_is_bulk_out(endpoint))) { /* we found a bulk out endpoint */ - dbg("found bulk out"); + dev_dbg(ddev, "found bulk out\n"); edge_serial->bulk_out_endpoint = endpoint->bEndpointAddress; bulk_out_found = true; @@ -3127,8 +2925,7 @@ static int edge_startup(struct usb_serial *serial) } if (!interrupt_in_found || !bulk_in_found || !bulk_out_found) { - dev_err(&dev->dev, "Error - the proper endpoints " - "were not found!\n"); + dev_err(ddev, "Error - the proper endpoints were not found!\n"); return -ENODEV; } @@ -3137,8 +2934,7 @@ static int edge_startup(struct usb_serial *serial) response = usb_submit_urb(edge_serial->interrupt_read_urb, GFP_KERNEL); if (response) - dev_err(&dev->dev, - "%s - Error %d submitting control urb\n", + dev_err(ddev, "%s - Error %d submitting control urb\n", __func__, response); } return response; @@ -3153,8 +2949,6 @@ static void edge_disconnect(struct usb_serial *serial) { struct edgeport_serial *edge_serial = usb_get_serial_data(serial); - dbg("%s", __func__); - /* stop reads and writes on all ports */ /* free up our endpoint stuff */ if (edge_serial->is_epic) { @@ -3176,75 +2970,38 @@ static void edge_disconnect(struct usb_serial *serial) static void edge_release(struct usb_serial *serial) { struct edgeport_serial *edge_serial = usb_get_serial_data(serial); - int i; - - dbg("%s", __func__); - - for (i = 0; i < serial->num_ports; ++i) - kfree(usb_get_serial_port_data(serial->port[i])); kfree(edge_serial); } - -/**************************************************************************** - * edgeport_init - * This is called by the module subsystem, or on startup to initialize us - ****************************************************************************/ -static int __init edgeport_init(void) +static int edge_port_probe(struct usb_serial_port *port) { - int retval; - - retval = usb_serial_register(&edgeport_2port_device); - if (retval) - goto failed_2port_device_register; - retval = usb_serial_register(&edgeport_4port_device); - if (retval) - goto failed_4port_device_register; - retval = usb_serial_register(&edgeport_8port_device); - if (retval) - goto failed_8port_device_register; - retval = usb_serial_register(&epic_device); - if (retval) - goto failed_epic_device_register; - retval = usb_register(&io_driver); - if (retval) - goto failed_usb_register; - atomic_set(&CmdUrbs, 0); - printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" - DRIVER_DESC "\n"); - return 0; + struct edgeport_port *edge_port; -failed_usb_register: - usb_serial_deregister(&epic_device); -failed_epic_device_register: - usb_serial_deregister(&edgeport_8port_device); -failed_8port_device_register: - usb_serial_deregister(&edgeport_4port_device); -failed_4port_device_register: - usb_serial_deregister(&edgeport_2port_device); -failed_2port_device_register: - return retval; -} + edge_port = kzalloc(sizeof(*edge_port), GFP_KERNEL); + if (!edge_port) + return -ENOMEM; + spin_lock_init(&edge_port->ep_lock); + edge_port->port = port; -/**************************************************************************** - * edgeport_exit - * Called when the driver is about to be unloaded. - ****************************************************************************/ -static void __exit edgeport_exit (void) + usb_set_serial_port_data(port, edge_port); + + return 0; +} + +static int edge_port_remove(struct usb_serial_port *port) { - usb_deregister(&io_driver); - usb_serial_deregister(&edgeport_2port_device); - usb_serial_deregister(&edgeport_4port_device); - usb_serial_deregister(&edgeport_8port_device); - usb_serial_deregister(&epic_device); + struct edgeport_port *edge_port; + + edge_port = usb_get_serial_port_data(port); + kfree(edge_port); + + return 0; } -module_init(edgeport_init); -module_exit(edgeport_exit); +module_usb_serial_driver(serial_drivers, id_table_combined); -/* Module information */ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); @@ -3252,6 +3009,3 @@ MODULE_FIRMWARE("edgeport/boot.fw"); MODULE_FIRMWARE("edgeport/boot2.fw"); MODULE_FIRMWARE("edgeport/down.fw"); MODULE_FIRMWARE("edgeport/down2.fw"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/drivers/usb/serial/io_edgeport.h b/drivers/usb/serial/io_edgeport.h index dced7ec6547..ad9c1d47a61 100644 --- a/drivers/usb/serial/io_edgeport.h +++ b/drivers/usb/serial/io_edgeport.h @@ -68,7 +68,7 @@ struct comMapper { #define PROC_SET_COM_ENTRY 2 -/* The following sturcture is passed to the write */ +/* The following structure is passed to the write */ struct procWrite { int Command; union { diff --git a/drivers/usb/serial/io_tables.h b/drivers/usb/serial/io_tables.h index 6ab2a3f97fe..ae5fac5656c 100644 --- a/drivers/usb/serial/io_tables.h +++ b/drivers/usb/serial/io_tables.h @@ -95,21 +95,12 @@ static const struct usb_device_id id_table_combined[] = { MODULE_DEVICE_TABLE(usb, id_table_combined); -static struct usb_driver io_driver = { - .name = "io_edgeport", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table_combined, - .no_dynamic_id = 1, -}; - static struct usb_serial_driver edgeport_2port_device = { .driver = { .owner = THIS_MODULE, .name = "edgeport_2", }, .description = "Edgeport 2 port adapter", - .usb_driver = &io_driver, .id_table = edgeport_2port_id_table, .num_ports = 2, .open = edge_open, @@ -119,11 +110,14 @@ static struct usb_serial_driver edgeport_2port_device = { .attach = edge_startup, .disconnect = edge_disconnect, .release = edge_release, + .port_probe = edge_port_probe, + .port_remove = edge_port_remove, .ioctl = edge_ioctl, .set_termios = edge_set_termios, .tiocmget = edge_tiocmget, .tiocmset = edge_tiocmset, - .get_icount = edge_get_icount, + .tiocmiwait = usb_serial_generic_tiocmiwait, + .get_icount = usb_serial_generic_get_icount, .write = edge_write, .write_room = edge_write_room, .chars_in_buffer = edge_chars_in_buffer, @@ -139,7 +133,6 @@ static struct usb_serial_driver edgeport_4port_device = { .name = "edgeport_4", }, .description = "Edgeport 4 port adapter", - .usb_driver = &io_driver, .id_table = edgeport_4port_id_table, .num_ports = 4, .open = edge_open, @@ -149,11 +142,14 @@ static struct usb_serial_driver edgeport_4port_device = { .attach = edge_startup, .disconnect = edge_disconnect, .release = edge_release, + .port_probe = edge_port_probe, + .port_remove = edge_port_remove, .ioctl = edge_ioctl, .set_termios = edge_set_termios, .tiocmget = edge_tiocmget, .tiocmset = edge_tiocmset, - .get_icount = edge_get_icount, + .tiocmiwait = usb_serial_generic_tiocmiwait, + .get_icount = usb_serial_generic_get_icount, .write = edge_write, .write_room = edge_write_room, .chars_in_buffer = edge_chars_in_buffer, @@ -169,7 +165,6 @@ static struct usb_serial_driver edgeport_8port_device = { .name = "edgeport_8", }, .description = "Edgeport 8 port adapter", - .usb_driver = &io_driver, .id_table = edgeport_8port_id_table, .num_ports = 8, .open = edge_open, @@ -179,11 +174,14 @@ static struct usb_serial_driver edgeport_8port_device = { .attach = edge_startup, .disconnect = edge_disconnect, .release = edge_release, + .port_probe = edge_port_probe, + .port_remove = edge_port_remove, .ioctl = edge_ioctl, .set_termios = edge_set_termios, .tiocmget = edge_tiocmget, .tiocmset = edge_tiocmset, - .get_icount = edge_get_icount, + .tiocmiwait = usb_serial_generic_tiocmiwait, + .get_icount = usb_serial_generic_get_icount, .write = edge_write, .write_room = edge_write_room, .chars_in_buffer = edge_chars_in_buffer, @@ -208,11 +206,14 @@ static struct usb_serial_driver epic_device = { .attach = edge_startup, .disconnect = edge_disconnect, .release = edge_release, + .port_probe = edge_port_probe, + .port_remove = edge_port_remove, .ioctl = edge_ioctl, .set_termios = edge_set_termios, .tiocmget = edge_tiocmget, .tiocmset = edge_tiocmset, - .get_icount = edge_get_icount, + .tiocmiwait = usb_serial_generic_tiocmiwait, + .get_icount = usb_serial_generic_get_icount, .write = edge_write, .write_room = edge_write_room, .chars_in_buffer = edge_chars_in_buffer, @@ -222,5 +223,10 @@ static struct usb_serial_driver epic_device = { .write_bulk_callback = edge_bulk_out_data_callback, }; +static struct usb_serial_driver * const serial_drivers[] = { + &edgeport_2port_device, &edgeport_4port_device, + &edgeport_8port_device, &epic_device, NULL +}; + #endif diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index 22506b095c4..c0a42e9e677 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -15,19 +15,11 @@ * For questions or problems with this driver, contact Inside Out * Networks technical support, or Peter Berger <pberger@brimson.com>, * or Al Borchers <alborchers@steinerpoint.com>. - * - * Version history: - * - * July 11, 2002 Removed 4 port device structure since all TI UMP - * chips have only 2 ports - * David Iacovelli (davidi@ionetworks.com) - * */ #include <linux/kernel.h> #include <linux/jiffies.h> #include <linux/errno.h> -#include <linux/init.h> #include <linux/slab.h> #include <linux/tty.h> #include <linux/tty_driver.h> @@ -36,6 +28,7 @@ #include <linux/spinlock.h> #include <linux/mutex.h> #include <linux/serial.h> +#include <linux/swab.h> #include <linux/kfifo.h> #include <linux/ioctl.h> #include <linux/firmware.h> @@ -47,10 +40,6 @@ #include "io_usbvend.h" #include "io_ti.h" -/* - * Version Information - */ -#define DRIVER_VERSION "v0.7mode043006" #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com> and David Iacovelli" #define DRIVER_DESC "Edgeport USB Serial Driver" @@ -75,8 +64,6 @@ #define EDGE_CLOSING_WAIT 4000 /* in .01 sec */ -#define EDGE_OUT_BUF_SIZE 1024 - /* Product information read from the Edgeport */ struct product_info { @@ -97,17 +84,13 @@ struct edgeport_port { int baud_rate; int close_pending; int lsr_event; - struct async_icount icount; - wait_queue_head_t delta_msr_wait; /* for handling sleeping while - waiting for msr change to - happen */ + struct edgeport_serial *edge_serial; struct usb_serial_port *port; __u8 bUartMode; /* Port type, 0: RS232, etc. */ spinlock_t ep_lock; int ep_read_urb_state; int ep_write_urb_in_use; - struct kfifo write_fifo; }; struct edgeport_serial { @@ -204,34 +187,23 @@ static const struct usb_device_id id_table_combined[] = { MODULE_DEVICE_TABLE(usb, id_table_combined); -static struct usb_driver io_driver = { - .name = "io_ti", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table_combined, - .no_dynamic_id = 1, -}; - - static unsigned char OperationalMajorVersion; static unsigned char OperationalMinorVersion; static unsigned short OperationalBuildNumber; -static int debug; - static int closing_wait = EDGE_CLOSING_WAIT; -static int ignore_cpu_rev; +static bool ignore_cpu_rev; static int default_uart_mode; /* RS232 */ -static void edge_tty_recv(struct device *dev, struct tty_struct *tty, - unsigned char *data, int length); +static void edge_tty_recv(struct usb_serial_port *port, unsigned char *data, + int length); static void stop_read(struct edgeport_port *edge_port); static int restart_read(struct edgeport_port *edge_port); static void edge_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios); -static void edge_send(struct tty_struct *tty); +static void edge_send(struct usb_serial_port *port, struct tty_struct *tty); /* sysfs attributes */ static int edge_create_sysfs_attrs(struct usb_serial_port *port); @@ -249,8 +221,8 @@ static int ti_vread_sync(struct usb_device *dev, __u8 request, if (status < 0) return status; if (status != size) { - dbg("%s - wanted to write %d, but only wrote %d", - __func__, size, status); + dev_dbg(&dev->dev, "%s - wanted to write %d, but only wrote %d\n", + __func__, size, status); return -ECOMM; } return 0; @@ -267,8 +239,8 @@ static int ti_vsend_sync(struct usb_device *dev, __u8 request, if (status < 0) return status; if (status != size) { - dbg("%s - wanted to write %d, but only wrote %d", - __func__, size, status); + dev_dbg(&dev->dev, "%s - wanted to write %d, but only wrote %d\n", + __func__, size, status); return -ECOMM; } return 0; @@ -284,9 +256,9 @@ static int send_cmd(struct usb_device *dev, __u8 command, /* clear tx/rx buffers and fifo in TI UMP */ static int purge_port(struct usb_serial_port *port, __u16 mask) { - int port_number = port->number - port->serial->minor; + int port_number = port->port_number; - dbg("%s - port %d, mask %x", __func__, port_number, mask); + dev_dbg(&port->dev, "%s - port %d, mask %x\n", __func__, port_number, mask); return send_cmd(port->serial->dev, UMPC_PURGE_PORT, @@ -309,9 +281,9 @@ static int read_download_mem(struct usb_device *dev, int start_address, { int status = 0; __u8 read_length; - __be16 be_start_address; + u16 be_start_address; - dbg("%s - @ %x for %d", __func__, start_address, length); + dev_dbg(&dev->dev, "%s - @ %x for %d\n", __func__, start_address, length); /* Read in blocks of 64 bytes * (TI firmware can't handle more than 64 byte reads) @@ -323,23 +295,25 @@ static int read_download_mem(struct usb_device *dev, int start_address, read_length = (__u8)length; if (read_length > 1) { - dbg("%s - @ %x for %d", __func__, - start_address, read_length); + dev_dbg(&dev->dev, "%s - @ %x for %d\n", __func__, start_address, read_length); } - be_start_address = cpu_to_be16(start_address); + /* + * NOTE: Must use swab as wIndex is sent in little-endian + * byte order regardless of host byte order. + */ + be_start_address = swab16((u16)start_address); status = ti_vread_sync(dev, UMPC_MEMORY_READ, (__u16)address_type, - (__force __u16)be_start_address, + be_start_address, buffer, read_length); if (status) { - dbg("%s - ERROR %x", __func__, status); + dev_dbg(&dev->dev, "%s - ERROR %x\n", __func__, status); return status; } if (read_length > 1) - usb_serial_debug_data(debug, &dev->dev, __func__, - read_length, buffer); + usb_serial_debug_data(&dev->dev, __func__, read_length, buffer); /* Update pointers/length */ start_address += read_length; @@ -369,15 +343,14 @@ static int read_boot_mem(struct edgeport_serial *serial, UMPC_MEMORY_READ, serial->TI_I2C_Type, (__u16)(start_address+i), &buffer[i], 0x01); if (status) { - dbg("%s - ERROR %x", __func__, status); + dev_dbg(&serial->serial->dev->dev, "%s - ERROR %x\n", __func__, status); return status; } } - dbg("%s - start_address = %x, length = %d", - __func__, start_address, length); - usb_serial_debug_data(debug, &serial->serial->dev->dev, - __func__, length, buffer); + dev_dbg(&serial->serial->dev->dev, "%s - start_address = %x, length = %d\n", + __func__, start_address, length); + usb_serial_debug_data(&serial->serial->dev->dev, __func__, length, buffer); serial->TiReadI2C = 1; @@ -395,11 +368,9 @@ static int write_boot_mem(struct edgeport_serial *serial, /* Must do a read before write */ if (!serial->TiReadI2C) { temp = kmalloc(1, GFP_KERNEL); - if (!temp) { - dev_err(&serial->serial->dev->dev, - "%s - out of memory\n", __func__); + if (!temp) return -ENOMEM; - } + status = read_boot_mem(serial, 0, 1, temp); kfree(temp); if (status) @@ -414,10 +385,8 @@ static int write_boot_mem(struct edgeport_serial *serial, return status; } - dbg("%s - start_sddr = %x, length = %d", - __func__, start_address, length); - usb_serial_debug_data(debug, &serial->serial->dev->dev, - __func__, length, buffer); + dev_dbg(&serial->serial->dev->dev, "%s - start_sddr = %x, length = %d\n", __func__, start_address, length); + usb_serial_debug_data(&serial->serial->dev->dev, __func__, length, buffer); return status; } @@ -427,32 +396,37 @@ static int write_boot_mem(struct edgeport_serial *serial, static int write_i2c_mem(struct edgeport_serial *serial, int start_address, int length, __u8 address_type, __u8 *buffer) { + struct device *dev = &serial->serial->dev->dev; int status = 0; int write_length; - __be16 be_start_address; + u16 be_start_address; /* We can only send a maximum of 1 aligned byte page at a time */ - /* calulate the number of bytes left in the first page */ + /* calculate the number of bytes left in the first page */ write_length = EPROM_PAGE_SIZE - (start_address & (EPROM_PAGE_SIZE - 1)); if (write_length > length) write_length = length; - dbg("%s - BytesInFirstPage Addr = %x, length = %d", - __func__, start_address, write_length); - usb_serial_debug_data(debug, &serial->serial->dev->dev, - __func__, write_length, buffer); + dev_dbg(dev, "%s - BytesInFirstPage Addr = %x, length = %d\n", + __func__, start_address, write_length); + usb_serial_debug_data(dev, __func__, write_length, buffer); - /* Write first page */ - be_start_address = cpu_to_be16(start_address); + /* + * Write first page. + * + * NOTE: Must use swab as wIndex is sent in little-endian byte order + * regardless of host byte order. + */ + be_start_address = swab16((u16)start_address); status = ti_vsend_sync(serial->serial->dev, UMPC_MEMORY_WRITE, (__u16)address_type, - (__force __u16)be_start_address, + be_start_address, buffer, write_length); if (status) { - dbg("%s - ERROR %d", __func__, status); + dev_dbg(dev, "%s - ERROR %d\n", __func__, status); return status; } @@ -468,20 +442,23 @@ static int write_i2c_mem(struct edgeport_serial *serial, else write_length = length; - dbg("%s - Page Write Addr = %x, length = %d", - __func__, start_address, write_length); - usb_serial_debug_data(debug, &serial->serial->dev->dev, - __func__, write_length, buffer); + dev_dbg(dev, "%s - Page Write Addr = %x, length = %d\n", + __func__, start_address, write_length); + usb_serial_debug_data(dev, __func__, write_length, buffer); - /* Write next page */ - be_start_address = cpu_to_be16(start_address); + /* + * Write next page. + * + * NOTE: Must use swab as wIndex is sent in little-endian byte + * order regardless of host byte order. + */ + be_start_address = swab16((u16)start_address); status = ti_vsend_sync(serial->serial->dev, UMPC_MEMORY_WRITE, (__u16)address_type, - (__force __u16)be_start_address, + be_start_address, buffer, write_length); if (status) { - dev_err(&serial->serial->dev->dev, "%s - ERROR %d\n", - __func__, status); + dev_err(dev, "%s - ERROR %d\n", __func__, status); return status; } @@ -506,10 +483,8 @@ static int tx_active(struct edgeport_port *port) int bytes_left = 0; oedb = kmalloc(sizeof(*oedb), GFP_KERNEL); - if (!oedb) { - dev_err(&port->port->dev, "%s - out of memory\n", __func__); + if (!oedb) return -ENOMEM; - } lsr = kmalloc(1, GFP_KERNEL); /* Sigh, that's right, just one byte, as not all platforms can do DMA @@ -524,7 +499,7 @@ static int tx_active(struct edgeport_port *port) if (status) goto exit_is_tx_active; - dbg("%s - XByteCount 0x%X", __func__, oedb->XByteCount); + dev_dbg(&port->port->dev, "%s - XByteCount 0x%X\n", __func__, oedb->XByteCount); /* and the LSR */ status = read_ram(port->port->serial->dev, @@ -532,7 +507,7 @@ static int tx_active(struct edgeport_port *port) if (status) goto exit_is_tx_active; - dbg("%s - LSR = 0x%X", __func__, *lsr); + dev_dbg(&port->port->dev, "%s - LSR = 0x%X\n", __func__, *lsr); /* If either buffer has data or we are transmitting then return TRUE */ if ((oedb->XByteCount & 0x80) != 0) @@ -543,68 +518,13 @@ static int tx_active(struct edgeport_port *port) /* We return Not Active if we get any kind of error */ exit_is_tx_active: - dbg("%s - return %d", __func__, bytes_left); + dev_dbg(&port->port->dev, "%s - return %d\n", __func__, bytes_left); kfree(lsr); kfree(oedb); return bytes_left; } -static void chase_port(struct edgeport_port *port, unsigned long timeout, - int flush) -{ - int baud_rate; - struct tty_struct *tty = tty_port_tty_get(&port->port->port); - wait_queue_t wait; - unsigned long flags; - - if (!timeout) - timeout = (HZ * EDGE_CLOSING_WAIT)/100; - - /* wait for data to drain from the buffer */ - spin_lock_irqsave(&port->ep_lock, flags); - init_waitqueue_entry(&wait, current); - add_wait_queue(&tty->write_wait, &wait); - for (;;) { - set_current_state(TASK_INTERRUPTIBLE); - if (kfifo_len(&port->write_fifo) == 0 - || timeout == 0 || signal_pending(current) - || !usb_get_intfdata(port->port->serial->interface)) - /* disconnect */ - break; - spin_unlock_irqrestore(&port->ep_lock, flags); - timeout = schedule_timeout(timeout); - spin_lock_irqsave(&port->ep_lock, flags); - } - set_current_state(TASK_RUNNING); - remove_wait_queue(&tty->write_wait, &wait); - if (flush) - kfifo_reset_out(&port->write_fifo); - spin_unlock_irqrestore(&port->ep_lock, flags); - tty_kref_put(tty); - - /* wait for data to drain from the device */ - timeout += jiffies; - while ((long)(jiffies - timeout) < 0 && !signal_pending(current) - && usb_get_intfdata(port->port->serial->interface)) { - /* not disconnected */ - if (!tx_active(port)) - break; - msleep(10); - } - - /* disconnected */ - if (!usb_get_intfdata(port->port->serial->interface)) - return; - - /* wait one more character time, based on baud rate */ - /* (tx_active doesn't seem to wait for the last byte) */ - baud_rate = port->baud_rate; - if (baud_rate == 0) - baud_rate = 50; - msleep(max(1, DIV_ROUND_UP(10000, baud_rate))); -} - static int choose_config(struct usb_device *dev) { /* @@ -614,14 +534,13 @@ static int choose_config(struct usb_device *dev) * configuration # 1, which is Config Descriptor 0. */ - dbg("%s - Number of Interfaces = %d", - __func__, dev->config->desc.bNumInterfaces); - dbg("%s - MAX Power = %d", - __func__, dev->config->desc.bMaxPower * 2); + dev_dbg(&dev->dev, "%s - Number of Interfaces = %d\n", + __func__, dev->config->desc.bNumInterfaces); + dev_dbg(&dev->dev, "%s - MAX Power = %d\n", + __func__, dev->config->desc.bMaxPower * 2); if (dev->config->desc.bNumInterfaces != 1) { - dev_err(&dev->dev, "%s - bNumInterfaces is not 1, ERROR!\n", - __func__); + dev_err(&dev->dev, "%s - bNumInterfaces is not 1, ERROR!\n", __func__); return -ENODEV; } @@ -681,8 +600,8 @@ static int get_descriptor_addr(struct edgeport_serial *serial, if (rom_desc->Type == desc_type) return start_address; - start_address = start_address + sizeof(struct ti_i2c_desc) - + rom_desc->Size; + start_address = start_address + sizeof(struct ti_i2c_desc) + + le16_to_cpu(rom_desc->Size); } while ((start_address < TI_MAX_I2C_SIZE) && rom_desc->Type); @@ -695,11 +614,11 @@ static int valid_csum(struct ti_i2c_desc *rom_desc, __u8 *buffer) __u16 i; __u8 cs = 0; - for (i = 0; i < rom_desc->Size; i++) + for (i = 0; i < le16_to_cpu(rom_desc->Size); i++) cs = (__u8)(cs + buffer[i]); if (cs != rom_desc->CheckSum) { - dbg("%s - Mismatch %x - %x", __func__, rom_desc->CheckSum, cs); + pr_debug("%s - Mismatch %x - %x", __func__, rom_desc->CheckSum, cs); return -EINVAL; } return 0; @@ -716,14 +635,11 @@ static int check_i2c_image(struct edgeport_serial *serial) __u16 ttype; rom_desc = kmalloc(sizeof(*rom_desc), GFP_KERNEL); - if (!rom_desc) { - dev_err(dev, "%s - out of memory\n", __func__); + if (!rom_desc) return -ENOMEM; - } + buffer = kmalloc(TI_MAX_I2C_SIZE, GFP_KERNEL); if (!buffer) { - dev_err(dev, "%s - out of memory when allocating buffer\n", - __func__); kfree(rom_desc); return -ENOMEM; } @@ -749,13 +665,13 @@ static int check_i2c_image(struct edgeport_serial *serial) break; if ((start_address + sizeof(struct ti_i2c_desc) + - rom_desc->Size) > TI_MAX_I2C_SIZE) { + le16_to_cpu(rom_desc->Size)) > TI_MAX_I2C_SIZE) { status = -ENODEV; - dbg("%s - structure too big, erroring out.", __func__); + dev_dbg(dev, "%s - structure too big, erroring out.\n", __func__); break; } - dbg("%s Type = 0x%x", __func__, rom_desc->Type); + dev_dbg(dev, "%s Type = 0x%x\n", __func__, rom_desc->Type); /* Skip type 2 record */ ttype = rom_desc->Type & 0x0f; @@ -764,7 +680,8 @@ static int check_i2c_image(struct edgeport_serial *serial) /* Read the descriptor data */ status = read_rom(serial, start_address + sizeof(struct ti_i2c_desc), - rom_desc->Size, buffer); + le16_to_cpu(rom_desc->Size), + buffer); if (status) break; @@ -773,7 +690,7 @@ static int check_i2c_image(struct edgeport_serial *serial) break; } start_address = start_address + sizeof(struct ti_i2c_desc) + - rom_desc->Size; + le16_to_cpu(rom_desc->Size); } while ((rom_desc->Type != I2C_DESC_TYPE_ION) && (start_address < TI_MAX_I2C_SIZE)); @@ -794,37 +711,36 @@ static int get_manuf_info(struct edgeport_serial *serial, __u8 *buffer) int start_address; struct ti_i2c_desc *rom_desc; struct edge_ti_manuf_descriptor *desc; + struct device *dev = &serial->serial->dev->dev; rom_desc = kmalloc(sizeof(*rom_desc), GFP_KERNEL); - if (!rom_desc) { - dev_err(&serial->serial->dev->dev, "%s - out of memory\n", - __func__); + if (!rom_desc) return -ENOMEM; - } + start_address = get_descriptor_addr(serial, I2C_DESC_TYPE_ION, rom_desc); if (!start_address) { - dbg("%s - Edge Descriptor not found in I2C", __func__); + dev_dbg(dev, "%s - Edge Descriptor not found in I2C\n", __func__); status = -ENODEV; goto exit; } /* Read the descriptor data */ status = read_rom(serial, start_address+sizeof(struct ti_i2c_desc), - rom_desc->Size, buffer); + le16_to_cpu(rom_desc->Size), buffer); if (status) goto exit; status = valid_csum(rom_desc, buffer); desc = (struct edge_ti_manuf_descriptor *)buffer; - dbg("%s - IonConfig 0x%x", __func__, desc->IonConfig); - dbg("%s - Version %d", __func__, desc->Version); - dbg("%s - Cpu/Board 0x%x", __func__, desc->CpuRev_BoardRev); - dbg("%s - NumPorts %d", __func__, desc->NumPorts); - dbg("%s - NumVirtualPorts %d", __func__, desc->NumVirtualPorts); - dbg("%s - TotalPorts %d", __func__, desc->TotalPorts); + dev_dbg(dev, "%s - IonConfig 0x%x\n", __func__, desc->IonConfig); + dev_dbg(dev, "%s - Version %d\n", __func__, desc->Version); + dev_dbg(dev, "%s - Cpu/Board 0x%x\n", __func__, desc->CpuRev_BoardRev); + dev_dbg(dev, "%s - NumPorts %d\n", __func__, desc->NumPorts); + dev_dbg(dev, "%s - NumVirtualPorts %d\n", __func__, desc->NumVirtualPorts); + dev_dbg(dev, "%s - TotalPorts %d\n", __func__, desc->TotalPorts); exit: kfree(rom_desc); @@ -860,18 +776,16 @@ static int build_i2c_fw_hdr(__u8 *header, struct device *dev) sizeof(struct ti_i2c_firmware_rec)); buffer = kmalloc(buffer_size, GFP_KERNEL); - if (!buffer) { - dev_err(dev, "%s - out of memory\n", __func__); + if (!buffer) return -ENOMEM; - } // Set entire image of 0xffs memset(buffer, 0xff, buffer_size); err = request_firmware(&fw, fw_name, dev); if (err) { - printk(KERN_ERR "Failed to load image \"%s\" err %d\n", - fw_name, err); + dev_err(dev, "Failed to load image \"%s\" err %d\n", + fw_name, err); kfree(buffer); return err; } @@ -907,7 +821,7 @@ static int build_i2c_fw_hdr(__u8 *header, struct device *dev) firmware_rec = (struct ti_i2c_firmware_rec*)i2c_header->Data; i2c_header->Type = I2C_DESC_TYPE_FIRMWARE_BLANK; - i2c_header->Size = (__u16)buffer_size; + i2c_header->Size = cpu_to_le16(buffer_size); i2c_header->CheckSum = cs; firmware_rec->Ver_Major = OperationalMajorVersion; firmware_rec->Ver_Minor = OperationalMinorVersion; @@ -918,25 +832,23 @@ static int build_i2c_fw_hdr(__u8 *header, struct device *dev) /* Try to figure out what type of I2c we have */ static int i2c_type_bootmode(struct edgeport_serial *serial) { + struct device *dev = &serial->serial->dev->dev; int status; u8 *data; data = kmalloc(1, GFP_KERNEL); - if (!data) { - dev_err(&serial->serial->dev->dev, - "%s - out of memory\n", __func__); + if (!data) return -ENOMEM; - } /* Try to read type 2 */ status = ti_vread_sync(serial->serial->dev, UMPC_MEMORY_READ, DTK_ADDR_SPACE_I2C_TYPE_II, 0, data, 0x01); if (status) - dbg("%s - read 2 status error = %d", __func__, status); + dev_dbg(dev, "%s - read 2 status error = %d\n", __func__, status); else - dbg("%s - read 2 data = 0x%x", __func__, *data); + dev_dbg(dev, "%s - read 2 data = 0x%x\n", __func__, *data); if ((!status) && (*data == UMP5152 || *data == UMP3410)) { - dbg("%s - ROM_TYPE_II", __func__); + dev_dbg(dev, "%s - ROM_TYPE_II\n", __func__); serial->TI_I2C_Type = DTK_ADDR_SPACE_I2C_TYPE_II; goto out; } @@ -945,16 +857,16 @@ static int i2c_type_bootmode(struct edgeport_serial *serial) status = ti_vread_sync(serial->serial->dev, UMPC_MEMORY_READ, DTK_ADDR_SPACE_I2C_TYPE_III, 0, data, 0x01); if (status) - dbg("%s - read 3 status error = %d", __func__, status); + dev_dbg(dev, "%s - read 3 status error = %d\n", __func__, status); else - dbg("%s - read 2 data = 0x%x", __func__, *data); + dev_dbg(dev, "%s - read 2 data = 0x%x\n", __func__, *data); if ((!status) && (*data == UMP5152 || *data == UMP3410)) { - dbg("%s - ROM_TYPE_III", __func__); + dev_dbg(dev, "%s - ROM_TYPE_III\n", __func__); serial->TI_I2C_Type = DTK_ADDR_SPACE_I2C_TYPE_III; goto out; } - dbg("%s - Unknown", __func__); + dev_dbg(dev, "%s - Unknown\n", __func__); serial->TI_I2C_Type = DTK_ADDR_SPACE_I2C_TYPE_II; status = -ENODEV; out: @@ -1065,11 +977,11 @@ static int download_fw(struct edgeport_serial *serial) if (serial->product_info.TiMode == TI_MODE_DOWNLOAD) { struct ti_i2c_desc *rom_desc; - dbg("%s - RUNNING IN DOWNLOAD MODE", __func__); + dev_dbg(dev, "%s - RUNNING IN DOWNLOAD MODE\n", __func__); status = check_i2c_image(serial); if (status) { - dbg("%s - DOWNLOAD MODE -- BAD I2C", __func__); + dev_dbg(dev, "%s - DOWNLOAD MODE -- BAD I2C\n", __func__); return status; } @@ -1077,10 +989,9 @@ static int download_fw(struct edgeport_serial *serial) * Read Manufacturing Descriptor from TI Based Edgeport */ ti_manuf_desc = kmalloc(sizeof(*ti_manuf_desc), GFP_KERNEL); - if (!ti_manuf_desc) { - dev_err(dev, "%s - out of memory.\n", __func__); + if (!ti_manuf_desc) return -ENOMEM; - } + status = get_manuf_info(serial, (__u8 *)ti_manuf_desc); if (status) { kfree(ti_manuf_desc); @@ -1089,7 +1000,7 @@ static int download_fw(struct edgeport_serial *serial) /* Check version number of ION descriptor */ if (!ignore_cpu_rev && ti_cpu_rev(ti_manuf_desc) < 2) { - dbg("%s - Wrong CPU Rev %d (Must be 2)", + dev_dbg(dev, "%s - Wrong CPU Rev %d (Must be 2)\n", __func__, ti_cpu_rev(ti_manuf_desc)); kfree(ti_manuf_desc); return -EINVAL; @@ -1097,7 +1008,6 @@ static int download_fw(struct edgeport_serial *serial) rom_desc = kmalloc(sizeof(*rom_desc), GFP_KERNEL); if (!rom_desc) { - dev_err(dev, "%s - out of memory.\n", __func__); kfree(ti_manuf_desc); return -ENOMEM; } @@ -1109,13 +1019,11 @@ static int download_fw(struct edgeport_serial *serial) struct ti_i2c_firmware_rec *firmware_version; u8 *record; - dbg("%s - Found Type FIRMWARE (Type 2) record", - __func__); + dev_dbg(dev, "%s - Found Type FIRMWARE (Type 2) record\n", __func__); firmware_version = kmalloc(sizeof(*firmware_version), GFP_KERNEL); if (!firmware_version) { - dev_err(dev, "%s - out of memory.\n", __func__); kfree(rom_desc); kfree(ti_manuf_desc); return -ENOMEM; @@ -1142,27 +1050,24 @@ static int download_fw(struct edgeport_serial *serial) download_new_ver = (OperationalMajorVersion << 8) + (OperationalMinorVersion); - dbg("%s - >> FW Versions Device %d.%d Driver %d.%d", - __func__, - firmware_version->Ver_Major, - firmware_version->Ver_Minor, - OperationalMajorVersion, - OperationalMinorVersion); + dev_dbg(dev, "%s - >> FW Versions Device %d.%d Driver %d.%d\n", + __func__, firmware_version->Ver_Major, + firmware_version->Ver_Minor, + OperationalMajorVersion, + OperationalMinorVersion); /* Check if we have an old version in the I2C and update if necessary */ if (download_cur_ver < download_new_ver) { - dbg("%s - Update I2C dld from %d.%d to %d.%d", - __func__, - firmware_version->Ver_Major, - firmware_version->Ver_Minor, - OperationalMajorVersion, - OperationalMinorVersion); + dev_dbg(dev, "%s - Update I2C dld from %d.%d to %d.%d\n", + __func__, + firmware_version->Ver_Major, + firmware_version->Ver_Minor, + OperationalMajorVersion, + OperationalMinorVersion); record = kmalloc(1, GFP_KERNEL); if (!record) { - dev_err(dev, "%s - out of memory.\n", - __func__); kfree(firmware_version); kfree(rom_desc); kfree(ti_manuf_desc); @@ -1211,9 +1116,7 @@ static int download_fw(struct edgeport_serial *serial) } if (*record != I2C_DESC_TYPE_FIRMWARE_BLANK) { - dev_err(dev, - "%s - error resetting device\n", - __func__); + dev_err(dev, "%s - error resetting device\n", __func__); kfree(record); kfree(firmware_version); kfree(rom_desc); @@ -1221,15 +1124,14 @@ static int download_fw(struct edgeport_serial *serial) return -ENODEV; } - dbg("%s - HARDWARE RESET", __func__); + dev_dbg(dev, "%s - HARDWARE RESET\n", __func__); /* Reset UMP -- Back to BOOT MODE */ status = ti_vsend_sync(serial->serial->dev, UMPC_HARDWARE_RESET, 0, 0, NULL, 0); - dbg("%s - HARDWARE RESET return %d", - __func__, status); + dev_dbg(dev, "%s - HARDWARE RESET return %d\n", __func__, status); /* return an error on purpose. */ kfree(record); @@ -1249,7 +1151,6 @@ static int download_fw(struct edgeport_serial *serial) header = kmalloc(HEADER_SIZE, GFP_KERNEL); if (!header) { - dev_err(dev, "%s - out of memory.\n", __func__); kfree(rom_desc); kfree(ti_manuf_desc); return -ENOMEM; @@ -1257,15 +1158,13 @@ static int download_fw(struct edgeport_serial *serial) vheader = kmalloc(HEADER_SIZE, GFP_KERNEL); if (!vheader) { - dev_err(dev, "%s - out of memory.\n", __func__); kfree(header); kfree(rom_desc); kfree(ti_manuf_desc); return -ENOMEM; } - dbg("%s - Found Type BLANK FIRMWARE (Type F2) record", - __func__); + dev_dbg(dev, "%s - Found Type BLANK FIRMWARE (Type F2) record\n", __func__); /* * In order to update the I2C firmware we must change @@ -1307,7 +1206,7 @@ static int download_fw(struct edgeport_serial *serial) HEADER_SIZE, vheader); if (status) { - dbg("%s - can't read header back", __func__); + dev_dbg(dev, "%s - can't read header back\n", __func__); kfree(vheader); kfree(header); kfree(rom_desc); @@ -1315,8 +1214,7 @@ static int download_fw(struct edgeport_serial *serial) return status; } if (memcmp(vheader, header, HEADER_SIZE)) { - dbg("%s - write download record failed", - __func__); + dev_dbg(dev, "%s - write download record failed\n", __func__); kfree(vheader); kfree(header); kfree(rom_desc); @@ -1327,13 +1225,13 @@ static int download_fw(struct edgeport_serial *serial) kfree(vheader); kfree(header); - dbg("%s - Start firmware update", __func__); + dev_dbg(dev, "%s - Start firmware update\n", __func__); /* Tell firmware to copy download image into I2C */ status = ti_vsend_sync(serial->serial->dev, UMPC_COPY_DNLD_TO_I2C, 0, 0, NULL, 0); - dbg("%s - Update complete 0x%x", __func__, status); + dev_dbg(dev, "%s - Update complete 0x%x\n", __func__, status); if (status) { dev_err(dev, "%s - UMPC_COPY_DNLD_TO_I2C failed\n", @@ -1353,7 +1251,7 @@ static int download_fw(struct edgeport_serial *serial) /********************************************************************/ /* Boot Mode */ /********************************************************************/ - dbg("%s - RUNNING IN BOOT MODE", __func__); + dev_dbg(dev, "%s - RUNNING IN BOOT MODE\n", __func__); /* Configure the TI device so we can use the BULK pipes for download */ status = config_boot_dev(serial->serial->dev); @@ -1362,8 +1260,8 @@ static int download_fw(struct edgeport_serial *serial) if (le16_to_cpu(serial->serial->dev->descriptor.idVendor) != USB_VENDOR_ID_ION) { - dbg("%s - VID = 0x%x", __func__, - le16_to_cpu(serial->serial->dev->descriptor.idVendor)); + dev_dbg(dev, "%s - VID = 0x%x\n", __func__, + le16_to_cpu(serial->serial->dev->descriptor.idVendor)); serial->TI_I2C_Type = DTK_ADDR_SPACE_I2C_TYPE_II; goto stayinbootmode; } @@ -1388,10 +1286,9 @@ static int download_fw(struct edgeport_serial *serial) * Read Manufacturing Descriptor from TI Based Edgeport */ ti_manuf_desc = kmalloc(sizeof(*ti_manuf_desc), GFP_KERNEL); - if (!ti_manuf_desc) { - dev_err(dev, "%s - out of memory.\n", __func__); + if (!ti_manuf_desc) return -ENOMEM; - } + status = get_manuf_info(serial, (__u8 *)ti_manuf_desc); if (status) { kfree(ti_manuf_desc); @@ -1400,8 +1297,8 @@ static int download_fw(struct edgeport_serial *serial) /* Check for version 2 */ if (!ignore_cpu_rev && ti_cpu_rev(ti_manuf_desc) < 2) { - dbg("%s - Wrong CPU Rev %d (Must be 2)", - __func__, ti_cpu_rev(ti_manuf_desc)); + dev_dbg(dev, "%s - Wrong CPU Rev %d (Must be 2)\n", + __func__, ti_cpu_rev(ti_manuf_desc)); kfree(ti_manuf_desc); goto stayinbootmode; } @@ -1426,18 +1323,16 @@ static int download_fw(struct edgeport_serial *serial) buffer_size = (((1024 * 16) - 512) + sizeof(struct ti_i2c_image_header)); buffer = kmalloc(buffer_size, GFP_KERNEL); - if (!buffer) { - dev_err(dev, "%s - out of memory\n", __func__); + if (!buffer) return -ENOMEM; - } /* Initialize the buffer to 0xff (pad the buffer) */ memset(buffer, 0xff, buffer_size); err = request_firmware(&fw, fw_name, dev); if (err) { - printk(KERN_ERR "Failed to load image \"%s\" err %d\n", - fw_name, err); + dev_err(dev, "Failed to load image \"%s\" err %d\n", + fw_name, err); kfree(buffer); return err; } @@ -1457,23 +1352,20 @@ static int download_fw(struct edgeport_serial *serial) header->CheckSum = cs; /* Download the operational code */ - dbg("%s - Downloading operational code image (TI UMP)", - __func__); + dev_dbg(dev, "%s - Downloading operational code image (TI UMP)\n", __func__); status = download_code(serial, buffer, buffer_size); kfree(buffer); if (status) { - dbg("%s - Error downloading operational code image", - __func__); + dev_dbg(dev, "%s - Error downloading operational code image\n", __func__); return status; } /* Device will reboot */ serial->product_info.TiMode = TI_MODE_TRANSITIONING; - dbg("%s - Download successful -- Device rebooting...", - __func__); + dev_dbg(dev, "%s - Download successful -- Device rebooting...\n", __func__); /* return an error on purpose */ return -ENODEV; @@ -1481,7 +1373,7 @@ static int download_fw(struct edgeport_serial *serial) stayinbootmode: /* Eprom is invalid or blank stay in boot mode */ - dbg("%s - STAYING IN BOOT MODE", __func__); + dev_dbg(dev, "%s - STAYING IN BOOT MODE\n", __func__); serial->product_info.TiMode = TI_MODE_BOOT; return 0; @@ -1490,7 +1382,8 @@ stayinbootmode: static int ti_do_config(struct edgeport_port *port, int feature, int on) { - int port_number = port->port->number - port->port->serial->minor; + int port_number = port->port->port_number; + on = !!on; /* 1 or 0 not bitmask */ return send_cmd(port->port->serial->dev, feature, (__u8)(UMPM_UART1_PORT + port_number), @@ -1502,7 +1395,7 @@ static int restore_mcr(struct edgeport_port *port, __u8 mcr) { int status = 0; - dbg("%s - %x", __func__, mcr); + dev_dbg(&port->port->dev, "%s - %x\n", __func__, mcr); status = ti_do_config(port, UMPC_SET_CLR_DTR, mcr & MCR_DTR); if (status) @@ -1539,11 +1432,11 @@ static void handle_new_msr(struct edgeport_port *edge_port, __u8 msr) struct async_icount *icount; struct tty_struct *tty; - dbg("%s - %02x", __func__, msr); + dev_dbg(&edge_port->port->dev, "%s - %02x\n", __func__, msr); if (msr & (EDGEPORT_MSR_DELTA_CTS | EDGEPORT_MSR_DELTA_DSR | EDGEPORT_MSR_DELTA_RI | EDGEPORT_MSR_DELTA_CD)) { - icount = &edge_port->icount; + icount = &edge_port->port->icount; /* update input line counters */ if (msr & EDGEPORT_MSR_DELTA_CTS) @@ -1554,7 +1447,7 @@ static void handle_new_msr(struct edgeport_port *edge_port, __u8 msr) icount->dcd++; if (msr & EDGEPORT_MSR_DELTA_RI) icount->rng++; - wake_up_interruptible(&edge_port->delta_msr_wait); + wake_up_interruptible(&edge_port->port->port.delta_msr_wait); } /* Save the new modem status */ @@ -1579,9 +1472,8 @@ static void handle_new_lsr(struct edgeport_port *edge_port, int lsr_data, struct async_icount *icount; __u8 new_lsr = (__u8)(lsr & (__u8)(LSR_OVER_ERR | LSR_PAR_ERR | LSR_FRM_ERR | LSR_BREAK)); - struct tty_struct *tty; - dbg("%s - %02x", __func__, new_lsr); + dev_dbg(&edge_port->port->dev, "%s - %02x\n", __func__, new_lsr); edge_port->shadow_lsr = lsr; @@ -1593,16 +1485,11 @@ static void handle_new_lsr(struct edgeport_port *edge_port, int lsr_data, new_lsr &= (__u8)(LSR_OVER_ERR | LSR_BREAK); /* Place LSR data byte into Rx buffer */ - if (lsr_data) { - tty = tty_port_tty_get(&edge_port->port->port); - if (tty) { - edge_tty_recv(&edge_port->port->dev, tty, &data, 1); - tty_kref_put(tty); - } - } + if (lsr_data) + edge_tty_recv(edge_port->port, &data, 1); /* update input line counters */ - icount = &edge_port->icount; + icount = &edge_port->port->icount; if (new_lsr & LSR_BREAK) icount->brk++; if (new_lsr & LSR_OVER_ERR) @@ -1619,6 +1506,7 @@ static void edge_interrupt_callback(struct urb *urb) struct edgeport_serial *edge_serial = urb->context; struct usb_serial_port *port; struct edgeport_port *edge_port; + struct device *dev; unsigned char *data = urb->transfer_buffer; int length = urb->actual_length; int port_number; @@ -1628,8 +1516,6 @@ static void edge_interrupt_callback(struct urb *urb) __u8 msr; int status = urb->status; - dbg("%s", __func__); - switch (status) { case 0: /* success */ @@ -1638,7 +1524,7 @@ static void edge_interrupt_callback(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", + dev_dbg(&urb->dev->dev, "%s - urb shutting down with status: %d\n", __func__, status); return; default: @@ -1648,27 +1534,26 @@ static void edge_interrupt_callback(struct urb *urb) } if (!length) { - dbg("%s - no data in urb", __func__); + dev_dbg(&urb->dev->dev, "%s - no data in urb\n", __func__); goto exit; } - usb_serial_debug_data(debug, &edge_serial->serial->dev->dev, - __func__, length, data); + dev = &edge_serial->serial->dev->dev; + usb_serial_debug_data(dev, __func__, length, data); if (length != 2) { - dbg("%s - expecting packet of size 2, got %d", - __func__, length); + dev_dbg(dev, "%s - expecting packet of size 2, got %d\n", __func__, length); goto exit; } port_number = TIUMP_GET_PORT_FROM_CODE(data[0]); function = TIUMP_GET_FUNC_FROM_CODE(data[0]); - dbg("%s - port_number %d, function %d, info 0x%x", - __func__, port_number, function, data[1]); + dev_dbg(dev, "%s - port_number %d, function %d, info 0x%x\n", __func__, + port_number, function, data[1]); port = edge_serial->serial->port[port_number]; edge_port = usb_get_serial_port_data(port); if (!edge_port) { - dbg("%s - edge_port not found", __func__); + dev_dbg(dev, "%s - edge_port not found\n", __func__); return; } switch (function) { @@ -1677,13 +1562,13 @@ static void edge_interrupt_callback(struct urb *urb) if (lsr & UMP_UART_LSR_DATA_MASK) { /* Save the LSR event for bulk read completion routine */ - dbg("%s - LSR Event Port %u LSR Status = %02x", - __func__, port_number, lsr); + dev_dbg(dev, "%s - LSR Event Port %u LSR Status = %02x\n", + __func__, port_number, lsr); edge_port->lsr_event = 1; edge_port->lsr_mask = lsr; } else { - dbg("%s - ===== Port %d LSR Status = %02x ======", - __func__, port_number, lsr); + dev_dbg(dev, "%s - ===== Port %d LSR Status = %02x ======\n", + __func__, port_number, lsr); handle_new_lsr(edge_port, 0, lsr, 0); } break; @@ -1691,8 +1576,8 @@ static void edge_interrupt_callback(struct urb *urb) case TIUMP_INTERRUPT_CODE_MSR: /* MSR */ /* Copy MSR from UMP */ msr = data[1]; - dbg("%s - ===== Port %u MSR Status = %02x ======", - __func__, port_number, msr); + dev_dbg(dev, "%s - ===== Port %u MSR Status = %02x ======\n", + __func__, port_number, msr); handle_new_msr(edge_port, msr); break; @@ -1715,14 +1600,12 @@ exit: static void edge_bulk_in_callback(struct urb *urb) { struct edgeport_port *edge_port = urb->context; + struct device *dev = &edge_port->port->dev; unsigned char *data = urb->transfer_buffer; - struct tty_struct *tty; int retval = 0; int port_number; int status = urb->status; - dbg("%s", __func__); - switch (status) { case 0: /* success */ @@ -1731,13 +1614,10 @@ static void edge_bulk_in_callback(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", - __func__, status); + dev_dbg(&urb->dev->dev, "%s - urb shutting down with status: %d\n", __func__, status); return; default: - dev_err(&urb->dev->dev, - "%s - nonzero read bulk status received: %d\n", - __func__, status); + dev_err(&urb->dev->dev, "%s - nonzero read bulk status received: %d\n", __func__, status); } if (status == -EPIPE) @@ -1748,58 +1628,52 @@ static void edge_bulk_in_callback(struct urb *urb) return; } - port_number = edge_port->port->number - edge_port->port->serial->minor; + port_number = edge_port->port->port_number; if (edge_port->lsr_event) { edge_port->lsr_event = 0; - dbg("%s ===== Port %u LSR Status = %02x, Data = %02x ======", - __func__, port_number, edge_port->lsr_mask, *data); + dev_dbg(dev, "%s ===== Port %u LSR Status = %02x, Data = %02x ======\n", + __func__, port_number, edge_port->lsr_mask, *data); handle_new_lsr(edge_port, 1, edge_port->lsr_mask, *data); /* Adjust buffer length/pointer */ --urb->actual_length; ++data; } - tty = tty_port_tty_get(&edge_port->port->port); - if (tty && urb->actual_length) { - usb_serial_debug_data(debug, &edge_port->port->dev, - __func__, urb->actual_length, data); + if (urb->actual_length) { + usb_serial_debug_data(dev, __func__, urb->actual_length, data); if (edge_port->close_pending) - dbg("%s - close pending, dropping data on the floor", + dev_dbg(dev, "%s - close pending, dropping data on the floor\n", __func__); else - edge_tty_recv(&edge_port->port->dev, tty, data, - urb->actual_length); - edge_port->icount.rx += urb->actual_length; + edge_tty_recv(edge_port->port, data, + urb->actual_length); + edge_port->port->icount.rx += urb->actual_length; } - tty_kref_put(tty); exit: /* continue read unless stopped */ spin_lock(&edge_port->ep_lock); - if (edge_port->ep_read_urb_state == EDGE_READ_URB_RUNNING) { - urb->dev = edge_port->port->serial->dev; + if (edge_port->ep_read_urb_state == EDGE_READ_URB_RUNNING) retval = usb_submit_urb(urb, GFP_ATOMIC); - } else if (edge_port->ep_read_urb_state == EDGE_READ_URB_STOPPING) { + else if (edge_port->ep_read_urb_state == EDGE_READ_URB_STOPPING) edge_port->ep_read_urb_state = EDGE_READ_URB_STOPPED; - } + spin_unlock(&edge_port->ep_lock); if (retval) - dev_err(&urb->dev->dev, - "%s - usb_submit_urb failed with result %d\n", - __func__, retval); + dev_err(dev, "%s - usb_submit_urb failed with result %d\n", __func__, retval); } -static void edge_tty_recv(struct device *dev, struct tty_struct *tty, - unsigned char *data, int length) +static void edge_tty_recv(struct usb_serial_port *port, unsigned char *data, + int length) { int queued; - queued = tty_insert_flip_string(tty, data, length); + queued = tty_insert_flip_string(&port->port, data, length); if (queued < length) - dev_err(dev, "%s - dropping data, %d bytes lost\n", + dev_err(&port->dev, "%s - dropping data, %d bytes lost\n", __func__, length - queued); - tty_flip_buffer_push(tty); + tty_flip_buffer_push(&port->port); } static void edge_bulk_out_callback(struct urb *urb) @@ -1809,8 +1683,6 @@ static void edge_bulk_out_callback(struct urb *urb) int status = urb->status; struct tty_struct *tty; - dbg("%s - port %d", __func__, port->number); - edge_port->ep_write_urb_in_use = 0; switch (status) { @@ -1821,17 +1693,17 @@ static void edge_bulk_out_callback(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", + dev_dbg(&urb->dev->dev, "%s - urb shutting down with status: %d\n", __func__, status); return; default: - dev_err(&urb->dev->dev, "%s - nonzero write bulk status " + dev_err_console(port, "%s - nonzero write bulk status " "received: %d\n", __func__, status); } /* send any buffered data */ tty = tty_port_tty_get(&port->port); - edge_send(tty); + edge_send(port, tty); tty_kref_put(tty); } @@ -1846,35 +1718,13 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port) u16 open_settings; u8 transaction_timeout; - dbg("%s - port %d", __func__, port->number); - if (edge_port == NULL) return -ENODEV; - port_number = port->number - port->serial->minor; - switch (port_number) { - case 0: - edge_port->uart_base = UMPMEM_BASE_UART1; - edge_port->dma_address = UMPD_OEDB1_ADDRESS; - break; - case 1: - edge_port->uart_base = UMPMEM_BASE_UART2; - edge_port->dma_address = UMPD_OEDB2_ADDRESS; - break; - default: - dev_err(&port->dev, "Unknown port number!!!\n"); - return -ENODEV; - } - - dbg("%s - port_number = %d, uart_base = %04x, dma_address = %04x", - __func__, port_number, edge_port->uart_base, - edge_port->dma_address); + port_number = port->port_number; dev = port->serial->dev; - memset(&(edge_port->icount), 0x00, sizeof(edge_port->icount)); - init_waitqueue_head(&edge_port->delta_msr_wait); - /* turn off loopback */ status = ti_do_config(edge_port, UMPC_SET_CLR_LOOPBACK, 0); if (status) { @@ -1886,7 +1736,7 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port) /* set up the port settings */ if (tty) - edge_set_termios(tty, port, tty->termios); + edge_set_termios(tty, port, &tty->termios); /* open up the port */ @@ -1901,7 +1751,7 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port) UMP_PIPE_TRANS_TIMEOUT_ENA | (transaction_timeout << 2)); - dbg("%s - Sending UMPC_OPEN_PORT", __func__); + dev_dbg(&port->dev, "%s - Sending UMPC_OPEN_PORT\n", __func__); /* Tell TI to open and start the port */ status = send_cmd(dev, UMPC_OPEN_PORT, @@ -1940,11 +1790,11 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port) return status; } - dbg("ShadowMSR 0x%X", edge_port->shadow_msr); + dev_dbg(&port->dev, "ShadowMSR 0x%X\n", edge_port->shadow_msr); /* Set Initial MCR */ edge_port->shadow_mcr = MCR_RTS | MCR_DTR; - dbg("ShadowMCR 0x%X", edge_port->shadow_mcr); + dev_dbg(&port->dev, "ShadowMCR 0x%X\n", edge_port->shadow_mcr); edge_serial = edge_port->edge_serial; if (mutex_lock_interruptible(&edge_serial->es_lock)) @@ -1959,9 +1809,7 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port) status = -EINVAL; goto release_es_lock; } - urb->complete = edge_interrupt_callback; urb->context = edge_serial; - urb->dev = dev; status = usb_submit_urb(urb, GFP_KERNEL); if (status) { dev_err(&port->dev, @@ -1987,9 +1835,7 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port) goto unlink_int_urb; } edge_port->ep_read_urb_state = EDGE_READ_URB_RUNNING; - urb->complete = edge_bulk_in_callback; urb->context = edge_port; - urb->dev = dev; status = usb_submit_urb(urb, GFP_KERNEL); if (status) { dev_err(&port->dev, @@ -2000,8 +1846,6 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port) ++edge_serial->num_ports_open; - dbg("%s - exited", __func__); - goto release_es_lock; unlink_int_urb: @@ -2016,10 +1860,9 @@ static void edge_close(struct usb_serial_port *port) { struct edgeport_serial *edge_serial; struct edgeport_port *edge_port; + struct usb_serial *serial = port->serial; + unsigned long flags; int port_number; - int status; - - dbg("%s - port %d", __func__, port->number); edge_serial = usb_get_serial_data(port->serial); edge_port = usb_get_serial_port_data(port); @@ -2030,23 +1873,18 @@ static void edge_close(struct usb_serial_port *port) * this flag and dump add read data */ edge_port->close_pending = 1; - /* chase the port close and flush */ - chase_port(edge_port, (HZ * closing_wait) / 100, 1); - usb_kill_urb(port->read_urb); usb_kill_urb(port->write_urb); edge_port->ep_write_urb_in_use = 0; + spin_lock_irqsave(&edge_port->ep_lock, flags); + kfifo_reset_out(&port->write_fifo); + spin_unlock_irqrestore(&edge_port->ep_lock, flags); + + dev_dbg(&port->dev, "%s - send umpc_close_port\n", __func__); + port_number = port->port_number; + send_cmd(serial->dev, UMPC_CLOSE_PORT, + (__u8)(UMPM_UART1_PORT + port_number), 0, NULL, 0); - /* assuming we can still talk to the device, - * send a close port command to it */ - dbg("%s - send umpc_close_port", __func__); - port_number = port->number - port->serial->minor; - status = send_cmd(port->serial->dev, - UMPC_CLOSE_PORT, - (__u8)(UMPM_UART1_PORT + port_number), - 0, - NULL, - 0); mutex_lock(&edge_serial->es_lock); --edge_port->edge_serial->num_ports_open; if (edge_port->edge_serial->num_ports_open <= 0) { @@ -2056,8 +1894,6 @@ static void edge_close(struct usb_serial_port *port) } mutex_unlock(&edge_serial->es_lock); edge_port->close_pending = 0; - - dbg("%s - exited", __func__); } static int edge_write(struct tty_struct *tty, struct usb_serial_port *port, @@ -2065,10 +1901,8 @@ static int edge_write(struct tty_struct *tty, struct usb_serial_port *port, { struct edgeport_port *edge_port = usb_get_serial_port_data(port); - dbg("%s - port %d", __func__, port->number); - if (count == 0) { - dbg("%s - write request of 0 bytes", __func__); + dev_dbg(&port->dev, "%s - write request of 0 bytes\n", __func__); return 0; } @@ -2077,23 +1911,19 @@ static int edge_write(struct tty_struct *tty, struct usb_serial_port *port, if (edge_port->close_pending == 1) return -ENODEV; - count = kfifo_in_locked(&edge_port->write_fifo, data, count, + count = kfifo_in_locked(&port->write_fifo, data, count, &edge_port->ep_lock); - edge_send(tty); + edge_send(port, tty); return count; } -static void edge_send(struct tty_struct *tty) +static void edge_send(struct usb_serial_port *port, struct tty_struct *tty) { - struct usb_serial_port *port = tty->driver_data; int count, result; struct edgeport_port *edge_port = usb_get_serial_port_data(port); unsigned long flags; - - dbg("%s - port %d", __func__, port->number); - spin_lock_irqsave(&edge_port->ep_lock, flags); if (edge_port->ep_write_urb_in_use) { @@ -2101,7 +1931,7 @@ static void edge_send(struct tty_struct *tty) return; } - count = kfifo_out(&edge_port->write_fifo, + count = kfifo_out(&port->write_fifo, port->write_urb->transfer_buffer, port->bulk_out_size); @@ -2114,27 +1944,21 @@ static void edge_send(struct tty_struct *tty) spin_unlock_irqrestore(&edge_port->ep_lock, flags); - usb_serial_debug_data(debug, &port->dev, __func__, count, - port->write_urb->transfer_buffer); + usb_serial_debug_data(&port->dev, __func__, count, port->write_urb->transfer_buffer); /* set up our urb */ - usb_fill_bulk_urb(port->write_urb, port->serial->dev, - usb_sndbulkpipe(port->serial->dev, - port->bulk_out_endpointAddress), - port->write_urb->transfer_buffer, count, - edge_bulk_out_callback, - port); + port->write_urb->transfer_buffer_length = count; /* send the data out the bulk port */ result = usb_submit_urb(port->write_urb, GFP_ATOMIC); if (result) { - dev_err(&port->dev, + dev_err_console(port, "%s - failed submitting write urb, error %d\n", __func__, result); edge_port->ep_write_urb_in_use = 0; /* TODO: reschedule edge_send */ } else - edge_port->icount.tx += count; + edge_port->port->icount.tx += count; /* wakeup any process waiting for writes to complete */ /* there is now more room in the buffer for new writes */ @@ -2149,18 +1973,16 @@ static int edge_write_room(struct tty_struct *tty) int room = 0; unsigned long flags; - dbg("%s - port %d", __func__, port->number); - if (edge_port == NULL) return 0; if (edge_port->close_pending == 1) return 0; spin_lock_irqsave(&edge_port->ep_lock, flags); - room = kfifo_avail(&edge_port->write_fifo); + room = kfifo_avail(&port->write_fifo); spin_unlock_irqrestore(&edge_port->ep_lock, flags); - dbg("%s - returns %d", __func__, room); + dev_dbg(&port->dev, "%s - returns %d\n", __func__, room); return room; } @@ -2170,30 +1992,35 @@ static int edge_chars_in_buffer(struct tty_struct *tty) struct edgeport_port *edge_port = usb_get_serial_port_data(port); int chars = 0; unsigned long flags; - - dbg("%s - port %d", __func__, port->number); - if (edge_port == NULL) return 0; - if (edge_port->close_pending == 1) - return 0; spin_lock_irqsave(&edge_port->ep_lock, flags); - chars = kfifo_len(&edge_port->write_fifo); + chars = kfifo_len(&port->write_fifo); spin_unlock_irqrestore(&edge_port->ep_lock, flags); - dbg("%s - returns %d", __func__, chars); + dev_dbg(&port->dev, "%s - returns %d\n", __func__, chars); return chars; } +static bool edge_tx_empty(struct usb_serial_port *port) +{ + struct edgeport_port *edge_port = usb_get_serial_port_data(port); + int ret; + + ret = tx_active(edge_port); + if (ret > 0) + return false; + + return true; +} + static void edge_throttle(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; struct edgeport_port *edge_port = usb_get_serial_port_data(port); int status; - dbg("%s - port %d", __func__, port->number); - if (edge_port == NULL) return; @@ -2219,8 +2046,6 @@ static void edge_unthrottle(struct tty_struct *tty) struct edgeport_port *edge_port = usb_get_serial_port_data(port); int status; - dbg("%s - port %d", __func__, port->number); - if (edge_port == NULL) return; @@ -2267,9 +2092,6 @@ static int restart_read(struct edgeport_port *edge_port) if (edge_port->ep_read_urb_state == EDGE_READ_URB_STOPPED) { urb = edge_port->port->read_urb; - urb->complete = edge_bulk_in_callback; - urb->context = edge_port; - urb->dev = edge_port->port->serial->dev; status = usb_submit_urb(urb, GFP_ATOMIC); } edge_port->ep_read_urb_state = EDGE_READ_URB_RUNNING; @@ -2283,24 +2105,20 @@ static int restart_read(struct edgeport_port *edge_port) static void change_port_settings(struct tty_struct *tty, struct edgeport_port *edge_port, struct ktermios *old_termios) { + struct device *dev = &edge_port->port->dev; struct ump_uart_config *config; int baud; unsigned cflag; int status; - int port_number = edge_port->port->number - - edge_port->port->serial->minor; - - dbg("%s - port %d", __func__, edge_port->port->number); + int port_number = edge_port->port->port_number; config = kmalloc (sizeof (*config), GFP_KERNEL); if (!config) { - *tty->termios = *old_termios; - dev_err(&edge_port->port->dev, "%s - out of memory\n", - __func__); + tty->termios = *old_termios; return; } - cflag = tty->termios->c_cflag; + cflag = tty->termios.c_cflag; config->wFlags = 0; @@ -2312,20 +2130,20 @@ static void change_port_settings(struct tty_struct *tty, switch (cflag & CSIZE) { case CS5: config->bDataBits = UMP_UART_CHAR5BITS; - dbg("%s - data bits = 5", __func__); + dev_dbg(dev, "%s - data bits = 5\n", __func__); break; case CS6: config->bDataBits = UMP_UART_CHAR6BITS; - dbg("%s - data bits = 6", __func__); + dev_dbg(dev, "%s - data bits = 6\n", __func__); break; case CS7: config->bDataBits = UMP_UART_CHAR7BITS; - dbg("%s - data bits = 7", __func__); + dev_dbg(dev, "%s - data bits = 7\n", __func__); break; default: case CS8: config->bDataBits = UMP_UART_CHAR8BITS; - dbg("%s - data bits = 8", __func__); + dev_dbg(dev, "%s - data bits = 8\n", __func__); break; } @@ -2333,32 +2151,32 @@ static void change_port_settings(struct tty_struct *tty, if (cflag & PARODD) { config->wFlags |= UMP_MASK_UART_FLAGS_PARITY; config->bParity = UMP_UART_ODDPARITY; - dbg("%s - parity = odd", __func__); + dev_dbg(dev, "%s - parity = odd\n", __func__); } else { config->wFlags |= UMP_MASK_UART_FLAGS_PARITY; config->bParity = UMP_UART_EVENPARITY; - dbg("%s - parity = even", __func__); + dev_dbg(dev, "%s - parity = even\n", __func__); } } else { config->bParity = UMP_UART_NOPARITY; - dbg("%s - parity = none", __func__); + dev_dbg(dev, "%s - parity = none\n", __func__); } if (cflag & CSTOPB) { config->bStopBits = UMP_UART_STOPBIT2; - dbg("%s - stop bits = 2", __func__); + dev_dbg(dev, "%s - stop bits = 2\n", __func__); } else { config->bStopBits = UMP_UART_STOPBIT1; - dbg("%s - stop bits = 1", __func__); + dev_dbg(dev, "%s - stop bits = 1\n", __func__); } /* figure out the flow control settings */ if (cflag & CRTSCTS) { config->wFlags |= UMP_MASK_UART_FLAGS_OUT_X_CTS_FLOW; config->wFlags |= UMP_MASK_UART_FLAGS_RTS_FLOW; - dbg("%s - RTS/CTS is enabled", __func__); + dev_dbg(dev, "%s - RTS/CTS is enabled\n", __func__); } else { - dbg("%s - RTS/CTS is disabled", __func__); + dev_dbg(dev, "%s - RTS/CTS is disabled\n", __func__); tty->hw_stopped = 0; restart_read(edge_port); } @@ -2371,20 +2189,20 @@ static void change_port_settings(struct tty_struct *tty, /* if we are implementing INBOUND XON/XOFF */ if (I_IXOFF(tty)) { config->wFlags |= UMP_MASK_UART_FLAGS_IN_X; - dbg("%s - INBOUND XON/XOFF is enabled, XON = %2x, XOFF = %2x", - __func__, config->cXon, config->cXoff); + dev_dbg(dev, "%s - INBOUND XON/XOFF is enabled, XON = %2x, XOFF = %2x\n", + __func__, config->cXon, config->cXoff); } else - dbg("%s - INBOUND XON/XOFF is disabled", __func__); + dev_dbg(dev, "%s - INBOUND XON/XOFF is disabled\n", __func__); /* if we are implementing OUTBOUND XON/XOFF */ if (I_IXON(tty)) { config->wFlags |= UMP_MASK_UART_FLAGS_OUT_X; - dbg("%s - OUTBOUND XON/XOFF is enabled, XON = %2x, XOFF = %2x", - __func__, config->cXon, config->cXoff); + dev_dbg(dev, "%s - OUTBOUND XON/XOFF is enabled, XON = %2x, XOFF = %2x\n", + __func__, config->cXon, config->cXoff); } else - dbg("%s - OUTBOUND XON/XOFF is disabled", __func__); + dev_dbg(dev, "%s - OUTBOUND XON/XOFF is disabled\n", __func__); - tty->termios->c_cflag &= ~CMSPAR; + tty->termios.c_cflag &= ~CMSPAR; /* Round the baud rate */ baud = tty_get_baud_rate(tty); @@ -2399,17 +2217,16 @@ static void change_port_settings(struct tty_struct *tty, /* FIXME: Recompute actual baud from divisor here */ - dbg("%s - baud rate = %d, wBaudRate = %d", __func__, baud, - config->wBaudRate); + dev_dbg(dev, "%s - baud rate = %d, wBaudRate = %d\n", __func__, baud, config->wBaudRate); - dbg("wBaudRate: %d", (int)(461550L / config->wBaudRate)); - dbg("wFlags: 0x%x", config->wFlags); - dbg("bDataBits: %d", config->bDataBits); - dbg("bParity: %d", config->bParity); - dbg("bStopBits: %d", config->bStopBits); - dbg("cXon: %d", config->cXon); - dbg("cXoff: %d", config->cXoff); - dbg("bUartMode: %d", config->bUartMode); + dev_dbg(dev, "wBaudRate: %d\n", (int)(461550L / config->wBaudRate)); + dev_dbg(dev, "wFlags: 0x%x\n", config->wFlags); + dev_dbg(dev, "bDataBits: %d\n", config->bDataBits); + dev_dbg(dev, "bParity: %d\n", config->bParity); + dev_dbg(dev, "bStopBits: %d\n", config->bStopBits); + dev_dbg(dev, "cXon: %d\n", config->cXon); + dev_dbg(dev, "cXoff: %d\n", config->cXoff); + dev_dbg(dev, "bUartMode: %d\n", config->bUartMode); /* move the word values into big endian mode */ cpu_to_be16s(&config->wFlags); @@ -2419,8 +2236,8 @@ static void change_port_settings(struct tty_struct *tty, (__u8)(UMPM_UART1_PORT + port_number), 0, (__u8 *)config, sizeof(*config)); if (status) - dbg("%s - error %d when trying to write config to device", - __func__, status); + dev_dbg(dev, "%s - error %d when trying to write config to device\n", + __func__, status); kfree(config); } @@ -2430,13 +2247,12 @@ static void edge_set_termios(struct tty_struct *tty, struct edgeport_port *edge_port = usb_get_serial_port_data(port); unsigned int cflag; - cflag = tty->termios->c_cflag; + cflag = tty->termios.c_cflag; - dbg("%s - clfag %08x iflag %08x", __func__, - tty->termios->c_cflag, tty->termios->c_iflag); - dbg("%s - old clfag %08x old iflag %08x", __func__, - old_termios->c_cflag, old_termios->c_iflag); - dbg("%s - port %d", __func__, port->number); + dev_dbg(&port->dev, "%s - clfag %08x iflag %08x\n", __func__, + tty->termios.c_cflag, tty->termios.c_iflag); + dev_dbg(&port->dev, "%s - old clfag %08x old iflag %08x\n", __func__, + old_termios->c_cflag, old_termios->c_iflag); if (edge_port == NULL) return; @@ -2444,7 +2260,7 @@ static void edge_set_termios(struct tty_struct *tty, change_port_settings(tty, edge_port, old_termios); } -static int edge_tiocmset(struct tty_struct *tty, struct file *file, +static int edge_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) { struct usb_serial_port *port = tty->driver_data; @@ -2452,8 +2268,6 @@ static int edge_tiocmset(struct tty_struct *tty, struct file *file, unsigned int mcr; unsigned long flags; - dbg("%s - port %d", __func__, port->number); - spin_lock_irqsave(&edge_port->ep_lock, flags); mcr = edge_port->shadow_mcr; if (set & TIOCM_RTS) @@ -2477,7 +2291,7 @@ static int edge_tiocmset(struct tty_struct *tty, struct file *file, return 0; } -static int edge_tiocmget(struct tty_struct *tty, struct file *file) +static int edge_tiocmget(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; struct edgeport_port *edge_port = usb_get_serial_port_data(port); @@ -2486,8 +2300,6 @@ static int edge_tiocmget(struct tty_struct *tty, struct file *file) unsigned int mcr; unsigned long flags; - dbg("%s - port %d", __func__, port->number); - spin_lock_irqsave(&edge_port->ep_lock, flags); msr = edge_port->shadow_msr; @@ -2500,95 +2312,53 @@ static int edge_tiocmget(struct tty_struct *tty, struct file *file) | ((msr & EDGEPORT_MSR_DSR) ? TIOCM_DSR: 0); /* 0x100 */ - dbg("%s -- %x", __func__, result); + dev_dbg(&port->dev, "%s -- %x\n", __func__, result); spin_unlock_irqrestore(&edge_port->ep_lock, flags); return result; } -static int edge_get_icount(struct tty_struct *tty, - struct serial_icounter_struct *icount) -{ - struct usb_serial_port *port = tty->driver_data; - struct edgeport_port *edge_port = usb_get_serial_port_data(port); - struct async_icount *ic = &edge_port->icount; - - icount->cts = ic->cts; - icount->dsr = ic->dsr; - icount->rng = ic->rng; - icount->dcd = ic->dcd; - icount->tx = ic->tx; - icount->rx = ic->rx; - icount->frame = ic->frame; - icount->parity = ic->parity; - icount->overrun = ic->overrun; - icount->brk = ic->brk; - icount->buf_overrun = ic->buf_overrun; - return 0; -} - static int get_serial_info(struct edgeport_port *edge_port, struct serial_struct __user *retinfo) { struct serial_struct tmp; + unsigned cwait; if (!retinfo) return -EFAULT; + cwait = edge_port->port->port.closing_wait; + if (cwait != ASYNC_CLOSING_WAIT_NONE) + cwait = jiffies_to_msecs(cwait) / 10; + memset(&tmp, 0, sizeof(tmp)); tmp.type = PORT_16550A; - tmp.line = edge_port->port->serial->minor; - tmp.port = edge_port->port->number; + tmp.line = edge_port->port->minor; + tmp.port = edge_port->port->port_number; tmp.irq = 0; tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ; tmp.xmit_fifo_size = edge_port->port->bulk_out_size; tmp.baud_base = 9600; tmp.close_delay = 5*HZ; - tmp.closing_wait = closing_wait; + tmp.closing_wait = cwait; if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) return -EFAULT; return 0; } -static int edge_ioctl(struct tty_struct *tty, struct file *file, +static int edge_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { struct usb_serial_port *port = tty->driver_data; struct edgeport_port *edge_port = usb_get_serial_port_data(port); - struct async_icount cnow; - struct async_icount cprev; - - dbg("%s - port %d, cmd = 0x%x", __func__, port->number, cmd); switch (cmd) { case TIOCGSERIAL: - dbg("%s - (%d) TIOCGSERIAL", __func__, port->number); + dev_dbg(&port->dev, "%s - TIOCGSERIAL\n", __func__); return get_serial_info(edge_port, (struct serial_struct __user *) arg); - case TIOCMIWAIT: - dbg("%s - (%d) TIOCMIWAIT", __func__, port->number); - cprev = edge_port->icount; - while (1) { - interruptible_sleep_on(&edge_port->delta_msr_wait); - /* see if a signal did it */ - if (signal_pending(current)) - return -ERESTARTSYS; - cnow = edge_port->icount; - if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && - cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) - return -EIO; /* no change => error */ - if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || - ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || - ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || - ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) { - return 0; - } - cprev = cnow; - } - /* not reached */ - break; } return -ENOIOCTLCMD; } @@ -2600,35 +2370,24 @@ static void edge_break(struct tty_struct *tty, int break_state) int status; int bv = 0; /* Off */ - dbg("%s - state = %d", __func__, break_state); - - /* chase the port close */ - chase_port(edge_port, 0, 0); - if (break_state == -1) bv = 1; /* On */ status = ti_do_config(edge_port, UMPC_SET_CLR_BREAK, bv); if (status) - dbg("%s - error %d sending break set/clear command.", - __func__, status); + dev_dbg(&port->dev, "%s - error %d sending break set/clear command.\n", + __func__, status); } static int edge_startup(struct usb_serial *serial) { struct edgeport_serial *edge_serial; - struct edgeport_port *edge_port; - struct usb_device *dev; int status; - int i; - - dev = serial->dev; /* create our private serial structure */ edge_serial = kzalloc(sizeof(struct edgeport_serial), GFP_KERNEL); - if (edge_serial == NULL) { - dev_err(&serial->dev->dev, "%s - Out of memory\n", __func__); + if (!edge_serial) return -ENOMEM; - } + mutex_init(&edge_serial->es_lock); edge_serial->serial = serial; usb_set_serial_data(serial, edge_serial); @@ -2639,74 +2398,82 @@ static int edge_startup(struct usb_serial *serial) return status; } - /* set up our port private structures */ - for (i = 0; i < serial->num_ports; ++i) { - edge_port = kzalloc(sizeof(struct edgeport_port), GFP_KERNEL); - if (edge_port == NULL) { - dev_err(&serial->dev->dev, "%s - Out of memory\n", - __func__); - goto cleanup; - } - spin_lock_init(&edge_port->ep_lock); - if (kfifo_alloc(&edge_port->write_fifo, EDGE_OUT_BUF_SIZE, - GFP_KERNEL)) { - dev_err(&serial->dev->dev, "%s - Out of memory\n", - __func__); - kfree(edge_port); - goto cleanup; - } - edge_port->port = serial->port[i]; - edge_port->edge_serial = edge_serial; - usb_set_serial_port_data(serial->port[i], edge_port); - edge_port->bUartMode = default_uart_mode; - } - return 0; - -cleanup: - for (--i; i >= 0; --i) { - edge_port = usb_get_serial_port_data(serial->port[i]); - kfifo_free(&edge_port->write_fifo); - kfree(edge_port); - usb_set_serial_port_data(serial->port[i], NULL); - } - kfree(edge_serial); - usb_set_serial_data(serial, NULL); - return -ENOMEM; } static void edge_disconnect(struct usb_serial *serial) { - int i; +} + +static void edge_release(struct usb_serial *serial) +{ + kfree(usb_get_serial_data(serial)); +} + +static int edge_port_probe(struct usb_serial_port *port) +{ struct edgeport_port *edge_port; + int ret; + + edge_port = kzalloc(sizeof(*edge_port), GFP_KERNEL); + if (!edge_port) + return -ENOMEM; - dbg("%s", __func__); + spin_lock_init(&edge_port->ep_lock); + edge_port->port = port; + edge_port->edge_serial = usb_get_serial_data(port->serial); + edge_port->bUartMode = default_uart_mode; - for (i = 0; i < serial->num_ports; ++i) { - edge_port = usb_get_serial_port_data(serial->port[i]); - edge_remove_sysfs_attrs(edge_port->port); + switch (port->port_number) { + case 0: + edge_port->uart_base = UMPMEM_BASE_UART1; + edge_port->dma_address = UMPD_OEDB1_ADDRESS; + break; + case 1: + edge_port->uart_base = UMPMEM_BASE_UART2; + edge_port->dma_address = UMPD_OEDB2_ADDRESS; + break; + default: + dev_err(&port->dev, "unknown port number\n"); + ret = -ENODEV; + goto err; } + + dev_dbg(&port->dev, + "%s - port_number = %d, uart_base = %04x, dma_address = %04x\n", + __func__, port->port_number, edge_port->uart_base, + edge_port->dma_address); + + usb_set_serial_port_data(port, edge_port); + + ret = edge_create_sysfs_attrs(port); + if (ret) + goto err; + + port->port.closing_wait = msecs_to_jiffies(closing_wait * 10); + port->port.drain_delay = 1; + + return 0; +err: + kfree(edge_port); + + return ret; } -static void edge_release(struct usb_serial *serial) +static int edge_port_remove(struct usb_serial_port *port) { - int i; struct edgeport_port *edge_port; - dbg("%s", __func__); + edge_port = usb_get_serial_port_data(port); + edge_remove_sysfs_attrs(port); + kfree(edge_port); - for (i = 0; i < serial->num_ports; ++i) { - edge_port = usb_get_serial_port_data(serial->port[i]); - kfifo_free(&edge_port->write_fifo); - kfree(edge_port); - } - kfree(usb_get_serial_data(serial)); + return 0; } - /* Sysfs Attributes */ -static ssize_t show_uart_mode(struct device *dev, +static ssize_t uart_mode_show(struct device *dev, struct device_attribute *attr, char *buf) { struct usb_serial_port *port = to_usb_serial_port(dev); @@ -2715,14 +2482,14 @@ static ssize_t show_uart_mode(struct device *dev, return sprintf(buf, "%d\n", edge_port->bUartMode); } -static ssize_t store_uart_mode(struct device *dev, +static ssize_t uart_mode_store(struct device *dev, struct device_attribute *attr, const char *valbuf, size_t count) { struct usb_serial_port *port = to_usb_serial_port(dev); struct edgeport_port *edge_port = usb_get_serial_port_data(port); unsigned int v = simple_strtoul(valbuf, NULL, 0); - dbg("%s: setting uart_mode = %d", __func__, v); + dev_dbg(dev, "%s: setting uart_mode = %d\n", __func__, v); if (v < 256) edge_port->bUartMode = v; @@ -2731,9 +2498,7 @@ static ssize_t store_uart_mode(struct device *dev, return count; } - -static DEVICE_ATTR(uart_mode, S_IWUSR | S_IRUGO, show_uart_mode, - store_uart_mode); +static DEVICE_ATTR_RW(uart_mode); static int edge_create_sysfs_attrs(struct usb_serial_port *port) { @@ -2753,7 +2518,6 @@ static struct usb_serial_driver edgeport_1port_device = { .name = "edgeport_ti_1", }, .description = "Edgeport TI 1 port adapter", - .usb_driver = &io_driver, .id_table = edgeport_1port_id_table, .num_ports = 1, .open = edge_open, @@ -2763,15 +2527,18 @@ static struct usb_serial_driver edgeport_1port_device = { .attach = edge_startup, .disconnect = edge_disconnect, .release = edge_release, - .port_probe = edge_create_sysfs_attrs, + .port_probe = edge_port_probe, + .port_remove = edge_port_remove, .ioctl = edge_ioctl, .set_termios = edge_set_termios, .tiocmget = edge_tiocmget, .tiocmset = edge_tiocmset, - .get_icount = edge_get_icount, + .tiocmiwait = usb_serial_generic_tiocmiwait, + .get_icount = usb_serial_generic_get_icount, .write = edge_write, .write_room = edge_write_room, .chars_in_buffer = edge_chars_in_buffer, + .tx_empty = edge_tx_empty, .break_ctl = edge_break, .read_int_callback = edge_interrupt_callback, .read_bulk_callback = edge_bulk_in_callback, @@ -2784,7 +2551,6 @@ static struct usb_serial_driver edgeport_2port_device = { .name = "edgeport_ti_2", }, .description = "Edgeport TI 2 port adapter", - .usb_driver = &io_driver, .id_table = edgeport_2port_id_table, .num_ports = 2, .open = edge_open, @@ -2794,63 +2560,35 @@ static struct usb_serial_driver edgeport_2port_device = { .attach = edge_startup, .disconnect = edge_disconnect, .release = edge_release, - .port_probe = edge_create_sysfs_attrs, + .port_probe = edge_port_probe, + .port_remove = edge_port_remove, .ioctl = edge_ioctl, .set_termios = edge_set_termios, .tiocmget = edge_tiocmget, .tiocmset = edge_tiocmset, + .tiocmiwait = usb_serial_generic_tiocmiwait, + .get_icount = usb_serial_generic_get_icount, .write = edge_write, .write_room = edge_write_room, .chars_in_buffer = edge_chars_in_buffer, + .tx_empty = edge_tx_empty, .break_ctl = edge_break, .read_int_callback = edge_interrupt_callback, .read_bulk_callback = edge_bulk_in_callback, .write_bulk_callback = edge_bulk_out_callback, }; +static struct usb_serial_driver * const serial_drivers[] = { + &edgeport_1port_device, &edgeport_2port_device, NULL +}; -static int __init edgeport_init(void) -{ - int retval; - retval = usb_serial_register(&edgeport_1port_device); - if (retval) - goto failed_1port_device_register; - retval = usb_serial_register(&edgeport_2port_device); - if (retval) - goto failed_2port_device_register; - retval = usb_register(&io_driver); - if (retval) - goto failed_usb_register; - printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" - DRIVER_DESC "\n"); - return 0; -failed_usb_register: - usb_serial_deregister(&edgeport_2port_device); -failed_2port_device_register: - usb_serial_deregister(&edgeport_1port_device); -failed_1port_device_register: - return retval; -} - -static void __exit edgeport_exit(void) -{ - usb_deregister(&io_driver); - usb_serial_deregister(&edgeport_1port_device); - usb_serial_deregister(&edgeport_2port_device); -} - -module_init(edgeport_init); -module_exit(edgeport_exit); +module_usb_serial_driver(serial_drivers, id_table_combined); -/* Module information */ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); MODULE_FIRMWARE("edgeport/down3.bin"); -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); - module_param(closing_wait, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(closing_wait, "Maximum wait for data to drain, in .01 secs"); diff --git a/drivers/usb/serial/io_usbvend.h b/drivers/usb/serial/io_usbvend.h index 51f83fbb73b..6f6a856bc37 100644 --- a/drivers/usb/serial/io_usbvend.h +++ b/drivers/usb/serial/io_usbvend.h @@ -594,7 +594,7 @@ struct edge_boot_descriptor { struct ti_i2c_desc { __u8 Type; // Type of descriptor - __u16 Size; // Size of data only not including header + __le16 Size; // Size of data only not including header __u8 CheckSum; // Checksum (8 bit sum of data only) __u8 Data[0]; // Data starts here } __attribute__((packed)); diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c index 4735931b4c7..f51a5d52c0e 100644 --- a/drivers/usb/serial/ipaq.c +++ b/drivers/usb/serial/ipaq.c @@ -8,45 +8,10 @@ * 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. - * - * (12/12/2002) ganesh - * Added support for practically all devices supported by ActiveSync - * on Windows. Thanks to Wes Cilldhaire <billybobjoehenrybob@hotmail.com>. - * - * (26/11/2002) ganesh - * Added insmod options to specify product and vendor id. - * Use modprobe ipaq vendor=0xfoo product=0xbar - * - * (26/7/2002) ganesh - * Fixed up broken error handling in ipaq_open. Retry the "kickstart" - * packet much harder - this drastically reduces connection failures. - * - * (30/4/2002) ganesh - * Added support for the Casio EM500. Completely untested. Thanks - * to info from Nathan <wfilardo@fuse.net> - * - * (19/3/2002) ganesh - * Don't submit urbs while holding spinlocks. Not strictly necessary - * in 2.5.x. - * - * (8/3/2002) ganesh - * The ipaq sometimes emits a '\0' before the CLIENT string. At this - * point of time, the ppp ldisc is not yet attached to the tty, so - * n_tty echoes "^ " to the ipaq, which messes up the chat. In 2.5.6-pre2 - * this causes a panic because echo_char() tries to sleep in interrupt - * context. - * The fix is to tell the upper layers that this is a raw device so that - * echoing is suppressed. Thanks to Lyle Lindholm for a detailed bug - * report. - * - * (25/2/2002) ganesh - * Added support for the HP Jornada 548 and 568. Completely untested. - * Thanks to info from Heath Robinson and Arieh Davidoff. */ #include <linux/kernel.h> #include <linux/errno.h> -#include <linux/init.h> #include <linux/slab.h> #include <linux/tty.h> #include <linux/tty_driver.h> @@ -59,16 +24,9 @@ #define KP_RETRIES 100 -/* - * Version Information - */ - -#define DRIVER_VERSION "v1.0" #define DRIVER_AUTHOR "Ganesh Varadarajan <ganesh@veritas.com>" #define DRIVER_DESC "USB PocketPC PDA driver" -static __u16 product, vendor; -static int debug; static int connect_retries = KP_RETRIES; static int initial_wait; @@ -78,9 +36,7 @@ static int ipaq_open(struct tty_struct *tty, static int ipaq_calc_num_ports(struct usb_serial *serial); static int ipaq_startup(struct usb_serial *serial); -static struct usb_device_id ipaq_id_table [] = { - /* The first entry is a placeholder for the insmod-specified device */ - { USB_DEVICE(0x049F, 0x0003) }, +static const struct usb_device_id ipaq_id_table[] = { { USB_DEVICE(0x0104, 0x00BE) }, /* Socket USB Sync */ { USB_DEVICE(0x03F0, 0x1016) }, /* HP USB Sync */ { USB_DEVICE(0x03F0, 0x1116) }, /* HP USB Sync 1611 */ @@ -539,14 +495,6 @@ static struct usb_device_id ipaq_id_table [] = { MODULE_DEVICE_TABLE(usb, ipaq_id_table); -static struct usb_driver ipaq_driver = { - .name = "ipaq", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = ipaq_id_table, - .no_dynamic_id = 1, -}; - /* All of the device info needed for the Compaq iPAQ */ static struct usb_serial_driver ipaq_device = { @@ -555,7 +503,6 @@ static struct usb_serial_driver ipaq_device = { .name = "ipaq", }, .description = "PocketPC PDA", - .usb_driver = &ipaq_driver, .id_table = ipaq_id_table, .bulk_in_size = 256, .bulk_out_size = 256, @@ -564,6 +511,10 @@ static struct usb_serial_driver ipaq_device = { .calc_num_ports = ipaq_calc_num_ports, }; +static struct usb_serial_driver * const serial_drivers[] = { + &ipaq_device, NULL +}; + static int ipaq_open(struct tty_struct *tty, struct usb_serial_port *port) { @@ -571,8 +522,6 @@ static int ipaq_open(struct tty_struct *tty, int result = 0; int retries = connect_retries; - dbg("%s - port %d", __func__, port->number); - msleep(1000*initial_wait); /* @@ -609,7 +558,7 @@ static int ipaq_calc_num_ports(struct usb_serial *serial) */ int ipaq_num_ports = 1; - dbg("%s - numberofendpoints: %d", __FUNCTION__, + dev_dbg(&serial->dev->dev, "%s - numberofendpoints: %d\n", __func__, (int)serial->interface->cur_altsetting->desc.bNumEndpoints); /* @@ -628,8 +577,6 @@ static int ipaq_calc_num_ports(struct usb_serial *serial) static int ipaq_startup(struct usb_serial *serial) { - dbg("%s", __func__); - /* Some of the devices in ipaq_id_table[] are composite, and we * shouldn't bind to all the interfaces. This test will rule out * some obviously invalid possibilities. @@ -649,58 +596,19 @@ static int ipaq_startup(struct usb_serial *serial) return -ENODEV; } - dbg("%s - iPAQ module configured for %d ports", - __FUNCTION__, serial->num_ports); + dev_dbg(&serial->dev->dev, + "%s - iPAQ module configured for %d ports\n", __func__, + serial->num_ports); return usb_reset_configuration(serial->dev); } -static int __init ipaq_init(void) -{ - int retval; - retval = usb_serial_register(&ipaq_device); - if (retval) - goto failed_usb_serial_register; - if (vendor) { - ipaq_id_table[0].idVendor = vendor; - ipaq_id_table[0].idProduct = product; - } - retval = usb_register(&ipaq_driver); - if (retval) - goto failed_usb_register; - - printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" - DRIVER_DESC "\n"); - return 0; -failed_usb_register: - usb_serial_deregister(&ipaq_device); -failed_usb_serial_register: - return retval; -} - -static void __exit ipaq_exit(void) -{ - usb_deregister(&ipaq_driver); - usb_serial_deregister(&ipaq_device); -} - - -module_init(ipaq_init); -module_exit(ipaq_exit); +module_usb_serial_driver(serial_drivers, ipaq_id_table); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); - -module_param(vendor, ushort, 0); -MODULE_PARM_DESC(vendor, "User specified USB idVendor"); - -module_param(product, ushort, 0); -MODULE_PARM_DESC(product, "User specified USB idProduct"); - module_param(connect_retries, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(connect_retries, "Maximum number of connect retries (one second each)"); diff --git a/drivers/usb/serial/ipw.c b/drivers/usb/serial/ipw.c index ca77e88836b..8b1cf18a668 100644 --- a/drivers/usb/serial/ipw.c +++ b/drivers/usb/serial/ipw.c @@ -38,7 +38,6 @@ #include <linux/kernel.h> #include <linux/errno.h> -#include <linux/init.h> #include <linux/slab.h> #include <linux/tty.h> #include <linux/tty_flip.h> @@ -47,11 +46,8 @@ #include <linux/usb.h> #include <linux/usb/serial.h> #include <linux/uaccess.h> +#include "usb-wwan.h" -/* - * Version Information - */ -#define DRIVER_VERSION "v0.4" #define DRIVER_AUTHOR "Roelf Diedericks" #define DRIVER_DESC "IPWireless tty driver" @@ -131,32 +127,20 @@ enum { #define IPW_WANTS_TO_SEND 0x30 -static const struct usb_device_id usb_ipw_ids[] = { +static const struct usb_device_id id_table[] = { { USB_DEVICE(IPW_VID, IPW_PID) }, { }, }; - -MODULE_DEVICE_TABLE(usb, usb_ipw_ids); - -static struct usb_driver usb_ipw_driver = { - .name = "ipwtty", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = usb_ipw_ids, - .no_dynamic_id = 1, -}; - -static int debug; +MODULE_DEVICE_TABLE(usb, id_table); static int ipw_open(struct tty_struct *tty, struct usb_serial_port *port) { - struct usb_device *dev = port->serial->dev; + struct usb_device *udev = port->serial->dev; + struct device *dev = &port->dev; u8 buf_flow_static[16] = IPW_BYTES_FLOWINIT; u8 *buf_flow_init; int result; - dbg("%s", __func__); - buf_flow_init = kmemdup(buf_flow_static, 16, GFP_KERNEL); if (!buf_flow_init) return -ENOMEM; @@ -164,8 +148,8 @@ static int ipw_open(struct tty_struct *tty, struct usb_serial_port *port) /* --1: Tell the modem to initialize (we think) From sniffs this is * always the first thing that gets sent to the modem during * opening of the device */ - dbg("%s: Sending SIO_INIT (we guess)", __func__); - result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + dev_dbg(dev, "%s: Sending SIO_INIT (we guess)\n", __func__); + result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), IPW_SIO_INIT, USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT, 0, @@ -174,22 +158,19 @@ static int ipw_open(struct tty_struct *tty, struct usb_serial_port *port) 0, 100000); if (result < 0) - dev_err(&port->dev, - "Init of modem failed (error = %d)\n", result); + dev_err(dev, "Init of modem failed (error = %d)\n", result); /* reset the bulk pipes */ - usb_clear_halt(dev, - usb_rcvbulkpipe(dev, port->bulk_in_endpointAddress)); - usb_clear_halt(dev, - usb_sndbulkpipe(dev, port->bulk_out_endpointAddress)); + usb_clear_halt(udev, usb_rcvbulkpipe(udev, port->bulk_in_endpointAddress)); + usb_clear_halt(udev, usb_sndbulkpipe(udev, port->bulk_out_endpointAddress)); /*--2: Start reading from the device */ - dbg("%s: setting up bulk read callback", __func__); - usb_serial_generic_open(tty, port); + dev_dbg(dev, "%s: setting up bulk read callback\n", __func__); + usb_wwan_open(tty, port); /*--3: Tell the modem to open the floodgates on the rx bulk channel */ - dbg("%s:asking modem for RxRead (RXBULK_ON)", __func__); - result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + dev_dbg(dev, "%s:asking modem for RxRead (RXBULK_ON)\n", __func__); + result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), IPW_SIO_RXCTL, USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT, IPW_RXBULK_ON, @@ -198,12 +179,11 @@ static int ipw_open(struct tty_struct *tty, struct usb_serial_port *port) 0, 100000); if (result < 0) - dev_err(&port->dev, - "Enabling bulk RxRead failed (error = %d)\n", result); + dev_err(dev, "Enabling bulk RxRead failed (error = %d)\n", result); /*--4: setup the initial flowcontrol */ - dbg("%s:setting init flowcontrol (%s)", __func__, buf_flow_init); - result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + dev_dbg(dev, "%s:setting init flowcontrol (%s)\n", __func__, buf_flow_init); + result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), IPW_SIO_HANDFLOW, USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT, 0, @@ -212,21 +192,42 @@ static int ipw_open(struct tty_struct *tty, struct usb_serial_port *port) 0x10, 200000); if (result < 0) - dev_err(&port->dev, - "initial flowcontrol failed (error = %d)\n", result); + dev_err(dev, "initial flowcontrol failed (error = %d)\n", result); kfree(buf_flow_init); return 0; } +static int ipw_attach(struct usb_serial *serial) +{ + struct usb_wwan_intf_private *data; + + data = kzalloc(sizeof(struct usb_wwan_intf_private), GFP_KERNEL); + if (!data) + return -ENOMEM; + + spin_lock_init(&data->susp_lock); + usb_set_serial_data(serial, data); + return 0; +} + +static void ipw_release(struct usb_serial *serial) +{ + struct usb_wwan_intf_private *data = usb_get_serial_data(serial); + + usb_set_serial_data(serial, NULL); + kfree(data); +} + static void ipw_dtr_rts(struct usb_serial_port *port, int on) { - struct usb_device *dev = port->serial->dev; + struct usb_device *udev = port->serial->dev; + struct device *dev = &port->dev; int result; - dbg("%s: on = %d", __func__, on); + dev_dbg(dev, "%s: on = %d\n", __func__, on); - result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), IPW_SIO_SET_PIN, USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT, on ? IPW_PIN_SETDTR : IPW_PIN_CLRDTR, @@ -235,10 +236,9 @@ static void ipw_dtr_rts(struct usb_serial_port *port, int on) 0, 200000); if (result < 0) - dev_err(&port->dev, "setting dtr failed (error = %d)\n", - result); + dev_err(dev, "setting dtr failed (error = %d)\n", result); - result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), IPW_SIO_SET_PIN, USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT, on ? IPW_PIN_SETRTS : IPW_PIN_CLRRTS, @@ -247,18 +247,18 @@ static void ipw_dtr_rts(struct usb_serial_port *port, int on) 0, 200000); if (result < 0) - dev_err(&port->dev, "setting rts failed (error = %d)\n", - result); + dev_err(dev, "setting rts failed (error = %d)\n", result); } static void ipw_close(struct usb_serial_port *port) { - struct usb_device *dev = port->serial->dev; + struct usb_device *udev = port->serial->dev; + struct device *dev = &port->dev; int result; /*--3: purge */ - dbg("%s:sending purge", __func__); - result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + dev_dbg(dev, "%s:sending purge\n", __func__); + result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), IPW_SIO_PURGE, USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT, 0x03, @@ -267,12 +267,12 @@ static void ipw_close(struct usb_serial_port *port) 0, 200000); if (result < 0) - dev_err(&port->dev, "purge failed (error = %d)\n", result); + dev_err(dev, "purge failed (error = %d)\n", result); /* send RXBULK_off (tell modem to stop transmitting bulk data on rx chan) */ - result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), IPW_SIO_RXCTL, USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT, IPW_RXBULK_OFF, @@ -282,10 +282,9 @@ static void ipw_close(struct usb_serial_port *port) 100000); if (result < 0) - dev_err(&port->dev, - "Disabling bulk RxRead failed (error = %d)\n", result); + dev_err(dev, "Disabling bulk RxRead failed (error = %d)\n", result); - usb_serial_generic_close(port); + usb_wwan_close(port); } static struct usb_serial_driver ipw_device = { @@ -294,46 +293,25 @@ static struct usb_serial_driver ipw_device = { .name = "ipw", }, .description = "IPWireless converter", - .usb_driver = &usb_ipw_driver, - .id_table = usb_ipw_ids, + .id_table = id_table, .num_ports = 1, .open = ipw_open, .close = ipw_close, + .attach = ipw_attach, + .release = ipw_release, + .port_probe = usb_wwan_port_probe, + .port_remove = usb_wwan_port_remove, .dtr_rts = ipw_dtr_rts, + .write = usb_wwan_write, }; +static struct usb_serial_driver * const serial_drivers[] = { + &ipw_device, NULL +}; - -static int __init usb_ipw_init(void) -{ - int retval; - - retval = usb_serial_register(&ipw_device); - if (retval) - return retval; - retval = usb_register(&usb_ipw_driver); - if (retval) { - usb_serial_deregister(&ipw_device); - return retval; - } - printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" - DRIVER_DESC "\n"); - return 0; -} - -static void __exit usb_ipw_exit(void) -{ - usb_deregister(&usb_ipw_driver); - usb_serial_deregister(&ipw_device); -} - -module_init(usb_ipw_init); -module_exit(usb_ipw_exit); +module_usb_serial_driver(serial_drivers, id_table); /* Module information */ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c index ccbce4066d0..73956d48a0c 100644 --- a/drivers/usb/serial/ir-usb.c +++ b/drivers/usb/serial/ir-usb.c @@ -22,38 +22,6 @@ * * See Documentation/usb/usb-serial.txt for more information on using this * driver - * - * 2008_Jun_02 Felipe Balbi <me@felipebalbi.com> - * Introduced common header to be used also in USB Gadget Framework. - * Still needs some other style fixes. - * - * 2007_Jun_21 Alan Cox <alan@lxorguk.ukuu.org.uk> - * Minimal cleanups for some of the driver problens and tty layer abuse. - * Still needs fixing to allow multiple dongles. - * - * 2002_Mar_07 greg kh - * moved some needed structures and #define values from the - * net/irda/irda-usb.h file into our file, as we don't want to depend on - * that codebase compiling correctly :) - * - * 2002_Jan_14 gb - * Added module parameter to force specific number of XBOFs. - * Added ir_xbof_change(). - * Reorganized read_bulk_callback error handling. - * Switched from FILL_BULK_URB() to usb_fill_bulk_urb(). - * - * 2001_Nov_08 greg kh - * Changed the irda_usb_find_class_desc() function based on comments and - * code from Martin Diehl. - * - * 2001_Nov_01 greg kh - * Added support for more IrDA USB devices. - * Added support for zero packet. Added buffer override paramater, so - * users can transfer larger packets at once if they wish. Both patches - * came from Dag Brattli <dag@obexcode.com>. - * - * 2001_Oct_07 greg kh - * initial version released. */ #include <linux/kernel.h> @@ -70,15 +38,9 @@ #include <linux/usb/serial.h> #include <linux/usb/irda.h> -/* - * Version Information - */ -#define DRIVER_VERSION "v0.5" #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Johan Hovold <jhovold@gmail.com>" #define DRIVER_DESC "USB IR Dongle driver" -static int debug; - /* if overridden by the user, then use their value for the size of the read and * write urbs */ static int buffer_size; @@ -109,21 +71,12 @@ static const struct usb_device_id ir_id_table[] = { MODULE_DEVICE_TABLE(usb, ir_id_table); -static struct usb_driver ir_driver = { - .name = "ir-usb", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = ir_id_table, - .no_dynamic_id = 1, -}; - static struct usb_serial_driver ir_device = { .driver = { .owner = THIS_MODULE, .name = "ir-usb", }, .description = "IR Dongle", - .usb_driver = &ir_driver, .id_table = ir_id_table, .num_ports = 1, .set_termios = ir_set_termios, @@ -133,18 +86,25 @@ static struct usb_serial_driver ir_device = { .process_read_urb = ir_process_read_urb, }; -static inline void irda_usb_dump_class_desc(struct usb_irda_cs_descriptor *desc) +static struct usb_serial_driver * const serial_drivers[] = { + &ir_device, NULL +}; + +static inline void irda_usb_dump_class_desc(struct usb_serial *serial, + struct usb_irda_cs_descriptor *desc) { - dbg("bLength=%x", desc->bLength); - dbg("bDescriptorType=%x", desc->bDescriptorType); - dbg("bcdSpecRevision=%x", __le16_to_cpu(desc->bcdSpecRevision)); - dbg("bmDataSize=%x", desc->bmDataSize); - dbg("bmWindowSize=%x", desc->bmWindowSize); - dbg("bmMinTurnaroundTime=%d", desc->bmMinTurnaroundTime); - dbg("wBaudRate=%x", __le16_to_cpu(desc->wBaudRate)); - dbg("bmAdditionalBOFs=%x", desc->bmAdditionalBOFs); - dbg("bIrdaRateSniff=%x", desc->bIrdaRateSniff); - dbg("bMaxUnicastList=%x", desc->bMaxUnicastList); + struct device *dev = &serial->dev->dev; + + dev_dbg(dev, "bLength=%x\n", desc->bLength); + dev_dbg(dev, "bDescriptorType=%x\n", desc->bDescriptorType); + dev_dbg(dev, "bcdSpecRevision=%x\n", __le16_to_cpu(desc->bcdSpecRevision)); + dev_dbg(dev, "bmDataSize=%x\n", desc->bmDataSize); + dev_dbg(dev, "bmWindowSize=%x\n", desc->bmWindowSize); + dev_dbg(dev, "bmMinTurnaroundTime=%d\n", desc->bmMinTurnaroundTime); + dev_dbg(dev, "wBaudRate=%x\n", __le16_to_cpu(desc->wBaudRate)); + dev_dbg(dev, "bmAdditionalBOFs=%x\n", desc->bmAdditionalBOFs); + dev_dbg(dev, "bIrdaRateSniff=%x\n", desc->bIrdaRateSniff); + dev_dbg(dev, "bMaxUnicastList=%x\n", desc->bMaxUnicastList); } /*------------------------------------------------------------------*/ @@ -160,8 +120,9 @@ static inline void irda_usb_dump_class_desc(struct usb_irda_cs_descriptor *desc) * Based on the same function in drivers/net/irda/irda-usb.c */ static struct usb_irda_cs_descriptor * -irda_usb_find_class_desc(struct usb_device *dev, unsigned int ifnum) +irda_usb_find_class_desc(struct usb_serial *serial, unsigned int ifnum) { + struct usb_device *dev = serial->dev; struct usb_irda_cs_descriptor *desc; int ret; @@ -174,20 +135,20 @@ irda_usb_find_class_desc(struct usb_device *dev, unsigned int ifnum) USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, ifnum, desc, sizeof(*desc), 1000); - dbg("%s - ret=%d", __func__, ret); + dev_dbg(&serial->dev->dev, "%s - ret=%d\n", __func__, ret); if (ret < sizeof(*desc)) { - dbg("%s - class descriptor read %s (%d)", - __func__, - (ret < 0) ? "failed" : "too short", - ret); + dev_dbg(&serial->dev->dev, + "%s - class descriptor read %s (%d)\n", __func__, + (ret < 0) ? "failed" : "too short", ret); goto error; } if (desc->bDescriptorType != USB_DT_CS_IRDA) { - dbg("%s - bad class descriptor type", __func__); + dev_dbg(&serial->dev->dev, "%s - bad class descriptor type\n", + __func__); goto error; } - irda_usb_dump_class_desc(desc); + irda_usb_dump_class_desc(serial, desc); return desc; error: @@ -237,14 +198,15 @@ static int ir_startup(struct usb_serial *serial) { struct usb_irda_cs_descriptor *irda_desc; - irda_desc = irda_usb_find_class_desc(serial->dev, 0); + irda_desc = irda_usb_find_class_desc(serial, 0); if (!irda_desc) { dev_err(&serial->dev->dev, "IRDA class descriptor not found, device not bound\n"); return -ENODEV; } - dbg("%s - Baud rates supported:%s%s%s%s%s%s%s%s%s", + dev_dbg(&serial->dev->dev, + "%s - Baud rates supported:%s%s%s%s%s%s%s%s%s\n", __func__, (irda_desc->wBaudRate & USB_IRDA_BR_2400) ? " 2400" : "", (irda_desc->wBaudRate & USB_IRDA_BR_9600) ? " 9600" : "", @@ -294,8 +256,6 @@ static int ir_open(struct tty_struct *tty, struct usb_serial_port *port) { int i; - dbg("%s - port %d", __func__, port->number); - for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) port->write_urbs[i]->transfer_flags = URB_ZERO_PACKET; @@ -327,7 +287,6 @@ static void ir_process_read_urb(struct urb *urb) { struct usb_serial_port *port = urb->context; unsigned char *data = urb->transfer_buffer; - struct tty_struct *tty; if (!urb->actual_length) return; @@ -342,25 +301,17 @@ static void ir_process_read_urb(struct urb *urb) if (urb->actual_length == 1) return; - tty = tty_port_tty_get(&port->port); - if (!tty) - return; - tty_insert_flip_string(tty, data + 1, urb->actual_length - 1); - tty_flip_buffer_push(tty); - tty_kref_put(tty); + tty_insert_flip_string(&port->port, data + 1, urb->actual_length - 1); + tty_flip_buffer_push(&port->port); } static void ir_set_termios_callback(struct urb *urb) { - struct usb_serial_port *port = urb->context; - int status = urb->status; - - dbg("%s - port %d", __func__, port->number); - kfree(urb->transfer_buffer); - if (status) - dbg("%s - non-zero urb status: %d", __func__, status); + if (urb->status) + dev_dbg(&urb->dev->dev, "%s - non-zero urb status: %d\n", + __func__, urb->status); } static void ir_set_termios(struct tty_struct *tty, @@ -372,8 +323,6 @@ static void ir_set_termios(struct tty_struct *tty, speed_t baud; int ir_baud; - dbg("%s - port %d", __func__, port->number); - baud = tty_get_baud_rate(tty); /* @@ -421,22 +370,19 @@ static void ir_set_termios(struct tty_struct *tty, ir_xbof = ir_xbof_change(xbof) ; /* Only speed changes are supported */ - tty_termios_copy_hw(tty->termios, old_termios); + tty_termios_copy_hw(&tty->termios, old_termios); tty_encode_baud_rate(tty, baud, baud); /* * send the baud change out on an "empty" data packet */ urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) { - dev_err(&port->dev, "%s - no more urbs\n", __func__); + if (!urb) return; - } + transfer_buffer = kmalloc(1, GFP_KERNEL); - if (!transfer_buffer) { - dev_err(&port->dev, "%s - out of memory\n", __func__); + if (!transfer_buffer) goto err_buf; - } *transfer_buffer = ir_xbof | ir_baud; @@ -470,37 +416,17 @@ err_buf: static int __init ir_init(void) { - int retval; - if (buffer_size) { ir_device.bulk_in_size = buffer_size; ir_device.bulk_out_size = buffer_size; } - retval = usb_serial_register(&ir_device); - if (retval) - goto failed_usb_serial_register; - - retval = usb_register(&ir_driver); - if (retval) - goto failed_usb_register; - - printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" - DRIVER_DESC "\n"); - - return 0; - -failed_usb_register: - usb_serial_deregister(&ir_device); - -failed_usb_serial_register: - return retval; + return usb_serial_register_drivers(serial_drivers, KBUILD_MODNAME, ir_id_table); } static void __exit ir_exit(void) { - usb_deregister(&ir_driver); - usb_serial_deregister(&ir_device); + usb_serial_deregister_drivers(serial_drivers); } @@ -511,8 +437,6 @@ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); module_param(xbof, int, 0); MODULE_PARM_DESC(xbof, "Force specific number of XBOFs"); module_param(buffer_size, int, 0); diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c index 12ed594f5f8..5ad4a0fb4b2 100644 --- a/drivers/usb/serial/iuu_phoenix.c +++ b/drivers/usb/serial/iuu_phoenix.c @@ -17,7 +17,6 @@ */ #include <linux/kernel.h> #include <linux/errno.h> -#include <linux/init.h> #include <linux/slab.h> #include <linux/tty.h> #include <linux/tty_driver.h> @@ -32,17 +31,6 @@ #include "iuu_phoenix.h" #include <linux/random.h> - -#ifdef CONFIG_USB_SERIAL_DEBUG -static int debug = 1; -#else -static int debug; -#endif - -/* - * Version Information - */ -#define DRIVER_VERSION "v0.12" #define DRIVER_DESC "Infinity USB Unlimited Phoenix driver" static const struct usb_device_id id_table[] = { @@ -51,28 +39,21 @@ static const struct usb_device_id id_table[] = { }; MODULE_DEVICE_TABLE(usb, id_table); -static struct usb_driver iuu_driver = { - .name = "iuu_phoenix", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, - .no_dynamic_id = 1, -}; - /* turbo parameter */ static int boost = 100; static int clockmode = 1; static int cdmode = 1; static int iuu_cardin; static int iuu_cardout; -static int xmas; +static bool xmas; static int vcc_default = 5; +static int iuu_create_sysfs_attrs(struct usb_serial_port *port); +static int iuu_remove_sysfs_attrs(struct usb_serial_port *port); static void read_rxcmd_callback(struct urb *urb); struct iuu_private { spinlock_t lock; /* store irq state */ - wait_queue_head_t delta_msr_wait; u8 line_status; int tiostatus; /* store IUART SIGNAL for tiocmget call */ u8 reset; /* if 1 reset is needed */ @@ -80,7 +61,6 @@ struct iuu_private { u8 *writebuf; /* buffer for writing to device */ int writelen; /* num of byte to write to device */ u8 *buf; /* used for initialize speed */ - u8 *dbgbuf; /* debug buffer */ u8 len; int vcc; /* vcc (either 3 or 5 V) */ u32 baud; @@ -88,69 +68,57 @@ struct iuu_private { u32 clk; }; - -static void iuu_free_buf(struct iuu_private *priv) +static int iuu_port_probe(struct usb_serial_port *port) { - kfree(priv->buf); - kfree(priv->dbgbuf); - kfree(priv->writebuf); -} + struct iuu_private *priv; + int ret; + + priv = kzalloc(sizeof(struct iuu_private), GFP_KERNEL); + if (!priv) + return -ENOMEM; -static int iuu_alloc_buf(struct iuu_private *priv) -{ priv->buf = kzalloc(256, GFP_KERNEL); - priv->dbgbuf = kzalloc(256, GFP_KERNEL); - priv->writebuf = kzalloc(256, GFP_KERNEL); - if (!priv->buf || !priv->dbgbuf || !priv->writebuf) { - iuu_free_buf(priv); - dbg("%s problem allocation buffer", __func__); + if (!priv->buf) { + kfree(priv); return -ENOMEM; } - dbg("%s - Privates buffers allocation success", __func__); - return 0; -} -static int iuu_startup(struct usb_serial *serial) -{ - struct iuu_private *priv; - priv = kzalloc(sizeof(struct iuu_private), GFP_KERNEL); - dbg("%s- priv allocation success", __func__); - if (!priv) - return -ENOMEM; - if (iuu_alloc_buf(priv)) { + priv->writebuf = kzalloc(256, GFP_KERNEL); + if (!priv->writebuf) { + kfree(priv->buf); kfree(priv); return -ENOMEM; } + priv->vcc = vcc_default; spin_lock_init(&priv->lock); - init_waitqueue_head(&priv->delta_msr_wait); - usb_set_serial_port_data(serial->port[0], priv); + + usb_set_serial_port_data(port, priv); + + ret = iuu_create_sysfs_attrs(port); + if (ret) { + kfree(priv->writebuf); + kfree(priv->buf); + kfree(priv); + return ret; + } + return 0; } -/* Release function */ -static void iuu_release(struct usb_serial *serial) +static int iuu_port_remove(struct usb_serial_port *port) { - struct usb_serial_port *port = serial->port[0]; struct iuu_private *priv = usb_get_serial_port_data(port); - if (!port) - return; - - dbg("%s", __func__); - if (priv) { - iuu_free_buf(priv); - dbg("%s - I will free all", __func__); - usb_set_serial_port_data(port, NULL); - - dbg("%s - priv is not anymore in port structure", __func__); - kfree(priv); + iuu_remove_sysfs_attrs(port); + kfree(priv->writebuf); + kfree(priv->buf); + kfree(priv); - dbg("%s priv is now kfree", __func__); - } + return 0; } -static int iuu_tiocmset(struct tty_struct *tty, struct file *file, +static int iuu_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) { struct usb_serial_port *port = tty->driver_data; @@ -158,13 +126,13 @@ static int iuu_tiocmset(struct tty_struct *tty, struct file *file, unsigned long flags; /* FIXME: locking on tiomstatus */ - dbg("%s (%d) msg : SET = 0x%04x, CLEAR = 0x%04x ", __func__, - port->number, set, clear); + dev_dbg(&port->dev, "%s msg : SET = 0x%04x, CLEAR = 0x%04x\n", + __func__, set, clear); spin_lock_irqsave(&priv->lock, flags); if ((set & TIOCM_RTS) && !(priv->tiostatus == TIOCM_RTS)) { - dbg("%s TIOCMSET RESET called !!!", __func__); + dev_dbg(&port->dev, "%s TIOCMSET RESET called !!!\n", __func__); priv->reset = 1; } if (set & TIOCM_RTS) @@ -179,7 +147,7 @@ static int iuu_tiocmset(struct tty_struct *tty, struct file *file, * When no card , the reader respond with TIOCM_CD * This is known as CD autodetect mechanism */ -static int iuu_tiocmget(struct tty_struct *tty, struct file *file) +static int iuu_tiocmget(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; struct iuu_private *priv = usb_get_serial_port_data(port); @@ -199,10 +167,8 @@ static void iuu_rxcmd(struct urb *urb) int result; int status = urb->status; - dbg("%s - enter", __func__); - if (status) { - dbg("%s - status = %d", __func__, status); + dev_dbg(&port->dev, "%s - status = %d\n", __func__, status); /* error stop all */ return; } @@ -222,7 +188,6 @@ static int iuu_reset(struct usb_serial_port *port, u8 wt) struct iuu_private *priv = usb_get_serial_port_data(port); int result; char *buf_ptr = port->write_urb->transfer_buffer; - dbg("%s - enter", __func__); /* Prepare the reset sequence */ @@ -256,16 +221,14 @@ static void iuu_update_status_callback(struct urb *urb) u8 *st; int status = urb->status; - dbg("%s - enter", __func__); - if (status) { - dbg("%s - status = %d", __func__, status); + dev_dbg(&port->dev, "%s - status = %d\n", __func__, status); /* error stop all */ return; } st = urb->transfer_buffer; - dbg("%s - enter", __func__); + dev_dbg(&port->dev, "%s - enter\n", __func__); if (urb->actual_length == 1) { switch (st[0]) { case 0x1: @@ -287,7 +250,7 @@ static void iuu_status_callback(struct urb *urb) int result; int status = urb->status; - dbg("%s - status = %d", __func__, status); + dev_dbg(&port->dev, "%s - status = %d\n", __func__, status); usb_fill_bulk_urb(port->read_urb, port->serial->dev, usb_rcvbulkpipe(port->serial->dev, port->bulk_in_endpointAddress), @@ -300,8 +263,6 @@ static int iuu_status(struct usb_serial_port *port) { int result; - dbg("%s - enter", __func__); - memset(port->write_urb->transfer_buffer, IUU_GET_STATE_REGISTER, 1); usb_fill_bulk_urb(port->write_urb, port->serial->dev, usb_sndbulkpipe(port->serial->dev, @@ -319,20 +280,18 @@ static int bulk_immediate(struct usb_serial_port *port, u8 *buf, u8 count) struct usb_serial *serial = port->serial; int actual = 0; - dbg("%s - enter", __func__); - /* send the data out the bulk port */ status = usb_bulk_msg(serial->dev, usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress), buf, - count, &actual, HZ * 1); + count, &actual, 1000); if (status != IUU_OPERATION_OK) - dbg("%s - error = %2x", __func__, status); + dev_dbg(&port->dev, "%s - error = %2x\n", __func__, status); else - dbg("%s - write OK !", __func__); + dev_dbg(&port->dev, "%s - write OK !\n", __func__); return status; } @@ -342,20 +301,17 @@ static int read_immediate(struct usb_serial_port *port, u8 *buf, u8 count) struct usb_serial *serial = port->serial; int actual = 0; - dbg("%s - enter", __func__); - /* send the data out the bulk port */ - status = usb_bulk_msg(serial->dev, usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress), buf, - count, &actual, HZ * 1); + count, &actual, 1000); if (status != IUU_OPERATION_OK) - dbg("%s - error = %2x", __func__, status); + dev_dbg(&port->dev, "%s - error = %2x\n", __func__, status); else - dbg("%s - read OK !", __func__); + dev_dbg(&port->dev, "%s - read OK !\n", __func__); return status; } @@ -368,8 +324,6 @@ static int iuu_led(struct usb_serial_port *port, unsigned int R, if (!buf) return -ENOMEM; - dbg("%s - enter", __func__); - buf[0] = IUU_SET_LED; buf[1] = R & 0xFF; buf[2] = (R >> 8) & 0xFF; @@ -381,9 +335,9 @@ static int iuu_led(struct usb_serial_port *port, unsigned int R, status = bulk_immediate(port, buf, 8); kfree(buf); if (status != IUU_OPERATION_OK) - dbg("%s - led error status = %2x", __func__, status); + dev_dbg(&port->dev, "%s - led error status = %2x\n", __func__, status); else - dbg("%s - led OK !", __func__); + dev_dbg(&port->dev, "%s - led OK !\n", __func__); return IUU_OPERATION_OK; } @@ -461,8 +415,6 @@ static int iuu_clk(struct usb_serial_port *port, int dwFrq) unsigned int P2 = 0; int frq = (int)dwFrq; - dbg("%s - enter", __func__); - if (frq == 0) { priv->buf[Count++] = IUU_UART_WRITE_I2C; priv->buf[Count++] = FrqGenAdr << 1; @@ -471,7 +423,7 @@ static int iuu_clk(struct usb_serial_port *port, int dwFrq) status = bulk_immediate(port, (u8 *) priv->buf, Count); if (status != 0) { - dbg("%s - write error ", __func__); + dev_dbg(&port->dev, "%s - write error\n", __func__); return status; } } else if (frq == 3579000) { @@ -580,46 +532,44 @@ static int iuu_clk(struct usb_serial_port *port, int dwFrq) status = bulk_immediate(port, (u8 *) priv->buf, Count); if (status != IUU_OPERATION_OK) - dbg("%s - write error ", __func__); + dev_dbg(&port->dev, "%s - write error\n", __func__); return status; } static int iuu_uart_flush(struct usb_serial_port *port) { + struct device *dev = &port->dev; int i; int status; u8 rxcmd = IUU_UART_RX; struct iuu_private *priv = usb_get_serial_port_data(port); - dbg("%s - enter", __func__); - if (iuu_led(port, 0xF000, 0, 0, 0xFF) < 0) return -EIO; for (i = 0; i < 2; i++) { status = bulk_immediate(port, &rxcmd, 1); if (status != IUU_OPERATION_OK) { - dbg("%s - uart_flush_write error", __func__); + dev_dbg(dev, "%s - uart_flush_write error\n", __func__); return status; } status = read_immediate(port, &priv->len, 1); if (status != IUU_OPERATION_OK) { - dbg("%s - uart_flush_read error", __func__); + dev_dbg(dev, "%s - uart_flush_read error\n", __func__); return status; } if (priv->len > 0) { - dbg("%s - uart_flush datalen is : %i ", __func__, - priv->len); + dev_dbg(dev, "%s - uart_flush datalen is : %i\n", __func__, priv->len); status = read_immediate(port, priv->buf, priv->len); if (status != IUU_OPERATION_OK) { - dbg("%s - uart_flush_read error", __func__); + dev_dbg(dev, "%s - uart_flush_read error\n", __func__); return status; } } } - dbg("%s - uart_flush_read OK!", __func__); + dev_dbg(dev, "%s - uart_flush_read OK!\n", __func__); iuu_led(port, 0, 0xF000, 0, 0xFF); return status; } @@ -628,11 +578,8 @@ static void read_buf_callback(struct urb *urb) { struct usb_serial_port *port = urb->context; unsigned char *data = urb->transfer_buffer; - struct tty_struct *tty; int status = urb->status; - dbg("%s - status = %d", __func__, status); - if (status) { if (status == -EPROTO) { /* reschedule needed */ @@ -640,15 +587,13 @@ static void read_buf_callback(struct urb *urb) return; } - dbg("%s - %i chars to write", __func__, urb->actual_length); - tty = tty_port_tty_get(&port->port); + dev_dbg(&port->dev, "%s - %i chars to write\n", __func__, urb->actual_length); if (data == NULL) - dbg("%s - data is NULL !!!", __func__); - if (tty && urb->actual_length && data) { - tty_insert_flip_string(tty, data, urb->actual_length); - tty_flip_buffer_push(tty); + dev_dbg(&port->dev, "%s - data is NULL !!!\n", __func__); + if (urb->actual_length && data) { + tty_insert_flip_string(&port->port, data, urb->actual_length); + tty_flip_buffer_push(&port->port); } - tty_kref_put(tty); iuu_led_activity_on(urb); } @@ -657,10 +602,8 @@ static int iuu_bulk_write(struct usb_serial_port *port) struct iuu_private *priv = usb_get_serial_port_data(port); unsigned long flags; int result; - int i; int buf_len; char *buf_ptr = port->write_urb->transfer_buffer; - dbg("%s - enter", __func__); spin_lock_irqsave(&priv->lock, flags); *buf_ptr++ = IUU_UART_ESC; @@ -671,14 +614,8 @@ static int iuu_bulk_write(struct usb_serial_port *port) buf_len = priv->writelen; priv->writelen = 0; spin_unlock_irqrestore(&priv->lock, flags); - if (debug == 1) { - for (i = 0; i < buf_len; i++) - sprintf(priv->dbgbuf + i*2 , - "%02X", priv->writebuf[i]); - priv->dbgbuf[buf_len+i*2] = 0; - dbg("%s - writing %i chars : %s", __func__, - buf_len, priv->dbgbuf); - } + dev_dbg(&port->dev, "%s - writing %i chars : %*ph\n", __func__, + buf_len, buf_len, buf_ptr); usb_fill_bulk_urb(port->write_urb, port->serial->dev, usb_sndbulkpipe(port->serial->dev, port->bulk_out_endpointAddress), @@ -692,7 +629,6 @@ static int iuu_bulk_write(struct usb_serial_port *port) static int iuu_read_buf(struct usb_serial_port *port, int len) { int result; - dbg("%s - enter", __func__); usb_fill_bulk_urb(port->read_urb, port->serial->dev, usb_rcvbulkpipe(port->serial->dev, @@ -714,21 +650,19 @@ static void iuu_uart_read_callback(struct urb *urb) unsigned char *data = urb->transfer_buffer; priv->poll++; - dbg("%s - enter", __func__); - if (status) { - dbg("%s - status = %d", __func__, status); + dev_dbg(&port->dev, "%s - status = %d\n", __func__, status); /* error stop all */ return; } if (data == NULL) - dbg("%s - data is NULL !!!", __func__); + dev_dbg(&port->dev, "%s - data is NULL !!!\n", __func__); if (urb->actual_length == 1 && data != NULL) len = (int) data[0]; if (urb->actual_length > 1) { - dbg("%s - urb->actual_length = %i", __func__, + dev_dbg(&port->dev, "%s - urb->actual_length = %i\n", __func__, urb->actual_length); error = 1; return; @@ -736,7 +670,7 @@ static void iuu_uart_read_callback(struct urb *urb) /* if len > 0 call readbuf */ if (len > 0 && error == 0) { - dbg("%s - call read buf - len to read is %i ", + dev_dbg(&port->dev, "%s - call read buf - len to read is %i\n", __func__, len); status = iuu_read_buf(port, len); return; @@ -763,7 +697,7 @@ static void iuu_uart_read_callback(struct urb *urb) } spin_unlock_irqrestore(&priv->lock, flags); /* if nothing to write call again rxcmd */ - dbg("%s - rxcmd recall", __func__); + dev_dbg(&port->dev, "%s - rxcmd recall\n", __func__); iuu_led_activity_off(urb); } @@ -772,7 +706,6 @@ static int iuu_uart_write(struct tty_struct *tty, struct usb_serial_port *port, { struct iuu_private *priv = usb_get_serial_port_data(port); unsigned long flags; - dbg("%s - enter", __func__); if (count > 256) return -ENOMEM; @@ -793,8 +726,6 @@ static void read_rxcmd_callback(struct urb *urb) int result; int status = urb->status; - dbg("%s - status = %d", __func__, status); - if (status) { /* error stop all */ return; @@ -806,7 +737,7 @@ static void read_rxcmd_callback(struct urb *urb) port->read_urb->transfer_buffer, 256, iuu_uart_read_callback, port); result = usb_submit_urb(port->read_urb, GFP_ATOMIC); - dbg("%s - submit result = %d", __func__, result); + dev_dbg(&port->dev, "%s - submit result = %d\n", __func__, result); } static int iuu_uart_on(struct usb_serial_port *port) @@ -826,19 +757,19 @@ static int iuu_uart_on(struct usb_serial_port *port) status = bulk_immediate(port, buf, 4); if (status != IUU_OPERATION_OK) { - dbg("%s - uart_on error", __func__); + dev_dbg(&port->dev, "%s - uart_on error\n", __func__); goto uart_enable_failed; } /* iuu_reset() the card after iuu_uart_on() */ status = iuu_uart_flush(port); if (status != IUU_OPERATION_OK) - dbg("%s - uart_flush error", __func__); + dev_dbg(&port->dev, "%s - uart_flush error\n", __func__); uart_enable_failed: kfree(buf); return status; } -/* Diables the IUU UART (a.k.a. the Phoenix voiderface) */ +/* Disables the IUU UART (a.k.a. the Phoenix voiderface) */ static int iuu_uart_off(struct usb_serial_port *port) { int status; @@ -850,7 +781,7 @@ static int iuu_uart_off(struct usb_serial_port *port) status = bulk_immediate(port, buf, 1); if (status != IUU_OPERATION_OK) - dbg("%s - uart_off error", __func__); + dev_dbg(&port->dev, "%s - uart_off error\n", __func__); kfree(buf); return status; @@ -867,7 +798,7 @@ static int iuu_uart_baud(struct usb_serial_port *port, u32 baud_base, u8 T1reload = 0; unsigned int T1FrekvensHZ = 0; - dbg("%s - enter baud_base=%d", __func__, baud_base); + dev_dbg(&port->dev, "%s - enter baud_base=%d\n", __func__, baud_base); dataout = kmalloc(sizeof(u8) * 5, GFP_KERNEL); if (!dataout) @@ -948,7 +879,7 @@ static int iuu_uart_baud(struct usb_serial_port *port, u32 baud_base, status = bulk_immediate(port, dataout, DataCount); if (status != IUU_OPERATION_OK) - dbg("%s - uart_off error", __func__); + dev_dbg(&port->dev, "%s - uart_off error\n", __func__); kfree(dataout); return status; } @@ -958,7 +889,7 @@ static void iuu_set_termios(struct tty_struct *tty, { const u32 supported_mask = CMSPAR|PARENB|PARODD; struct iuu_private *priv = usb_get_serial_port_data(port); - unsigned int cflag = tty->termios->c_cflag; + unsigned int cflag = tty->termios.c_cflag; int status; u32 actual; u32 parity; @@ -967,9 +898,9 @@ static void iuu_set_termios(struct tty_struct *tty, u32 newval = cflag & supported_mask; /* Just use the ospeed. ispeed should be the same. */ - baud = tty->termios->c_ospeed; + baud = tty->termios.c_ospeed; - dbg("%s - enter c_ospeed or baud=%d", __func__, baud); + dev_dbg(&port->dev, "%s - enter c_ospeed or baud=%d\n", __func__, baud); /* compute the parity parameter */ parity = 0; @@ -998,66 +929,55 @@ static void iuu_set_termios(struct tty_struct *tty, * settings back over and then adjust them */ if (old_termios) - tty_termios_copy_hw(tty->termios, old_termios); + tty_termios_copy_hw(&tty->termios, old_termios); if (status != 0) /* Set failed - return old bits */ return; /* Re-encode speed, parity and csize */ tty_encode_baud_rate(tty, baud, baud); - tty->termios->c_cflag &= ~(supported_mask|CSIZE); - tty->termios->c_cflag |= newval | csize; + tty->termios.c_cflag &= ~(supported_mask|CSIZE); + tty->termios.c_cflag |= newval | csize; } static void iuu_close(struct usb_serial_port *port) { /* iuu_led (port,255,0,0,0); */ - struct usb_serial *serial; - serial = port->serial; - if (!serial) - return; + iuu_uart_off(port); - dbg("%s - port %d", __func__, port->number); + usb_kill_urb(port->write_urb); + usb_kill_urb(port->read_urb); - iuu_uart_off(port); - if (serial->dev) { - /* free writebuf */ - /* shutdown our urbs */ - dbg("%s - shutting down urbs", __func__); - usb_kill_urb(port->write_urb); - usb_kill_urb(port->read_urb); - usb_kill_urb(port->interrupt_in_urb); - iuu_led(port, 0, 0, 0xF000, 0xFF); - } + iuu_led(port, 0, 0, 0xF000, 0xFF); } static void iuu_init_termios(struct tty_struct *tty) { - dbg("%s - enter", __func__); - *(tty->termios) = tty_std_termios; - tty->termios->c_cflag = CLOCAL | CREAD | CS8 | B9600 + tty->termios = tty_std_termios; + tty->termios.c_cflag = CLOCAL | CREAD | CS8 | B9600 | TIOCM_CTS | CSTOPB | PARENB; - tty->termios->c_ispeed = 9600; - tty->termios->c_ospeed = 9600; - tty->termios->c_lflag = 0; - tty->termios->c_oflag = 0; - tty->termios->c_iflag = 0; + tty->termios.c_ispeed = 9600; + tty->termios.c_ospeed = 9600; + tty->termios.c_lflag = 0; + tty->termios.c_oflag = 0; + tty->termios.c_iflag = 0; } static int iuu_open(struct tty_struct *tty, struct usb_serial_port *port) { struct usb_serial *serial = port->serial; + struct device *dev = &port->dev; u8 *buf; int result; int baud; u32 actual; struct iuu_private *priv = usb_get_serial_port_data(port); - baud = tty->termios->c_ospeed; - tty->termios->c_ispeed = baud; + baud = tty->termios.c_ospeed; + tty->termios.c_ispeed = baud; /* Re-encode speed */ tty_encode_baud_rate(tty, baud, baud); - dbg("%s - port %d, baud %d", __func__, port->number, baud); + dev_dbg(dev, "%s - baud %d\n", __func__, baud); usb_clear_halt(serial->dev, port->write_urb->pipe); usb_clear_halt(serial->dev, port->read_urb->pipe); @@ -1072,14 +992,14 @@ static int iuu_open(struct tty_struct *tty, struct usb_serial_port *port) result = usb_control_msg(port->serial->dev, \ usb_rcvctrlpipe(port->serial->dev, 0), \ b, a, c, d, buf, 1, 1000); \ - dbg("0x%x:0x%x:0x%x:0x%x %d - %x", a, b, c, d, result, \ + dev_dbg(dev, "0x%x:0x%x:0x%x:0x%x %d - %x\n", a, b, c, d, result, \ buf[0]); } while (0); #define SOUP(a, b, c, d) do { \ result = usb_control_msg(port->serial->dev, \ usb_sndctrlpipe(port->serial->dev, 0), \ b, a, c, d, NULL, 0, 1000); \ - dbg("0x%x:0x%x:0x%x:0x%x %d", a, b, c, d, result); } while (0) + dev_dbg(dev, "0x%x:0x%x:0x%x:0x%x %d\n", a, b, c, d, result); } while (0) /* This is not UART related but IUU USB driver related or something */ /* like that. Basically no IUU will accept any commands from the USB */ @@ -1159,7 +1079,7 @@ static int iuu_open(struct tty_struct *tty, struct usb_serial_port *port) iuu_uart_flush(port); - dbg("%s - initialization done", __func__); + dev_dbg(dev, "%s - initialization done\n", __func__); memset(port->write_urb->transfer_buffer, IUU_UART_RX, 1); usb_fill_bulk_urb(port->write_urb, port->serial->dev, @@ -1168,15 +1088,13 @@ static int iuu_open(struct tty_struct *tty, struct usb_serial_port *port) port->write_urb->transfer_buffer, 1, read_rxcmd_callback, port); result = usb_submit_urb(port->write_urb, GFP_KERNEL); - if (result) { - dev_err(&port->dev, "%s - failed submitting read urb," - " error %d\n", __func__, result); + dev_err(dev, "%s - failed submitting read urb, error %d\n", __func__, result); iuu_close(port); - return -EPROTO; } else { - dbg("%s - rxcmd OK", __func__); + dev_dbg(dev, "%s - rxcmd OK\n", __func__); } + return result; } @@ -1190,8 +1108,6 @@ static int iuu_vcc_set(struct usb_serial_port *port, unsigned int vcc) if (!buf) return -ENOMEM; - dbg("%s - enter", __func__); - buf[0] = IUU_SET_VCC; buf[1] = vcc & 0xFF; buf[2] = (vcc >> 8) & 0xFF; @@ -1202,9 +1118,9 @@ static int iuu_vcc_set(struct usb_serial_port *port, unsigned int vcc) kfree(buf); if (status != IUU_OPERATION_OK) - dbg("%s - vcc error status = %2x", __func__, status); + dev_dbg(&port->dev, "%s - vcc error status = %2x\n", __func__, status); else - dbg("%s - vcc OK !", __func__); + dev_dbg(&port->dev, "%s - vcc OK !\n", __func__); return status; } @@ -1213,7 +1129,7 @@ static int iuu_vcc_set(struct usb_serial_port *port, unsigned int vcc) * Sysfs Attributes */ -static ssize_t show_vcc_mode(struct device *dev, +static ssize_t vcc_mode_show(struct device *dev, struct device_attribute *attr, char *buf) { struct usb_serial_port *port = to_usb_serial_port(dev); @@ -1222,20 +1138,20 @@ static ssize_t show_vcc_mode(struct device *dev, return sprintf(buf, "%d\n", priv->vcc); } -static ssize_t store_vcc_mode(struct device *dev, +static ssize_t vcc_mode_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct usb_serial_port *port = to_usb_serial_port(dev); struct iuu_private *priv = usb_get_serial_port_data(port); unsigned long v; - if (strict_strtoul(buf, 10, &v)) { + if (kstrtoul(buf, 10, &v)) { dev_err(dev, "%s - vcc_mode: %s is not a unsigned long\n", __func__, buf); goto fail_store_vcc_mode; } - dbg("%s: setting vcc_mode = %ld", __func__, v); + dev_dbg(dev, "%s: setting vcc_mode = %ld\n", __func__, v); if ((v != 3) && (v != 5)) { dev_err(dev, "%s - vcc_mode %ld is invalid\n", __func__, v); @@ -1246,21 +1162,15 @@ static ssize_t store_vcc_mode(struct device *dev, fail_store_vcc_mode: return count; } - -static DEVICE_ATTR(vcc_mode, S_IRUSR | S_IWUSR, show_vcc_mode, - store_vcc_mode); +static DEVICE_ATTR_RW(vcc_mode); static int iuu_create_sysfs_attrs(struct usb_serial_port *port) { - dbg("%s", __func__); - return device_create_file(&port->dev, &dev_attr_vcc_mode); } static int iuu_remove_sysfs_attrs(struct usb_serial_port *port) { - dbg("%s", __func__); - device_remove_file(&port->dev, &dev_attr_vcc_mode); return 0; } @@ -1278,8 +1188,6 @@ static struct usb_serial_driver iuu_device = { .num_ports = 1, .bulk_in_size = 512, .bulk_out_size = 512, - .port_probe = iuu_create_sysfs_attrs, - .port_remove = iuu_remove_sysfs_attrs, .open = iuu_open, .close = iuu_close, .write = iuu_uart_write, @@ -1288,46 +1196,21 @@ static struct usb_serial_driver iuu_device = { .tiocmset = iuu_tiocmset, .set_termios = iuu_set_termios, .init_termios = iuu_init_termios, - .attach = iuu_startup, - .release = iuu_release, + .port_probe = iuu_port_probe, + .port_remove = iuu_port_remove, }; -static int __init iuu_init(void) -{ - int retval; - retval = usb_serial_register(&iuu_device); - if (retval) - goto failed_usb_serial_register; - retval = usb_register(&iuu_driver); - if (retval) - goto failed_usb_register; - printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" - DRIVER_DESC "\n"); - return 0; -failed_usb_register: - usb_serial_deregister(&iuu_device); -failed_usb_serial_register: - return retval; -} - -static void __exit iuu_exit(void) -{ - usb_deregister(&iuu_driver); - usb_serial_deregister(&iuu_device); -} +static struct usb_serial_driver * const serial_drivers[] = { + &iuu_device, NULL +}; -module_init(iuu_init); -module_exit(iuu_exit); +module_usb_serial_driver(serial_drivers, id_table); MODULE_AUTHOR("Alain Degreffe eczema@ecze.com"); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); -MODULE_VERSION(DRIVER_VERSION); -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); - module_param(xmas, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(xmas, "Xmas colors enabled or not"); diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c index 0791778a66f..93cb7cebda6 100644 --- a/drivers/usb/serial/keyspan.c +++ b/drivers/usb/serial/keyspan.c @@ -25,122 +25,51 @@ Tip 'o the hat to IBM (and previously Linuxcare :) for supporting staff in their work on open source projects. - - Change History - - 2003sep04 LPM (Keyspan) add support for new single port product USA19HS. - Improve setup message handling for all devices. - - Wed Feb 19 22:00:00 PST 2003 (Jeffrey S. Laing <keyspan@jsl.com>) - Merged the current (1/31/03) Keyspan code with the current (2.4.21-pre4) - Linux source tree. The Linux tree lacked support for the 49WLC and - others. The Keyspan patches didn't work with the current kernel. - - 2003jan30 LPM add support for the 49WLC and MPR - - Wed Apr 25 12:00:00 PST 2002 (Keyspan) - Started with Hugh Blemings' code dated Jan 17, 2002. All adapters - now supported (including QI and QW). Modified port open, port - close, and send setup() logic to fix various data and endpoint - synchronization bugs and device LED status bugs. Changed keyspan_ - write_room() to accurately return transmit buffer availability. - Changed forwardingLength from 1 to 16 for all adapters. - - Fri Oct 12 16:45:00 EST 2001 - Preliminary USA-19QI and USA-28 support (both test OK for me, YMMV) - - Wed Apr 25 12:00:00 PST 2002 (Keyspan) - Started with Hugh Blemings' code dated Jan 17, 2002. All adapters - now supported (including QI and QW). Modified port open, port - close, and send setup() logic to fix various data and endpoint - synchronization bugs and device LED status bugs. Changed keyspan_ - write_room() to accurately return transmit buffer availability. - Changed forwardingLength from 1 to 16 for all adapters. - - Fri Oct 12 16:45:00 EST 2001 - Preliminary USA-19QI and USA-28 support (both test OK for me, YMMV) - - Mon Oct 8 14:29:00 EST 2001 hugh - Fixed bug that prevented mulitport devices operating correctly - if they weren't the first unit attached. - - Sat Oct 6 12:31:21 EST 2001 hugh - Added support for USA-28XA and -28XB, misc cleanups, break support - for usa26 based models thanks to David Gibson. - - Thu May 31 11:56:42 PDT 2001 gkh - switched from using spinlock to a semaphore - - (04/08/2001) gb - Identify version on module load. - - (11/01/2000) Adam J. Richter - usb_device_id table support. - - Tue Oct 10 23:15:33 EST 2000 Hugh - Merged Paul's changes with my USA-49W mods. Work in progress - still... - - Wed Jul 19 14:00:42 EST 2000 gkh - Added module_init and module_exit functions to handle the fact that - this driver is a loadable module now. - - Tue Jul 18 16:14:52 EST 2000 Hugh - Basic character input/output for USA-19 now mostly works, - fixed at 9600 baud for the moment. - - Sat Jul 8 11:11:48 EST 2000 Hugh - First public release - nothing works except the firmware upload. - Tested on PPC and x86 architectures, seems to behave... */ #include <linux/kernel.h> #include <linux/jiffies.h> #include <linux/errno.h> -#include <linux/init.h> #include <linux/slab.h> #include <linux/tty.h> #include <linux/tty_driver.h> #include <linux/tty_flip.h> #include <linux/module.h> #include <linux/spinlock.h> -#include <linux/firmware.h> -#include <linux/ihex.h> #include <linux/uaccess.h> #include <linux/usb.h> #include <linux/usb/serial.h> +#include <linux/usb/ezusb.h> #include "keyspan.h" -static int debug; - -/* - * Version Information - */ -#define DRIVER_VERSION "v1.1.5" #define DRIVER_AUTHOR "Hugh Blemings <hugh@misc.nu" #define DRIVER_DESC "Keyspan USB to Serial Converter Driver" #define INSTAT_BUFLEN 32 #define GLOCONT_BUFLEN 64 #define INDAT49W_BUFLEN 512 +#define IN_BUFLEN 64 +#define OUT_BUFLEN 64 +#define INACK_BUFLEN 1 +#define OUTCONT_BUFLEN 64 /* Per device and per port private data */ struct keyspan_serial_private { const struct keyspan_device_details *device_details; struct urb *instat_urb; - char instat_buf[INSTAT_BUFLEN]; + char *instat_buf; /* added to support 49wg, where data from all 4 ports comes in on 1 EP and high-speed supported */ struct urb *indat_urb; - char indat_buf[INDAT49W_BUFLEN]; + char *indat_buf; /* XXX this one probably will need a lock */ struct urb *glocont_urb; - char glocont_buf[GLOCONT_BUFLEN]; - char ctrl_buf[8]; /* for EP0 control message */ + char *glocont_buf; + char *ctrl_buf; /* for EP0 control message */ }; struct keyspan_port_private { @@ -155,18 +84,18 @@ struct keyspan_port_private { /* Input endpoints and buffer for this port */ struct urb *in_urbs[2]; - char in_buffer[2][64]; + char *in_buffer[2]; /* Output endpoints and buffer for this port */ struct urb *out_urbs[2]; - char out_buffer[2][64]; + char *out_buffer[2]; /* Input ack endpoint */ struct urb *inack_urb; - char inack_buffer[1]; + char *inack_buffer; /* Output control endpoint */ struct urb *outcont_urb; - char outcont_buffer[64]; + char *outcont_buffer; /* Settings for the port */ int baud; @@ -197,61 +126,13 @@ struct keyspan_port_private { #include "keyspan_usa67msg.h" -/* Functions used by new usb-serial code. */ -static int __init keyspan_init(void) -{ - int retval; - retval = usb_serial_register(&keyspan_pre_device); - if (retval) - goto failed_pre_device_register; - retval = usb_serial_register(&keyspan_1port_device); - if (retval) - goto failed_1port_device_register; - retval = usb_serial_register(&keyspan_2port_device); - if (retval) - goto failed_2port_device_register; - retval = usb_serial_register(&keyspan_4port_device); - if (retval) - goto failed_4port_device_register; - retval = usb_register(&keyspan_driver); - if (retval) - goto failed_usb_register; - - printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" - DRIVER_DESC "\n"); - - return 0; -failed_usb_register: - usb_serial_deregister(&keyspan_4port_device); -failed_4port_device_register: - usb_serial_deregister(&keyspan_2port_device); -failed_2port_device_register: - usb_serial_deregister(&keyspan_1port_device); -failed_1port_device_register: - usb_serial_deregister(&keyspan_pre_device); -failed_pre_device_register: - return retval; -} - -static void __exit keyspan_exit(void) -{ - usb_deregister(&keyspan_driver); - usb_serial_deregister(&keyspan_pre_device); - usb_serial_deregister(&keyspan_1port_device); - usb_serial_deregister(&keyspan_2port_device); - usb_serial_deregister(&keyspan_4port_device); -} - -module_init(keyspan_init); -module_exit(keyspan_exit); +module_usb_serial_driver(serial_drivers, keyspan_ids_combined); static void keyspan_break_ctl(struct tty_struct *tty, int break_state) { struct usb_serial_port *port = tty->driver_data; struct keyspan_port_private *p_priv; - dbg("%s", __func__); - p_priv = usb_get_serial_port_data(port); if (break_state == -1) @@ -271,21 +152,19 @@ static void keyspan_set_termios(struct tty_struct *tty, const struct keyspan_device_details *d_details; unsigned int cflag; - dbg("%s", __func__); - p_priv = usb_get_serial_port_data(port); d_details = p_priv->device_details; - cflag = tty->termios->c_cflag; - device_port = port->number - port->serial->minor; + cflag = tty->termios.c_cflag; + device_port = port->port_number; /* Baud rate calculation takes baud rate as an integer so other rates can be generated if desired. */ baud_rate = tty_get_baud_rate(tty); /* If no match or invalid, don't change */ - if (d_details->calculate_baud_rate(baud_rate, d_details->baudclk, + if (d_details->calculate_baud_rate(port, baud_rate, d_details->baudclk, NULL, NULL, NULL, device_port) == KEYSPAN_BAUD_RATE_OK) { /* FIXME - more to do here to ensure rate changes cleanly */ - /* FIXME - calcuate exact rate from divisor ? */ + /* FIXME - calculate exact rate from divisor ? */ p_priv->baud = baud_rate; } else baud_rate = tty_termios_baud_rate(old_termios); @@ -293,15 +172,15 @@ static void keyspan_set_termios(struct tty_struct *tty, tty_encode_baud_rate(tty, baud_rate, baud_rate); /* set CTS/RTS handshake etc. */ p_priv->cflag = cflag; - p_priv->flow_control = (cflag & CRTSCTS)? flow_cts: flow_none; + p_priv->flow_control = (cflag & CRTSCTS) ? flow_cts : flow_none; /* Mark/Space not supported */ - tty->termios->c_cflag &= ~CMSPAR; + tty->termios.c_cflag &= ~CMSPAR; keyspan_send_setup(port, 0); } -static int keyspan_tiocmget(struct tty_struct *tty, struct file *file) +static int keyspan_tiocmget(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; struct keyspan_port_private *p_priv = usb_get_serial_port_data(port); @@ -317,7 +196,7 @@ static int keyspan_tiocmget(struct tty_struct *tty, struct file *file) return value; } -static int keyspan_tiocmset(struct tty_struct *tty, struct file *file, +static int keyspan_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) { struct usb_serial_port *port = tty->driver_data; @@ -358,8 +237,8 @@ static int keyspan_write(struct tty_struct *tty, dataOffset = 1; } - dbg("%s - for port %d (%d chars), flip=%d", - __func__, port->number, count, p_priv->out_flip); + dev_dbg(&port->dev, "%s - %d chars, flip=%d\n", __func__, count, + p_priv->out_flip); for (left = count; left > 0; left -= todo) { todo = left; @@ -372,11 +251,11 @@ static int keyspan_write(struct tty_struct *tty, this_urb = p_priv->out_urbs[flip]; if (this_urb == NULL) { /* no bulk out, so return 0 bytes written */ - dbg("%s - no output urb :(", __func__); + dev_dbg(&port->dev, "%s - no output urb :(\n", __func__); return count; } - dbg("%s - endpoint %d flip %d", + dev_dbg(&port->dev, "%s - endpoint %d flip %d\n", __func__, usb_pipeendpoint(this_urb->pipe), flip); if (this_urb->status == -EINPROGRESS) { @@ -397,10 +276,9 @@ static int keyspan_write(struct tty_struct *tty, /* send the data out the bulk port */ this_urb->transfer_buffer_length = todo + dataOffset; - this_urb->dev = port->serial->dev; err = usb_submit_urb(this_urb, GFP_ATOMIC); if (err != 0) - dbg("usb_submit_urb(write bulk) failed (%d)", err); + dev_dbg(&port->dev, "usb_submit_urb(write bulk) failed (%d)\n", err); p_priv->tx_start_time[flip] = jiffies; /* Flip for next time if usa26 or usa28 interface @@ -416,23 +294,19 @@ static void usa26_indat_callback(struct urb *urb) int i, err; int endpoint; struct usb_serial_port *port; - struct tty_struct *tty; unsigned char *data = urb->transfer_buffer; int status = urb->status; - dbg("%s", __func__); - endpoint = usb_pipeendpoint(urb->pipe); if (status) { - dbg("%s - nonzero status: %x on endpoint %d.", - __func__, status, endpoint); + dev_dbg(&urb->dev->dev, "%s - nonzero status: %x on endpoint %d.\n", + __func__, status, endpoint); return; } port = urb->context; - tty = tty_port_tty_get(&port->port); - if (tty && urb->actual_length) { + if (urb->actual_length) { /* 0x80 bit is error flag */ if ((data[0] & 0x80) == 0) { /* no errors on individual bytes, only @@ -442,10 +316,10 @@ static void usa26_indat_callback(struct urb *urb) else err = 0; for (i = 1; i < urb->actual_length ; ++i) - tty_insert_flip_char(tty, data[i], err); + tty_insert_flip_char(&port->port, data[i], err); } else { /* some bytes had errors, every byte has status */ - dbg("%s - RX error!!!!", __func__); + dev_dbg(&port->dev, "%s - RX error!!!!\n", __func__); for (i = 0; i + 1 < urb->actual_length; i += 2) { int stat = data[i], flag = 0; if (stat & RXERROR_OVERRUN) @@ -455,18 +329,17 @@ static void usa26_indat_callback(struct urb *urb) if (stat & RXERROR_PARITY) flag |= TTY_PARITY; /* XXX should handle break (0x10) */ - tty_insert_flip_char(tty, data[i+1], flag); + tty_insert_flip_char(&port->port, data[i+1], + flag); } } - tty_flip_buffer_push(tty); + tty_flip_buffer_push(&port->port); } - tty_kref_put(tty); /* Resubmit urb so we continue receiving */ - urb->dev = port->serial->dev; err = usb_submit_urb(urb, GFP_ATOMIC); if (err != 0) - dbg("%s - resubmit read urb failed. (%d)", __func__, err); + dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err); } /* Outdat handling is common for all devices */ @@ -477,15 +350,13 @@ static void usa2x_outdat_callback(struct urb *urb) port = urb->context; p_priv = usb_get_serial_port_data(port); - dbg("%s - urb %d", __func__, urb == p_priv->out_urbs[1]); + dev_dbg(&port->dev, "%s - urb %d\n", __func__, urb == p_priv->out_urbs[1]); usb_serial_port_softint(port); } static void usa26_inack_callback(struct urb *urb) { - dbg("%s", __func__); - } static void usa26_outcont_callback(struct urb *urb) @@ -497,7 +368,7 @@ static void usa26_outcont_callback(struct urb *urb) p_priv = usb_get_serial_port_data(port); if (p_priv->resend_cont) { - dbg("%s - sending setup", __func__); + dev_dbg(&port->dev, "%s - sending setup\n", __func__); keyspan_usa26_send_setup(port->serial, port, p_priv->resend_cont - 1); } @@ -510,35 +381,25 @@ static void usa26_instat_callback(struct urb *urb) struct usb_serial *serial; struct usb_serial_port *port; struct keyspan_port_private *p_priv; - struct tty_struct *tty; int old_dcd_state, err; int status = urb->status; serial = urb->context; if (status) { - dbg("%s - nonzero status: %x", __func__, status); + dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status); return; } if (urb->actual_length != 9) { - dbg("%s - %d byte report??", __func__, urb->actual_length); + dev_dbg(&urb->dev->dev, "%s - %d byte report??\n", __func__, urb->actual_length); goto exit; } msg = (struct keyspan_usa26_portStatusMessage *)data; -#if 0 - dbg("%s - port status: port %d cts %d dcd %d dsr %d ri %d toff %d txoff %d rxen %d cr %d", - __func__, msg->port, msg->hskia_cts, msg->gpia_dcd, msg->dsr, msg->ri, msg->_txOff, - msg->_txXoff, msg->rxEnabled, msg->controlResponse); -#endif - - /* Now do something useful with the data */ - - /* Check port number from message and retrieve private data */ if (msg->port >= serial->num_ports) { - dbg("%s - Unexpected port number %d", __func__, msg->port); + dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", __func__, msg->port); goto exit; } port = serial->port[msg->port]; @@ -551,24 +412,18 @@ static void usa26_instat_callback(struct urb *urb) p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0); p_priv->ri_state = ((msg->ri) ? 1 : 0); - if (old_dcd_state != p_priv->dcd_state) { - tty = tty_port_tty_get(&port->port); - if (tty && !C_CLOCAL(tty)) - tty_hangup(tty); - tty_kref_put(tty); - } + if (old_dcd_state != p_priv->dcd_state) + tty_port_tty_hangup(&port->port, true); /* Resubmit urb so we continue receiving */ - urb->dev = serial->dev; err = usb_submit_urb(urb, GFP_ATOMIC); if (err != 0) - dbg("%s - resubmit read urb failed. (%d)", __func__, err); + dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err); exit: ; } static void usa26_glocont_callback(struct urb *urb) { - dbg("%s", __func__); } @@ -576,13 +431,10 @@ static void usa28_indat_callback(struct urb *urb) { int err; struct usb_serial_port *port; - struct tty_struct *tty; unsigned char *data; struct keyspan_port_private *p_priv; int status = urb->status; - dbg("%s", __func__); - port = urb->context; p_priv = usb_get_serial_port_data(port); data = urb->transfer_buffer; @@ -592,8 +444,8 @@ static void usa28_indat_callback(struct urb *urb) do { if (status) { - dbg("%s - nonzero status: %x on endpoint %d.", - __func__, status, usb_pipeendpoint(urb->pipe)); + dev_dbg(&urb->dev->dev, "%s - nonzero status: %x on endpoint %d.\n", + __func__, status, usb_pipeendpoint(urb->pipe)); return; } @@ -601,18 +453,16 @@ static void usa28_indat_callback(struct urb *urb) p_priv = usb_get_serial_port_data(port); data = urb->transfer_buffer; - tty =tty_port_tty_get(&port->port); - if (tty && urb->actual_length) { - tty_insert_flip_string(tty, data, urb->actual_length); - tty_flip_buffer_push(tty); + if (urb->actual_length) { + tty_insert_flip_string(&port->port, data, + urb->actual_length); + tty_flip_buffer_push(&port->port); } - tty_kref_put(tty); /* Resubmit urb so we continue receiving */ - urb->dev = port->serial->dev; err = usb_submit_urb(urb, GFP_ATOMIC); if (err != 0) - dbg("%s - resubmit read urb failed. (%d)", + dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err); p_priv->in_flip ^= 1; @@ -622,7 +472,6 @@ static void usa28_indat_callback(struct urb *urb) static void usa28_inack_callback(struct urb *urb) { - dbg("%s", __func__); } static void usa28_outcont_callback(struct urb *urb) @@ -634,7 +483,7 @@ static void usa28_outcont_callback(struct urb *urb) p_priv = usb_get_serial_port_data(port); if (p_priv->resend_cont) { - dbg("%s - sending setup", __func__); + dev_dbg(&port->dev, "%s - sending setup\n", __func__); keyspan_usa28_send_setup(port->serial, port, p_priv->resend_cont - 1); } @@ -648,32 +497,26 @@ static void usa28_instat_callback(struct urb *urb) struct usb_serial *serial; struct usb_serial_port *port; struct keyspan_port_private *p_priv; - struct tty_struct *tty; int old_dcd_state; int status = urb->status; serial = urb->context; if (status) { - dbg("%s - nonzero status: %x", __func__, status); + dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status); return; } if (urb->actual_length != sizeof(struct keyspan_usa28_portStatusMessage)) { - dbg("%s - bad length %d", __func__, urb->actual_length); + dev_dbg(&urb->dev->dev, "%s - bad length %d\n", __func__, urb->actual_length); goto exit; } - /*dbg("%s %x %x %x %x %x %x %x %x %x %x %x %x", __func__ - data[0], data[1], data[2], data[3], data[4], data[5], - data[6], data[7], data[8], data[9], data[10], data[11]);*/ - - /* Now do something useful with the data */ msg = (struct keyspan_usa28_portStatusMessage *)data; /* Check port number from message and retrieve private data */ if (msg->port >= serial->num_ports) { - dbg("%s - Unexpected port number %d", __func__, msg->port); + dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", __func__, msg->port); goto exit; } port = serial->port[msg->port]; @@ -686,24 +529,18 @@ static void usa28_instat_callback(struct urb *urb) p_priv->dcd_state = ((msg->dcd) ? 1 : 0); p_priv->ri_state = ((msg->ri) ? 1 : 0); - if( old_dcd_state != p_priv->dcd_state && old_dcd_state) { - tty = tty_port_tty_get(&port->port); - if (tty && !C_CLOCAL(tty)) - tty_hangup(tty); - tty_kref_put(tty); - } + if (old_dcd_state != p_priv->dcd_state && old_dcd_state) + tty_port_tty_hangup(&port->port, true); /* Resubmit urb so we continue receiving */ - urb->dev = serial->dev; err = usb_submit_urb(urb, GFP_ATOMIC); if (err != 0) - dbg("%s - resubmit read urb failed. (%d)", __func__, err); + dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err); exit: ; } static void usa28_glocont_callback(struct urb *urb) { - dbg("%s", __func__); } @@ -714,15 +551,13 @@ static void usa49_glocont_callback(struct urb *urb) struct keyspan_port_private *p_priv; int i; - dbg("%s", __func__); - serial = urb->context; for (i = 0; i < serial->num_ports; ++i) { port = serial->port[i]; p_priv = usb_get_serial_port_data(port); if (p_priv->resend_cont) { - dbg("%s - sending setup", __func__); + dev_dbg(&port->dev, "%s - sending setup\n", __func__); keyspan_usa49_send_setup(serial, port, p_priv->resend_cont - 1); break; @@ -743,32 +578,25 @@ static void usa49_instat_callback(struct urb *urb) int old_dcd_state; int status = urb->status; - dbg("%s", __func__); - serial = urb->context; if (status) { - dbg("%s - nonzero status: %x", __func__, status); + dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status); return; } if (urb->actual_length != sizeof(struct keyspan_usa49_portStatusMessage)) { - dbg("%s - bad length %d", __func__, urb->actual_length); + dev_dbg(&urb->dev->dev, "%s - bad length %d\n", __func__, urb->actual_length); goto exit; } - /*dbg(" %x %x %x %x %x %x %x %x %x %x %x", __func__, - data[0], data[1], data[2], data[3], data[4], data[5], - data[6], data[7], data[8], data[9], data[10]);*/ - - /* Now do something useful with the data */ msg = (struct keyspan_usa49_portStatusMessage *)data; /* Check port number from message and retrieve private data */ if (msg->portNumber >= serial->num_ports) { - dbg("%s - Unexpected port number %d", - __func__, msg->portNumber); + dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", + __func__, msg->portNumber); goto exit; } port = serial->port[msg->portNumber]; @@ -781,25 +609,18 @@ static void usa49_instat_callback(struct urb *urb) p_priv->dcd_state = ((msg->dcd) ? 1 : 0); p_priv->ri_state = ((msg->ri) ? 1 : 0); - if (old_dcd_state != p_priv->dcd_state && old_dcd_state) { - struct tty_struct *tty = tty_port_tty_get(&port->port); - if (tty && !C_CLOCAL(tty)) - tty_hangup(tty); - tty_kref_put(tty); - } + if (old_dcd_state != p_priv->dcd_state && old_dcd_state) + tty_port_tty_hangup(&port->port, true); /* Resubmit urb so we continue receiving */ - urb->dev = serial->dev; - err = usb_submit_urb(urb, GFP_ATOMIC); if (err != 0) - dbg("%s - resubmit read urb failed. (%d)", __func__, err); + dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err); exit: ; } static void usa49_inack_callback(struct urb *urb) { - dbg("%s", __func__); } static void usa49_indat_callback(struct urb *urb) @@ -807,27 +628,23 @@ static void usa49_indat_callback(struct urb *urb) int i, err; int endpoint; struct usb_serial_port *port; - struct tty_struct *tty; unsigned char *data = urb->transfer_buffer; int status = urb->status; - dbg("%s", __func__); - endpoint = usb_pipeendpoint(urb->pipe); if (status) { - dbg("%s - nonzero status: %x on endpoint %d.", __func__, - status, endpoint); + dev_dbg(&urb->dev->dev, "%s - nonzero status: %x on endpoint %d.\n", + __func__, status, endpoint); return; } port = urb->context; - tty = tty_port_tty_get(&port->port); - if (tty && urb->actual_length) { + if (urb->actual_length) { /* 0x80 bit is error flag */ if ((data[0] & 0x80) == 0) { /* no error on any byte */ - tty_insert_flip_string(tty, data + 1, + tty_insert_flip_string(&port->port, data + 1, urb->actual_length - 1); } else { /* some bytes had errors, every byte has status */ @@ -840,18 +657,17 @@ static void usa49_indat_callback(struct urb *urb) if (stat & RXERROR_PARITY) flag |= TTY_PARITY; /* XXX should handle break (0x10) */ - tty_insert_flip_char(tty, data[i+1], flag); + tty_insert_flip_char(&port->port, data[i+1], + flag); } } - tty_flip_buffer_push(tty); + tty_flip_buffer_push(&port->port); } - tty_kref_put(tty); /* Resubmit urb so we continue receiving */ - urb->dev = port->serial->dev; err = usb_submit_urb(urb, GFP_ATOMIC); if (err != 0) - dbg("%s - resubmit read urb failed. (%d)", __func__, err); + dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err); } static void usa49wg_indat_callback(struct urb *urb) @@ -859,16 +675,13 @@ static void usa49wg_indat_callback(struct urb *urb) int i, len, x, err; struct usb_serial *serial; struct usb_serial_port *port; - struct tty_struct *tty; unsigned char *data = urb->transfer_buffer; int status = urb->status; - dbg("%s", __func__); - serial = urb->context; if (status) { - dbg("%s - nonzero status: %x", __func__, status); + dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status); return; } @@ -876,60 +689,56 @@ static void usa49wg_indat_callback(struct urb *urb) i = 0; len = 0; - if (urb->actual_length) { - while (i < urb->actual_length) { + while (i < urb->actual_length) { - /* Check port number from message*/ - if (data[i] >= serial->num_ports) { - dbg("%s - Unexpected port number %d", - __func__, data[i]); - return; - } - port = serial->port[data[i++]]; - tty = tty_port_tty_get(&port->port); - len = data[i++]; + /* Check port number from message */ + if (data[i] >= serial->num_ports) { + dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", + __func__, data[i]); + return; + } + port = serial->port[data[i++]]; + len = data[i++]; - /* 0x80 bit is error flag */ - if ((data[i] & 0x80) == 0) { - /* no error on any byte */ - i++; - for (x = 1; x < len ; ++x) - tty_insert_flip_char(tty, data[i++], 0); - } else { - /* - * some bytes had errors, every byte has status - */ - for (x = 0; x + 1 < len; x += 2) { - int stat = data[i], flag = 0; - if (stat & RXERROR_OVERRUN) - flag |= TTY_OVERRUN; - if (stat & RXERROR_FRAMING) - flag |= TTY_FRAME; - if (stat & RXERROR_PARITY) - flag |= TTY_PARITY; - /* XXX should handle break (0x10) */ - tty_insert_flip_char(tty, - data[i+1], flag); - i += 2; - } + /* 0x80 bit is error flag */ + if ((data[i] & 0x80) == 0) { + /* no error on any byte */ + i++; + for (x = 1; x < len && i < urb->actual_length; ++x) + tty_insert_flip_char(&port->port, + data[i++], 0); + } else { + /* + * some bytes had errors, every byte has status + */ + for (x = 0; x + 1 < len && + i + 1 < urb->actual_length; x += 2) { + int stat = data[i], flag = 0; + + if (stat & RXERROR_OVERRUN) + flag |= TTY_OVERRUN; + if (stat & RXERROR_FRAMING) + flag |= TTY_FRAME; + if (stat & RXERROR_PARITY) + flag |= TTY_PARITY; + /* XXX should handle break (0x10) */ + tty_insert_flip_char(&port->port, data[i+1], + flag); + i += 2; } - tty_flip_buffer_push(tty); - tty_kref_put(tty); } + tty_flip_buffer_push(&port->port); } /* Resubmit urb so we continue receiving */ - urb->dev = serial->dev; - err = usb_submit_urb(urb, GFP_ATOMIC); if (err != 0) - dbg("%s - resubmit read urb failed. (%d)", __func__, err); + dev_dbg(&urb->dev->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err); } /* not used, usa-49 doesn't have per-port control endpoints */ static void usa49_outcont_callback(struct urb *urb) { - dbg("%s", __func__); } static void usa90_indat_callback(struct urb *urb) @@ -938,16 +747,13 @@ static void usa90_indat_callback(struct urb *urb) int endpoint; struct usb_serial_port *port; struct keyspan_port_private *p_priv; - struct tty_struct *tty; unsigned char *data = urb->transfer_buffer; int status = urb->status; - dbg("%s", __func__); - endpoint = usb_pipeendpoint(urb->pipe); if (status) { - dbg("%s - nonzero status: %x on endpoint %d.", + dev_dbg(&urb->dev->dev, "%s - nonzero status: %x on endpoint %d.\n", __func__, status, endpoint); return; } @@ -956,12 +762,12 @@ static void usa90_indat_callback(struct urb *urb) p_priv = usb_get_serial_port_data(port); if (urb->actual_length) { - tty = tty_port_tty_get(&port->port); /* if current mode is DMA, looks like usa28 format otherwise looks like usa26 data format */ if (p_priv->baud > 57600) - tty_insert_flip_string(tty, data, urb->actual_length); + tty_insert_flip_string(&port->port, data, + urb->actual_length); else { /* 0x80 bit is error flag */ if ((data[0] & 0x80) == 0) { @@ -972,11 +778,11 @@ static void usa90_indat_callback(struct urb *urb) else err = 0; for (i = 1; i < urb->actual_length ; ++i) - tty_insert_flip_char(tty, data[i], - err); + tty_insert_flip_char(&port->port, + data[i], err); } else { /* some bytes had errors, every byte has status */ - dbg("%s - RX error!!!!", __func__); + dev_dbg(&port->dev, "%s - RX error!!!!\n", __func__); for (i = 0; i + 1 < urb->actual_length; i += 2) { int stat = data[i], flag = 0; if (stat & RXERROR_OVERRUN) @@ -986,20 +792,18 @@ static void usa90_indat_callback(struct urb *urb) if (stat & RXERROR_PARITY) flag |= TTY_PARITY; /* XXX should handle break (0x10) */ - tty_insert_flip_char(tty, data[i+1], - flag); + tty_insert_flip_char(&port->port, + data[i+1], flag); } } } - tty_flip_buffer_push(tty); - tty_kref_put(tty); + tty_flip_buffer_push(&port->port); } /* Resubmit urb so we continue receiving */ - urb->dev = port->serial->dev; err = usb_submit_urb(urb, GFP_ATOMIC); if (err != 0) - dbg("%s - resubmit read urb failed. (%d)", __func__, err); + dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err); } @@ -1010,18 +814,17 @@ static void usa90_instat_callback(struct urb *urb) struct usb_serial *serial; struct usb_serial_port *port; struct keyspan_port_private *p_priv; - struct tty_struct *tty; int old_dcd_state, err; int status = urb->status; serial = urb->context; if (status) { - dbg("%s - nonzero status: %x", __func__, status); + dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status); return; } if (urb->actual_length < 14) { - dbg("%s - %d byte report??", __func__, urb->actual_length); + dev_dbg(&urb->dev->dev, "%s - %d byte report??\n", __func__, urb->actual_length); goto exit; } @@ -1039,18 +842,13 @@ static void usa90_instat_callback(struct urb *urb) p_priv->dcd_state = ((msg->dcd) ? 1 : 0); p_priv->ri_state = ((msg->ri) ? 1 : 0); - if (old_dcd_state != p_priv->dcd_state && old_dcd_state) { - tty = tty_port_tty_get(&port->port); - if (tty && !C_CLOCAL(tty)) - tty_hangup(tty); - tty_kref_put(tty); - } + if (old_dcd_state != p_priv->dcd_state && old_dcd_state) + tty_port_tty_hangup(&port->port, true); /* Resubmit urb so we continue receiving */ - urb->dev = serial->dev; err = usb_submit_urb(urb, GFP_ATOMIC); if (err != 0) - dbg("%s - resubmit read urb failed. (%d)", __func__, err); + dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err); exit: ; } @@ -1064,7 +862,7 @@ static void usa90_outcont_callback(struct urb *urb) p_priv = usb_get_serial_port_data(port); if (p_priv->resend_cont) { - dbg("%s - sending setup", __func__); + dev_dbg(&urb->dev->dev, "%s - sending setup\n", __func__); keyspan_usa90_send_setup(port->serial, port, p_priv->resend_cont - 1); } @@ -1082,18 +880,16 @@ static void usa67_instat_callback(struct urb *urb) int old_dcd_state; int status = urb->status; - dbg("%s", __func__); - serial = urb->context; if (status) { - dbg("%s - nonzero status: %x", __func__, status); + dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status); return; } if (urb->actual_length != sizeof(struct keyspan_usa67_portStatusMessage)) { - dbg("%s - bad length %d", __func__, urb->actual_length); + dev_dbg(&urb->dev->dev, "%s - bad length %d\n", __func__, urb->actual_length); return; } @@ -1103,7 +899,7 @@ static void usa67_instat_callback(struct urb *urb) /* Check port number from message and retrieve private data */ if (msg->port >= serial->num_ports) { - dbg("%s - Unexpected port number %d", __func__, msg->port); + dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", __func__, msg->port); return; } @@ -1115,18 +911,13 @@ static void usa67_instat_callback(struct urb *urb) p_priv->cts_state = ((msg->hskia_cts) ? 1 : 0); p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0); - if (old_dcd_state != p_priv->dcd_state && old_dcd_state) { - struct tty_struct *tty = tty_port_tty_get(&port->port); - if (tty && !C_CLOCAL(tty)) - tty_hangup(tty); - tty_kref_put(tty); - } + if (old_dcd_state != p_priv->dcd_state && old_dcd_state) + tty_port_tty_hangup(&port->port, true); /* Resubmit urb so we continue receiving */ - urb->dev = serial->dev; err = usb_submit_urb(urb, GFP_ATOMIC); if (err != 0) - dbg("%s - resubmit read urb failed. (%d)", __func__, err); + dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err); } static void usa67_glocont_callback(struct urb *urb) @@ -1136,15 +927,13 @@ static void usa67_glocont_callback(struct urb *urb) struct keyspan_port_private *p_priv; int i; - dbg("%s", __func__); - serial = urb->context; for (i = 0; i < serial->num_ports; ++i) { port = serial->port[i]; p_priv = usb_get_serial_port_data(port); if (p_priv->resend_cont) { - dbg("%s - sending setup", __func__); + dev_dbg(&port->dev, "%s - sending setup\n", __func__); keyspan_usa67_send_setup(serial, port, p_priv->resend_cont - 1); break; @@ -1161,7 +950,6 @@ static int keyspan_write_room(struct tty_struct *tty) int data_len; struct urb *this_urb; - dbg("%s", __func__); p_priv = usb_get_serial_port_data(port); d_details = p_priv->device_details; @@ -1192,20 +980,15 @@ static int keyspan_write_room(struct tty_struct *tty) static int keyspan_open(struct tty_struct *tty, struct usb_serial_port *port) { struct keyspan_port_private *p_priv; - struct keyspan_serial_private *s_priv; - struct usb_serial *serial = port->serial; const struct keyspan_device_details *d_details; int i, err; int baud_rate, device_port; struct urb *urb; unsigned int cflag = 0; - s_priv = usb_get_serial_data(serial); p_priv = usb_get_serial_port_data(port); d_details = p_priv->device_details; - dbg("%s - port%d.", __func__, port->number); - /* Set some sane defaults */ p_priv->rts_state = 1; p_priv->dtr_state = 1; @@ -1223,15 +1006,13 @@ static int keyspan_open(struct tty_struct *tty, struct usb_serial_port *port) urb = p_priv->in_urbs[i]; if (urb == NULL) continue; - urb->dev = serial->dev; /* make sure endpoint data toggle is synchronized with the device */ usb_clear_halt(urb->dev, urb->pipe); err = usb_submit_urb(urb, GFP_KERNEL); if (err != 0) - dbg("%s - submit urb %d failed (%d)", - __func__, i, err); + dev_dbg(&port->dev, "%s - submit urb %d failed (%d)\n", __func__, i, err); } /* Reset low level data toggle on out endpoints */ @@ -1239,7 +1020,6 @@ static int keyspan_open(struct tty_struct *tty, struct usb_serial_port *port) urb = p_priv->out_urbs[i]; if (urb == NULL) continue; - urb->dev = serial->dev; /* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe), 0); */ } @@ -1247,22 +1027,22 @@ static int keyspan_open(struct tty_struct *tty, struct usb_serial_port *port) /* get the terminal config for the setup message now so we don't * need to send 2 of them */ - device_port = port->number - port->serial->minor; + device_port = port->port_number; if (tty) { - cflag = tty->termios->c_cflag; + cflag = tty->termios.c_cflag; /* Baud rate calculation takes baud rate as an integer so other rates can be generated if desired. */ baud_rate = tty_get_baud_rate(tty); /* If no match or invalid, leave as default */ if (baud_rate >= 0 - && d_details->calculate_baud_rate(baud_rate, d_details->baudclk, + && d_details->calculate_baud_rate(port, baud_rate, d_details->baudclk, NULL, NULL, NULL, device_port) == KEYSPAN_BAUD_RATE_OK) { p_priv->baud = baud_rate; } } /* set CTS/RTS handshake etc. */ p_priv->cflag = cflag; - p_priv->flow_control = (cflag & CRTSCTS)? flow_cts: flow_none; + p_priv->flow_control = (cflag & CRTSCTS) ? flow_cts : flow_none; keyspan_send_setup(port, 1); /* mdelay(100); */ @@ -1289,57 +1069,39 @@ static void keyspan_dtr_rts(struct usb_serial_port *port, int on) static void keyspan_close(struct usb_serial_port *port) { int i; - struct usb_serial *serial = port->serial; - struct keyspan_serial_private *s_priv; struct keyspan_port_private *p_priv; - dbg("%s", __func__); - s_priv = usb_get_serial_data(serial); p_priv = usb_get_serial_port_data(port); p_priv->rts_state = 0; p_priv->dtr_state = 0; - if (serial->dev) { - keyspan_send_setup(port, 2); - /* pilot-xfer seems to work best with this delay */ - mdelay(100); - /* keyspan_set_termios(port, NULL); */ - } - - /*while (p_priv->outcont_urb->status == -EINPROGRESS) { - dbg("%s - urb in progress", __func__); - }*/ + keyspan_send_setup(port, 2); + /* pilot-xfer seems to work best with this delay */ + mdelay(100); p_priv->out_flip = 0; p_priv->in_flip = 0; - if (serial->dev) { - /* Stop reading/writing urbs */ - stop_urb(p_priv->inack_urb); - /* stop_urb(p_priv->outcont_urb); */ - for (i = 0; i < 2; i++) { - stop_urb(p_priv->in_urbs[i]); - stop_urb(p_priv->out_urbs[i]); - } + stop_urb(p_priv->inack_urb); + for (i = 0; i < 2; i++) { + stop_urb(p_priv->in_urbs[i]); + stop_urb(p_priv->out_urbs[i]); } } /* download the firmware to a pre-renumeration device */ static int keyspan_fake_startup(struct usb_serial *serial) { - int response; - const struct ihex_binrec *record; - char *fw_name; - const struct firmware *fw; + char *fw_name; - dbg("Keyspan startup version %04x product %04x", - le16_to_cpu(serial->dev->descriptor.bcdDevice), - le16_to_cpu(serial->dev->descriptor.idProduct)); + dev_dbg(&serial->dev->dev, "Keyspan startup version %04x product %04x\n", + le16_to_cpu(serial->dev->descriptor.bcdDevice), + le16_to_cpu(serial->dev->descriptor.idProduct)); if ((le16_to_cpu(serial->dev->descriptor.bcdDevice) & 0x8000) != 0x8000) { - dbg("Firmware already loaded. Quitting."); + dev_dbg(&serial->dev->dev, "Firmware already loaded. Quitting.\n"); return 1; } @@ -1399,34 +1161,16 @@ static int keyspan_fake_startup(struct usb_serial *serial) return 1; } - if (request_ihex_firmware(&fw, fw_name, &serial->dev->dev)) { - dev_err(&serial->dev->dev, "Required keyspan firmware image (%s) unavailable.\n", fw_name); - return(1); - } - - dbg("Uploading Keyspan %s firmware.", fw_name); - - /* download the firmware image */ - response = ezusb_set_reset(serial, 1); - - record = (const struct ihex_binrec *)fw->data; + dev_dbg(&serial->dev->dev, "Uploading Keyspan %s firmware.\n", fw_name); - while (record) { - response = ezusb_writememory(serial, be32_to_cpu(record->addr), - (unsigned char *)record->data, - be16_to_cpu(record->len), 0xa0); - if (response < 0) { - dev_err(&serial->dev->dev, "ezusb_writememory failed for Keyspan firmware (%d %04X %p %d)\n", - response, be32_to_cpu(record->addr), - record->data, be16_to_cpu(record->len)); - break; - } - record = ihex_next_binrec(record); + if (ezusb_fx1_ihex_firmware_download(serial->dev, fw_name) < 0) { + dev_err(&serial->dev->dev, "failed to load firmware \"%s\"\n", + fw_name); + return -ENOENT; } - release_firmware(fw); - /* bring device out of reset. Renumeration will occur in a - moment and the new device will bind to the real driver */ - response = ezusb_set_reset(serial, 0); + + /* after downloading firmware Renumeration will occur in a + moment and the new device will bind to the real driver */ /* we don't want this device to have a driver assigned to it. */ return 1; @@ -1462,12 +1206,10 @@ static struct urb *keyspan_setup_urb(struct usb_serial *serial, int endpoint, if (endpoint == -1) return NULL; /* endpoint not needed */ - dbg("%s - alloc for endpoint %d.", __func__, endpoint); + dev_dbg(&serial->interface->dev, "%s - alloc for endpoint %d.\n", __func__, endpoint); urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */ - if (urb == NULL) { - dbg("%s - alloc for endpoint %d failed.", __func__, endpoint); + if (!urb) return NULL; - } if (endpoint == 0) { /* control EP filled in when used */ @@ -1498,7 +1240,7 @@ static struct urb *keyspan_setup_urb(struct usb_serial *serial, int endpoint, return NULL; } - dbg("%s - using urb %p for %s endpoint %x", + dev_dbg(&serial->interface->dev, "%s - using urb %p for %s endpoint %x\n", __func__, urb, ep_type_name, endpoint); return urb; } @@ -1558,15 +1300,9 @@ static struct callbacks { data in device_details */ static void keyspan_setup_urbs(struct usb_serial *serial) { - int i, j; struct keyspan_serial_private *s_priv; const struct keyspan_device_details *d_details; - struct usb_serial_port *port; - struct keyspan_port_private *p_priv; struct callbacks *cback; - int endp; - - dbg("%s", __func__); s_priv = usb_get_serial_data(serial); d_details = s_priv->device_details; @@ -1590,56 +1326,18 @@ static void keyspan_setup_urbs(struct usb_serial *serial) (serial, d_details->glocont_endpoint, USB_DIR_OUT, serial, s_priv->glocont_buf, GLOCONT_BUFLEN, cback->glocont_callback); - - /* Setup endpoints for each port specific thing */ - for (i = 0; i < d_details->num_ports; i++) { - port = serial->port[i]; - p_priv = usb_get_serial_port_data(port); - - /* Do indat endpoints first, once for each flip */ - endp = d_details->indat_endpoints[i]; - for (j = 0; j <= d_details->indat_endp_flip; ++j, ++endp) { - p_priv->in_urbs[j] = keyspan_setup_urb - (serial, endp, USB_DIR_IN, port, - p_priv->in_buffer[j], 64, - cback->indat_callback); - } - for (; j < 2; ++j) - p_priv->in_urbs[j] = NULL; - - /* outdat endpoints also have flip */ - endp = d_details->outdat_endpoints[i]; - for (j = 0; j <= d_details->outdat_endp_flip; ++j, ++endp) { - p_priv->out_urbs[j] = keyspan_setup_urb - (serial, endp, USB_DIR_OUT, port, - p_priv->out_buffer[j], 64, - cback->outdat_callback); - } - for (; j < 2; ++j) - p_priv->out_urbs[j] = NULL; - - /* inack endpoint */ - p_priv->inack_urb = keyspan_setup_urb - (serial, d_details->inack_endpoints[i], USB_DIR_IN, - port, p_priv->inack_buffer, 1, cback->inack_callback); - - /* outcont endpoint */ - p_priv->outcont_urb = keyspan_setup_urb - (serial, d_details->outcont_endpoints[i], USB_DIR_OUT, - port, p_priv->outcont_buffer, 64, - cback->outcont_callback); - } } /* usa19 function doesn't require prescaler */ -static int keyspan_usa19_calc_baud(u32 baud_rate, u32 baudclk, u8 *rate_hi, +static int keyspan_usa19_calc_baud(struct usb_serial_port *port, + u32 baud_rate, u32 baudclk, u8 *rate_hi, u8 *rate_low, u8 *prescaler, int portnum) { u32 b16, /* baud rate times 16 (actual rate used internally) */ div, /* divisor */ cnt; /* inverse of divisor (programmed into 8051) */ - dbg("%s - %d.", __func__, baud_rate); + dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate); /* prevent divide by zero... */ b16 = baud_rate * 16L; @@ -1666,19 +1364,20 @@ static int keyspan_usa19_calc_baud(u32 baud_rate, u32 baudclk, u8 *rate_hi, if (rate_hi) *rate_hi = (u8) ((cnt >> 8) & 0xff); if (rate_low && rate_hi) - dbg("%s - %d %02x %02x.", + dev_dbg(&port->dev, "%s - %d %02x %02x.\n", __func__, baud_rate, *rate_hi, *rate_low); return KEYSPAN_BAUD_RATE_OK; } /* usa19hs function doesn't require prescaler */ -static int keyspan_usa19hs_calc_baud(u32 baud_rate, u32 baudclk, u8 *rate_hi, - u8 *rate_low, u8 *prescaler, int portnum) +static int keyspan_usa19hs_calc_baud(struct usb_serial_port *port, + u32 baud_rate, u32 baudclk, u8 *rate_hi, + u8 *rate_low, u8 *prescaler, int portnum) { u32 b16, /* baud rate times 16 (actual rate used internally) */ div; /* divisor */ - dbg("%s - %d.", __func__, baud_rate); + dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate); /* prevent divide by zero... */ b16 = baud_rate * 16L; @@ -1701,13 +1400,14 @@ static int keyspan_usa19hs_calc_baud(u32 baud_rate, u32 baudclk, u8 *rate_hi, *rate_hi = (u8) ((div >> 8) & 0xff); if (rate_low && rate_hi) - dbg("%s - %d %02x %02x.", + dev_dbg(&port->dev, "%s - %d %02x %02x.\n", __func__, baud_rate, *rate_hi, *rate_low); return KEYSPAN_BAUD_RATE_OK; } -static int keyspan_usa19w_calc_baud(u32 baud_rate, u32 baudclk, u8 *rate_hi, +static int keyspan_usa19w_calc_baud(struct usb_serial_port *port, + u32 baud_rate, u32 baudclk, u8 *rate_hi, u8 *rate_low, u8 *prescaler, int portnum) { u32 b16, /* baud rate times 16 (actual rate used internally) */ @@ -1719,7 +1419,7 @@ static int keyspan_usa19w_calc_baud(u32 baud_rate, u32 baudclk, u8 *rate_hi, u8 best_prescaler; int i; - dbg("%s - %d.", __func__, baud_rate); + dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate); /* prevent divide by zero */ b16 = baud_rate * 16L; @@ -1764,20 +1464,21 @@ static int keyspan_usa19w_calc_baud(u32 baud_rate, u32 baudclk, u8 *rate_hi, *rate_hi = (u8) ((div >> 8) & 0xff); if (prescaler) { *prescaler = best_prescaler; - /* dbg("%s - %d %d", __func__, *prescaler, div); */ + /* dev_dbg(&port->dev, "%s - %d %d\n", __func__, *prescaler, div); */ } return KEYSPAN_BAUD_RATE_OK; } /* USA-28 supports different maximum baud rates on each port */ -static int keyspan_usa28_calc_baud(u32 baud_rate, u32 baudclk, u8 *rate_hi, - u8 *rate_low, u8 *prescaler, int portnum) +static int keyspan_usa28_calc_baud(struct usb_serial_port *port, + u32 baud_rate, u32 baudclk, u8 *rate_hi, + u8 *rate_low, u8 *prescaler, int portnum) { u32 b16, /* baud rate times 16 (actual rate used internally) */ div, /* divisor */ cnt; /* inverse of divisor (programmed into 8051) */ - dbg("%s - %d.", __func__, baud_rate); + dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate); /* prevent divide by zero */ b16 = baud_rate * 16L; @@ -1810,7 +1511,7 @@ static int keyspan_usa28_calc_baud(u32 baud_rate, u32 baudclk, u8 *rate_hi, *rate_low = (u8) (cnt & 0xff); if (rate_hi) *rate_hi = (u8) ((cnt >> 8) & 0xff); - dbg("%s - %d OK.", __func__, baud_rate); + dev_dbg(&port->dev, "%s - %d OK.\n", __func__, baud_rate); return KEYSPAN_BAUD_RATE_OK; } @@ -1822,34 +1523,32 @@ static int keyspan_usa26_send_setup(struct usb_serial *serial, struct keyspan_serial_private *s_priv; struct keyspan_port_private *p_priv; const struct keyspan_device_details *d_details; - int outcont_urb; struct urb *this_urb; int device_port, err; - dbg("%s reset=%d", __func__, reset_port); + dev_dbg(&port->dev, "%s reset=%d\n", __func__, reset_port); s_priv = usb_get_serial_data(serial); p_priv = usb_get_serial_port_data(port); d_details = s_priv->device_details; - device_port = port->number - port->serial->minor; + device_port = port->port_number; - outcont_urb = d_details->outcont_endpoints[port->number]; this_urb = p_priv->outcont_urb; - dbg("%s - endpoint %d", __func__, usb_pipeendpoint(this_urb->pipe)); - /* Make sure we have an urb then send the message */ if (this_urb == NULL) { - dbg("%s - oops no urb.", __func__); + dev_dbg(&port->dev, "%s - oops no urb.\n", __func__); return -1; } + dev_dbg(&port->dev, "%s - endpoint %d\n", __func__, usb_pipeendpoint(this_urb->pipe)); + /* Save reset port val for resend. Don't overwrite resend for open/close condition. */ if ((reset_port + 1) > p_priv->resend_cont) p_priv->resend_cont = reset_port + 1; if (this_urb->status == -EINPROGRESS) { - /* dbg("%s - already writing", __func__); */ + /* dev_dbg(&port->dev, "%s - already writing\n", __func__); */ mdelay(5); return -1; } @@ -1860,11 +1559,11 @@ static int keyspan_usa26_send_setup(struct usb_serial *serial, if (p_priv->old_baud != p_priv->baud) { p_priv->old_baud = p_priv->baud; msg.setClocking = 0xff; - if (d_details->calculate_baud_rate - (p_priv->baud, d_details->baudclk, &msg.baudHi, - &msg.baudLo, &msg.prescaler, device_port) == KEYSPAN_INVALID_BAUD_RATE) { - dbg("%s - Invalid baud rate %d requested, using 9600.", - __func__, p_priv->baud); + if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk, + &msg.baudHi, &msg.baudLo, &msg.prescaler, + device_port) == KEYSPAN_INVALID_BAUD_RATE) { + dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n", + __func__, p_priv->baud); msg.baudLo = 0; msg.baudHi = 125; /* Values for 9600 baud */ msg.prescaler = 10; @@ -1872,7 +1571,7 @@ static int keyspan_usa26_send_setup(struct usb_serial *serial, msg.setPrescaler = 0xff; } - msg.lcr = (p_priv->cflag & CSTOPB)? STOPBITS_678_2: STOPBITS_5678_1; + msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1; switch (p_priv->cflag & CSIZE) { case CS5: msg.lcr |= USA_DATABITS_5; @@ -1889,7 +1588,7 @@ static int keyspan_usa26_send_setup(struct usb_serial *serial, } if (p_priv->cflag & PARENB) { /* note USA_PARITY_NONE == 0 */ - msg.lcr |= (p_priv->cflag & PARODD)? + msg.lcr |= (p_priv->cflag & PARODD) ? USA_PARITY_ODD : USA_PARITY_EVEN; } msg.setLcr = 0xff; @@ -1956,18 +1655,9 @@ static int keyspan_usa26_send_setup(struct usb_serial *serial, /* send the data out the device on control endpoint */ this_urb->transfer_buffer_length = sizeof(msg); - this_urb->dev = serial->dev; err = usb_submit_urb(this_urb, GFP_ATOMIC); if (err != 0) - dbg("%s - usb_submit_urb(setup) failed (%d)", __func__, err); -#if 0 - else { - dbg("%s - usb_submit_urb(%d) OK %d bytes (end %d)", __func__ - outcont_urb, this_urb->transfer_buffer_length, - usb_pipeendpoint(this_urb->pipe)); - } -#endif - + dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err); return 0; } @@ -1982,17 +1672,15 @@ static int keyspan_usa28_send_setup(struct usb_serial *serial, struct urb *this_urb; int device_port, err; - dbg("%s", __func__); - s_priv = usb_get_serial_data(serial); p_priv = usb_get_serial_port_data(port); d_details = s_priv->device_details; - device_port = port->number - port->serial->minor; + device_port = port->port_number; /* only do something if we have a bulk out endpoint */ this_urb = p_priv->outcont_urb; if (this_urb == NULL) { - dbg("%s - oops no urb.", __func__); + dev_dbg(&port->dev, "%s - oops no urb.\n", __func__); return -1; } @@ -2001,7 +1689,7 @@ static int keyspan_usa28_send_setup(struct usb_serial *serial, if ((reset_port + 1) > p_priv->resend_cont) p_priv->resend_cont = reset_port + 1; if (this_urb->status == -EINPROGRESS) { - dbg("%s already writing", __func__); + dev_dbg(&port->dev, "%s already writing\n", __func__); mdelay(5); return -1; } @@ -2009,9 +1697,10 @@ static int keyspan_usa28_send_setup(struct usb_serial *serial, memset(&msg, 0, sizeof(struct keyspan_usa28_portControlMessage)); msg.setBaudRate = 1; - if (d_details->calculate_baud_rate(p_priv->baud, d_details->baudclk, - &msg.baudHi, &msg.baudLo, NULL, device_port) == KEYSPAN_INVALID_BAUD_RATE) { - dbg("%s - Invalid baud rate requested %d.", + if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk, + &msg.baudHi, &msg.baudLo, NULL, + device_port) == KEYSPAN_INVALID_BAUD_RATE) { + dev_dbg(&port->dev, "%s - Invalid baud rate requested %d.\n", __func__, p_priv->baud); msg.baudLo = 0xff; msg.baudHi = 0xb2; /* Values for 9600 baud */ @@ -2084,16 +1773,9 @@ static int keyspan_usa28_send_setup(struct usb_serial *serial, /* send the data out the device on control endpoint */ this_urb->transfer_buffer_length = sizeof(msg); - this_urb->dev = serial->dev; err = usb_submit_urb(this_urb, GFP_ATOMIC); if (err != 0) - dbg("%s - usb_submit_urb(setup) failed", __func__); -#if 0 - else { - dbg("%s - usb_submit_urb(setup) OK %d bytes", __func__, - this_urb->transfer_buffer_length); - } -#endif + dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed\n", __func__); return 0; } @@ -2110,8 +1792,6 @@ static int keyspan_usa49_send_setup(struct usb_serial *serial, struct urb *this_urb; int err, device_port; - dbg("%s", __func__); - s_priv = usb_get_serial_data(serial); p_priv = usb_get_serial_port_data(port); d_details = s_priv->device_details; @@ -2119,43 +1799,41 @@ static int keyspan_usa49_send_setup(struct usb_serial *serial, this_urb = s_priv->glocont_urb; /* Work out which port within the device is being setup */ - device_port = port->number - port->serial->minor; - - dbg("%s - endpoint %d port %d (%d)", - __func__, usb_pipeendpoint(this_urb->pipe), - port->number, device_port); + device_port = port->port_number; - /* Make sure we have an urb then send the message */ + /* Make sure we have an urb then send the message */ if (this_urb == NULL) { - dbg("%s - oops no urb for port %d.", __func__, port->number); + dev_dbg(&port->dev, "%s - oops no urb for port.\n", __func__); return -1; } + dev_dbg(&port->dev, "%s - endpoint %d (%d)\n", + __func__, usb_pipeendpoint(this_urb->pipe), device_port); + /* Save reset port val for resend. Don't overwrite resend for open/close condition. */ if ((reset_port + 1) > p_priv->resend_cont) p_priv->resend_cont = reset_port + 1; if (this_urb->status == -EINPROGRESS) { - /* dbg("%s - already writing", __func__); */ + /* dev_dbg(&port->dev, "%s - already writing\n", __func__); */ mdelay(5); return -1; } memset(&msg, 0, sizeof(struct keyspan_usa49_portControlMessage)); - /*msg.portNumber = port->number;*/ msg.portNumber = device_port; /* Only set baud rate if it's changed */ if (p_priv->old_baud != p_priv->baud) { p_priv->old_baud = p_priv->baud; msg.setClocking = 0xff; - if (d_details->calculate_baud_rate - (p_priv->baud, d_details->baudclk, &msg.baudHi, - &msg.baudLo, &msg.prescaler, device_port) == KEYSPAN_INVALID_BAUD_RATE) { - dbg("%s - Invalid baud rate %d requested, using 9600.", - __func__, p_priv->baud); + if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk, + &msg.baudHi, &msg.baudLo, &msg.prescaler, + device_port) == KEYSPAN_INVALID_BAUD_RATE) { + dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n", + __func__, p_priv->baud); msg.baudLo = 0; msg.baudHi = 125; /* Values for 9600 baud */ msg.prescaler = 10; @@ -2163,7 +1841,7 @@ static int keyspan_usa49_send_setup(struct usb_serial *serial, /* msg.setPrescaler = 0xff; */ } - msg.lcr = (p_priv->cflag & CSTOPB)? STOPBITS_678_2: STOPBITS_5678_1; + msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1; switch (p_priv->cflag & CSIZE) { case CS5: msg.lcr |= USA_DATABITS_5; @@ -2180,7 +1858,7 @@ static int keyspan_usa49_send_setup(struct usb_serial *serial, } if (p_priv->cflag & PARENB) { /* note USA_PARITY_NONE == 0 */ - msg.lcr |= (p_priv->cflag & PARODD)? + msg.lcr |= (p_priv->cflag & PARODD) ? USA_PARITY_ODD : USA_PARITY_EVEN; } msg.setLcr = 0xff; @@ -2271,19 +1949,10 @@ static int keyspan_usa49_send_setup(struct usb_serial *serial, /* send the data out the device on control endpoint */ this_urb->transfer_buffer_length = sizeof(msg); - - this_urb->dev = serial->dev; } err = usb_submit_urb(this_urb, GFP_ATOMIC); if (err != 0) - dbg("%s - usb_submit_urb(setup) failed (%d)", __func__, err); -#if 0 - else { - dbg("%s - usb_submit_urb(%d) OK %d bytes (end %d)", __func__, - outcont_urb, this_urb->transfer_buffer_length, - usb_pipeendpoint(this_urb->pipe)); - } -#endif + dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err); return 0; } @@ -2300,8 +1969,6 @@ static int keyspan_usa90_send_setup(struct usb_serial *serial, int err; u8 prescaler; - dbg("%s", __func__); - s_priv = usb_get_serial_data(serial); p_priv = usb_get_serial_port_data(port); d_details = s_priv->device_details; @@ -2309,7 +1976,7 @@ static int keyspan_usa90_send_setup(struct usb_serial *serial, /* only do something if we have a bulk out endpoint */ this_urb = p_priv->outcont_urb; if (this_urb == NULL) { - dbg("%s - oops no urb.", __func__); + dev_dbg(&port->dev, "%s - oops no urb.\n", __func__); return -1; } @@ -2318,7 +1985,7 @@ static int keyspan_usa90_send_setup(struct usb_serial *serial, if ((reset_port + 1) > p_priv->resend_cont) p_priv->resend_cont = reset_port + 1; if (this_urb->status == -EINPROGRESS) { - dbg("%s already writing", __func__); + dev_dbg(&port->dev, "%s already writing\n", __func__); mdelay(5); return -1; } @@ -2329,13 +1996,12 @@ static int keyspan_usa90_send_setup(struct usb_serial *serial, if (p_priv->old_baud != p_priv->baud) { p_priv->old_baud = p_priv->baud; msg.setClocking = 0x01; - if (d_details->calculate_baud_rate - (p_priv->baud, d_details->baudclk, &msg.baudHi, - &msg.baudLo, &prescaler, 0) == KEYSPAN_INVALID_BAUD_RATE) { - dbg("%s - Invalid baud rate %d requested, using 9600.", - __func__, p_priv->baud); + if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk, + &msg.baudHi, &msg.baudLo, &prescaler, 0) == KEYSPAN_INVALID_BAUD_RATE) { + dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n", + __func__, p_priv->baud); p_priv->baud = 9600; - d_details->calculate_baud_rate(p_priv->baud, d_details->baudclk, + d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk, &msg.baudHi, &msg.baudLo, &prescaler, 0); } msg.setRxMode = 1; @@ -2351,7 +2017,7 @@ static int keyspan_usa90_send_setup(struct usb_serial *serial, msg.txMode = TXMODE_BYHAND; } - msg.lcr = (p_priv->cflag & CSTOPB)? STOPBITS_678_2: STOPBITS_5678_1; + msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1; switch (p_priv->cflag & CSIZE) { case CS5: msg.lcr |= USA_DATABITS_5; @@ -2368,7 +2034,7 @@ static int keyspan_usa90_send_setup(struct usb_serial *serial, } if (p_priv->cflag & PARENB) { /* note USA_PARITY_NONE == 0 */ - msg.lcr |= (p_priv->cflag & PARODD)? + msg.lcr |= (p_priv->cflag & PARODD) ? USA_PARITY_ODD : USA_PARITY_EVEN; } if (p_priv->old_cflag != p_priv->cflag) { @@ -2415,10 +2081,9 @@ static int keyspan_usa90_send_setup(struct usb_serial *serial, /* send the data out the device on control endpoint */ this_urb->transfer_buffer_length = sizeof(msg); - this_urb->dev = serial->dev; err = usb_submit_urb(this_urb, GFP_ATOMIC); if (err != 0) - dbg("%s - usb_submit_urb(setup) failed (%d)", __func__, err); + dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err); return 0; } @@ -2433,8 +2098,6 @@ static int keyspan_usa67_send_setup(struct usb_serial *serial, struct urb *this_urb; int err, device_port; - dbg("%s", __func__); - s_priv = usb_get_serial_data(serial); p_priv = usb_get_serial_port_data(port); d_details = s_priv->device_details; @@ -2442,12 +2105,11 @@ static int keyspan_usa67_send_setup(struct usb_serial *serial, this_urb = s_priv->glocont_urb; /* Work out which port within the device is being setup */ - device_port = port->number - port->serial->minor; + device_port = port->port_number; /* Make sure we have an urb then send the message */ if (this_urb == NULL) { - dbg("%s - oops no urb for port %d.", __func__, - port->number); + dev_dbg(&port->dev, "%s - oops no urb for port.\n", __func__); return -1; } @@ -2456,7 +2118,7 @@ static int keyspan_usa67_send_setup(struct usb_serial *serial, if ((reset_port + 1) > p_priv->resend_cont) p_priv->resend_cont = reset_port + 1; if (this_urb->status == -EINPROGRESS) { - /* dbg("%s - already writing", __func__); */ + /* dev_dbg(&port->dev, "%s - already writing\n", __func__); */ mdelay(5); return -1; } @@ -2469,11 +2131,11 @@ static int keyspan_usa67_send_setup(struct usb_serial *serial, if (p_priv->old_baud != p_priv->baud) { p_priv->old_baud = p_priv->baud; msg.setClocking = 0xff; - if (d_details->calculate_baud_rate - (p_priv->baud, d_details->baudclk, &msg.baudHi, - &msg.baudLo, &msg.prescaler, device_port) == KEYSPAN_INVALID_BAUD_RATE) { - dbg("%s - Invalid baud rate %d requested, using 9600.", - __func__, p_priv->baud); + if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk, + &msg.baudHi, &msg.baudLo, &msg.prescaler, + device_port) == KEYSPAN_INVALID_BAUD_RATE) { + dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n", + __func__, p_priv->baud); msg.baudLo = 0; msg.baudHi = 125; /* Values for 9600 baud */ msg.prescaler = 10; @@ -2498,7 +2160,7 @@ static int keyspan_usa67_send_setup(struct usb_serial *serial, } if (p_priv->cflag & PARENB) { /* note USA_PARITY_NONE == 0 */ - msg.lcr |= (p_priv->cflag & PARODD)? + msg.lcr |= (p_priv->cflag & PARODD) ? USA_PARITY_ODD : USA_PARITY_EVEN; } msg.setLcr = 0xff; @@ -2561,12 +2223,10 @@ static int keyspan_usa67_send_setup(struct usb_serial *serial, /* send the data out the device on control endpoint */ this_urb->transfer_buffer_length = sizeof(msg); - this_urb->dev = serial->dev; err = usb_submit_urb(this_urb, GFP_ATOMIC); if (err != 0) - dbg("%s - usb_submit_urb(setup) failed (%d)", __func__, - err); + dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err); return 0; } @@ -2576,8 +2236,6 @@ static void keyspan_send_setup(struct usb_serial_port *port, int reset_port) struct keyspan_serial_private *s_priv; const struct keyspan_device_details *d_details; - dbg("%s", __func__); - s_priv = usb_get_serial_data(serial); d_details = s_priv->device_details; @@ -2606,13 +2264,9 @@ static void keyspan_send_setup(struct usb_serial_port *port, int reset_port) static int keyspan_startup(struct usb_serial *serial) { int i, err; - struct usb_serial_port *port; struct keyspan_serial_private *s_priv; - struct keyspan_port_private *p_priv; const struct keyspan_device_details *d_details; - dbg("%s", __func__); - for (i = 0; (d_details = keyspan_devices[i]) != NULL; ++i) if (d_details->product_id == le16_to_cpu(serial->dev->descriptor.idProduct)) @@ -2620,114 +2274,216 @@ static int keyspan_startup(struct usb_serial *serial) if (d_details == NULL) { dev_err(&serial->dev->dev, "%s - unknown product id %x\n", __func__, le16_to_cpu(serial->dev->descriptor.idProduct)); - return 1; + return -ENODEV; } /* Setup private data for serial driver */ s_priv = kzalloc(sizeof(struct keyspan_serial_private), GFP_KERNEL); - if (!s_priv) { - dbg("%s - kmalloc for keyspan_serial_private failed.", - __func__); + if (!s_priv) return -ENOMEM; - } + + s_priv->instat_buf = kzalloc(INSTAT_BUFLEN, GFP_KERNEL); + if (!s_priv->instat_buf) + goto err_instat_buf; + + s_priv->indat_buf = kzalloc(INDAT49W_BUFLEN, GFP_KERNEL); + if (!s_priv->indat_buf) + goto err_indat_buf; + + s_priv->glocont_buf = kzalloc(GLOCONT_BUFLEN, GFP_KERNEL); + if (!s_priv->glocont_buf) + goto err_glocont_buf; + + s_priv->ctrl_buf = kzalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL); + if (!s_priv->ctrl_buf) + goto err_ctrl_buf; s_priv->device_details = d_details; usb_set_serial_data(serial, s_priv); - /* Now setup per port private data */ - for (i = 0; i < serial->num_ports; i++) { - port = serial->port[i]; - p_priv = kzalloc(sizeof(struct keyspan_port_private), - GFP_KERNEL); - if (!p_priv) { - dbg("%s - kmalloc for keyspan_port_private (%d) failed!.", __func__, i); - return 1; - } - p_priv->device_details = d_details; - usb_set_serial_port_data(port, p_priv); - } - keyspan_setup_urbs(serial); if (s_priv->instat_urb != NULL) { - s_priv->instat_urb->dev = serial->dev; err = usb_submit_urb(s_priv->instat_urb, GFP_KERNEL); if (err != 0) - dbg("%s - submit instat urb failed %d", __func__, - err); + dev_dbg(&serial->dev->dev, "%s - submit instat urb failed %d\n", __func__, err); } if (s_priv->indat_urb != NULL) { - s_priv->indat_urb->dev = serial->dev; err = usb_submit_urb(s_priv->indat_urb, GFP_KERNEL); if (err != 0) - dbg("%s - submit indat urb failed %d", __func__, - err); + dev_dbg(&serial->dev->dev, "%s - submit indat urb failed %d\n", __func__, err); } return 0; + +err_ctrl_buf: + kfree(s_priv->glocont_buf); +err_glocont_buf: + kfree(s_priv->indat_buf); +err_indat_buf: + kfree(s_priv->instat_buf); +err_instat_buf: + kfree(s_priv); + + return -ENOMEM; } static void keyspan_disconnect(struct usb_serial *serial) { - int i, j; - struct usb_serial_port *port; - struct keyspan_serial_private *s_priv; - struct keyspan_port_private *p_priv; - - dbg("%s", __func__); + struct keyspan_serial_private *s_priv; s_priv = usb_get_serial_data(serial); - /* Stop reading/writing urbs */ stop_urb(s_priv->instat_urb); stop_urb(s_priv->glocont_urb); stop_urb(s_priv->indat_urb); - for (i = 0; i < serial->num_ports; ++i) { - port = serial->port[i]; - p_priv = usb_get_serial_port_data(port); - stop_urb(p_priv->inack_urb); - stop_urb(p_priv->outcont_urb); - for (j = 0; j < 2; j++) { - stop_urb(p_priv->in_urbs[j]); - stop_urb(p_priv->out_urbs[j]); - } - } +} + +static void keyspan_release(struct usb_serial *serial) +{ + struct keyspan_serial_private *s_priv; + + s_priv = usb_get_serial_data(serial); - /* Now free them */ usb_free_urb(s_priv->instat_urb); usb_free_urb(s_priv->indat_urb); usb_free_urb(s_priv->glocont_urb); - for (i = 0; i < serial->num_ports; ++i) { - port = serial->port[i]; - p_priv = usb_get_serial_port_data(port); - usb_free_urb(p_priv->inack_urb); - usb_free_urb(p_priv->outcont_urb); - for (j = 0; j < 2; j++) { - usb_free_urb(p_priv->in_urbs[j]); - usb_free_urb(p_priv->out_urbs[j]); - } - } + + kfree(s_priv->ctrl_buf); + kfree(s_priv->glocont_buf); + kfree(s_priv->indat_buf); + kfree(s_priv->instat_buf); + + kfree(s_priv); } -static void keyspan_release(struct usb_serial *serial) +static int keyspan_port_probe(struct usb_serial_port *port) { - int i; - struct usb_serial_port *port; - struct keyspan_serial_private *s_priv; - - dbg("%s", __func__); + struct usb_serial *serial = port->serial; + struct keyspan_serial_private *s_priv; + struct keyspan_port_private *p_priv; + const struct keyspan_device_details *d_details; + struct callbacks *cback; + int endp; + int port_num; + int i; s_priv = usb_get_serial_data(serial); + d_details = s_priv->device_details; - /* dbg("Freeing serial->private."); */ - kfree(s_priv); + p_priv = kzalloc(sizeof(*p_priv), GFP_KERNEL); + if (!p_priv) + return -ENOMEM; - /* dbg("Freeing port->private."); */ - /* Now free per port private data */ - for (i = 0; i < serial->num_ports; i++) { - port = serial->port[i]; - kfree(usb_get_serial_port_data(port)); + for (i = 0; i < ARRAY_SIZE(p_priv->in_buffer); ++i) { + p_priv->in_buffer[i] = kzalloc(IN_BUFLEN, GFP_KERNEL); + if (!p_priv->in_buffer[i]) + goto err_in_buffer; + } + + for (i = 0; i < ARRAY_SIZE(p_priv->out_buffer); ++i) { + p_priv->out_buffer[i] = kzalloc(OUT_BUFLEN, GFP_KERNEL); + if (!p_priv->out_buffer[i]) + goto err_out_buffer; + } + + p_priv->inack_buffer = kzalloc(INACK_BUFLEN, GFP_KERNEL); + if (!p_priv->inack_buffer) + goto err_inack_buffer; + + p_priv->outcont_buffer = kzalloc(OUTCONT_BUFLEN, GFP_KERNEL); + if (!p_priv->outcont_buffer) + goto err_outcont_buffer; + + p_priv->device_details = d_details; + + /* Setup values for the various callback routines */ + cback = &keyspan_callbacks[d_details->msg_format]; + + port_num = port->port_number; + + /* Do indat endpoints first, once for each flip */ + endp = d_details->indat_endpoints[port_num]; + for (i = 0; i <= d_details->indat_endp_flip; ++i, ++endp) { + p_priv->in_urbs[i] = keyspan_setup_urb(serial, endp, + USB_DIR_IN, port, + p_priv->in_buffer[i], + IN_BUFLEN, + cback->indat_callback); + } + /* outdat endpoints also have flip */ + endp = d_details->outdat_endpoints[port_num]; + for (i = 0; i <= d_details->outdat_endp_flip; ++i, ++endp) { + p_priv->out_urbs[i] = keyspan_setup_urb(serial, endp, + USB_DIR_OUT, port, + p_priv->out_buffer[i], + OUT_BUFLEN, + cback->outdat_callback); + } + /* inack endpoint */ + p_priv->inack_urb = keyspan_setup_urb(serial, + d_details->inack_endpoints[port_num], + USB_DIR_IN, port, + p_priv->inack_buffer, + INACK_BUFLEN, + cback->inack_callback); + /* outcont endpoint */ + p_priv->outcont_urb = keyspan_setup_urb(serial, + d_details->outcont_endpoints[port_num], + USB_DIR_OUT, port, + p_priv->outcont_buffer, + OUTCONT_BUFLEN, + cback->outcont_callback); + + usb_set_serial_port_data(port, p_priv); + + return 0; + +err_outcont_buffer: + kfree(p_priv->inack_buffer); +err_inack_buffer: + for (i = 0; i < ARRAY_SIZE(p_priv->out_buffer); ++i) + kfree(p_priv->out_buffer[i]); +err_out_buffer: + for (i = 0; i < ARRAY_SIZE(p_priv->in_buffer); ++i) + kfree(p_priv->in_buffer[i]); +err_in_buffer: + kfree(p_priv); + + return -ENOMEM; +} + +static int keyspan_port_remove(struct usb_serial_port *port) +{ + struct keyspan_port_private *p_priv; + int i; + + p_priv = usb_get_serial_port_data(port); + + stop_urb(p_priv->inack_urb); + stop_urb(p_priv->outcont_urb); + for (i = 0; i < 2; i++) { + stop_urb(p_priv->in_urbs[i]); + stop_urb(p_priv->out_urbs[i]); + } + + usb_free_urb(p_priv->inack_urb); + usb_free_urb(p_priv->outcont_urb); + for (i = 0; i < 2; i++) { + usb_free_urb(p_priv->in_urbs[i]); + usb_free_urb(p_priv->out_urbs[i]); } + + kfree(p_priv->outcont_buffer); + kfree(p_priv->inack_buffer); + for (i = 0; i < ARRAY_SIZE(p_priv->out_buffer); ++i) + kfree(p_priv->out_buffer[i]); + for (i = 0; i < ARRAY_SIZE(p_priv->in_buffer); ++i) + kfree(p_priv->in_buffer[i]); + + kfree(p_priv); + + return 0; } MODULE_AUTHOR(DRIVER_AUTHOR); @@ -2746,7 +2502,3 @@ MODULE_FIRMWARE("keyspan/usa18x.fw"); MODULE_FIRMWARE("keyspan/usa19w.fw"); MODULE_FIRMWARE("keyspan/usa49w.fw"); MODULE_FIRMWARE("keyspan/usa49wlc.fw"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); - diff --git a/drivers/usb/serial/keyspan.h b/drivers/usb/serial/keyspan.h index 2d8baf6ac47..0273dda303a 100644 --- a/drivers/usb/serial/keyspan.h +++ b/drivers/usb/serial/keyspan.h @@ -42,6 +42,8 @@ static void keyspan_dtr_rts (struct usb_serial_port *port, int on); static int keyspan_startup (struct usb_serial *serial); static void keyspan_disconnect (struct usb_serial *serial); static void keyspan_release (struct usb_serial *serial); +static int keyspan_port_probe(struct usb_serial_port *port); +static int keyspan_port_remove(struct usb_serial_port *port); static int keyspan_write_room (struct tty_struct *tty); static int keyspan_write (struct tty_struct *tty, @@ -58,26 +60,29 @@ static void keyspan_set_termios (struct tty_struct *tty, struct ktermios *old); static void keyspan_break_ctl (struct tty_struct *tty, int break_state); -static int keyspan_tiocmget (struct tty_struct *tty, - struct file *file); +static int keyspan_tiocmget (struct tty_struct *tty); static int keyspan_tiocmset (struct tty_struct *tty, - struct file *file, unsigned int set, + unsigned int set, unsigned int clear); static int keyspan_fake_startup (struct usb_serial *serial); -static int keyspan_usa19_calc_baud (u32 baud_rate, u32 baudclk, +static int keyspan_usa19_calc_baud (struct usb_serial_port *port, + u32 baud_rate, u32 baudclk, u8 *rate_hi, u8 *rate_low, u8 *prescaler, int portnum); -static int keyspan_usa19w_calc_baud (u32 baud_rate, u32 baudclk, +static int keyspan_usa19w_calc_baud (struct usb_serial_port *port, + u32 baud_rate, u32 baudclk, u8 *rate_hi, u8 *rate_low, u8 *prescaler, int portnum); -static int keyspan_usa28_calc_baud (u32 baud_rate, u32 baudclk, +static int keyspan_usa28_calc_baud (struct usb_serial_port *port, + u32 baud_rate, u32 baudclk, u8 *rate_hi, u8 *rate_low, u8 *prescaler, int portnum); -static int keyspan_usa19hs_calc_baud (u32 baud_rate, u32 baudclk, +static int keyspan_usa19hs_calc_baud (struct usb_serial_port *port, + u32 baud_rate, u32 baudclk, u8 *rate_hi, u8 *rate_low, u8 *prescaler, int portnum); @@ -189,8 +194,9 @@ struct keyspan_device_details { /* Endpoint used for global control functions */ int glocont_endpoint; - int (*calculate_baud_rate) (u32 baud_rate, u32 baudclk, - u8 *rate_hi, u8 *rate_low, u8 *prescaler, int portnum); + int (*calculate_baud_rate) (struct usb_serial_port *port, + u32 baud_rate, u32 baudclk, + u8 *rate_hi, u8 *rate_low, u8 *prescaler, int portnum); u32 baudclk; }; @@ -488,14 +494,6 @@ static const struct usb_device_id keyspan_ids_combined[] = { MODULE_DEVICE_TABLE(usb, keyspan_ids_combined); -static struct usb_driver keyspan_driver = { - .name = "keyspan", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = keyspan_ids_combined, - .no_dynamic_id = 1, -}; - /* usb_device_id table for the pre-firmware download keyspan devices */ static const struct usb_device_id keyspan_pre_ids[] = { { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa18x_pre_product_id) }, @@ -571,6 +569,8 @@ static struct usb_serial_driver keyspan_1port_device = { .attach = keyspan_startup, .disconnect = keyspan_disconnect, .release = keyspan_release, + .port_probe = keyspan_port_probe, + .port_remove = keyspan_port_remove, }; static struct usb_serial_driver keyspan_2port_device = { @@ -593,6 +593,8 @@ static struct usb_serial_driver keyspan_2port_device = { .attach = keyspan_startup, .disconnect = keyspan_disconnect, .release = keyspan_release, + .port_probe = keyspan_port_probe, + .port_remove = keyspan_port_remove, }; static struct usb_serial_driver keyspan_4port_device = { @@ -615,6 +617,13 @@ static struct usb_serial_driver keyspan_4port_device = { .attach = keyspan_startup, .disconnect = keyspan_disconnect, .release = keyspan_release, + .port_probe = keyspan_port_probe, + .port_remove = keyspan_port_remove, +}; + +static struct usb_serial_driver * const serial_drivers[] = { + &keyspan_pre_device, &keyspan_1port_device, + &keyspan_2port_device, &keyspan_4port_device, NULL }; #endif diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c index a10dd5676cc..742d827f876 100644 --- a/drivers/usb/serial/keyspan_pda.c +++ b/drivers/usb/serial/keyspan_pda.c @@ -12,65 +12,11 @@ * * See Documentation/usb/usb-serial.txt for more information on using this * driver - * - * (09/07/2001) gkh - * cleaned up the Xircom support. Added ids for Entregra device which is - * the same as the Xircom device. Enabled the code to be compiled for - * either Xircom or Keyspan devices. - * - * (08/11/2001) Cristian M. Craciunescu - * support for Xircom PGSDB9 - * - * (05/31/2001) gkh - * switched from using spinlock to a semaphore, which fixes lots of - * problems. - * - * (04/08/2001) gb - * Identify version on module load. - * - * (11/01/2000) Adam J. Richter - * usb_device_id table support - * - * (10/05/2000) gkh - * Fixed bug with urb->dev not being set properly, now that the usb - * core needs it. - * - * (08/28/2000) gkh - * Added locks for SMP safeness. - * Fixed MOD_INC and MOD_DEC logic and the ability to open a port more - * than once. - * - * (07/20/2000) borchers - * - keyspan_pda_write no longer sleeps if it is called on interrupt time; - * PPP and the line discipline with stty echo on can call write on - * interrupt time and this would cause an oops if write slept - * - if keyspan_pda_write is in an interrupt, it will not call - * usb_control_msg (which sleeps) to query the room in the device - * buffer, it simply uses the current room value it has - * - if the urb is busy or if it is throttled keyspan_pda_write just - * returns 0, rather than sleeping to wait for this to change; the - * write_chan code in n_tty.c will sleep if needed before calling - * keyspan_pda_write again - * - if the device needs to be unthrottled, write now queues up the - * call to usb_control_msg (which sleeps) to unthrottle the device - * - the wakeups from keyspan_pda_write_bulk_callback are queued rather - * than done directly from the callback to avoid the race in write_chan - * - keyspan_pda_chars_in_buffer also indicates its buffer is full if the - * urb status is -EINPROGRESS, meaning it cannot write at the moment - * - * (07/19/2000) gkh - * Added module_init and module_exit functions to handle the fact that this - * driver is a loadable module now. - * - * (03/26/2000) gkh - * Split driver up into device specific pieces. - * */ #include <linux/kernel.h> #include <linux/errno.h> -#include <linux/init.h> #include <linux/slab.h> #include <linux/tty.h> #include <linux/tty_driver.h> @@ -78,13 +24,10 @@ #include <linux/module.h> #include <linux/spinlock.h> #include <linux/workqueue.h> -#include <linux/firmware.h> -#include <linux/ihex.h> #include <linux/uaccess.h> #include <linux/usb.h> #include <linux/usb/serial.h> - -static int debug; +#include <linux/usb/ezusb.h> /* make a simple define to handle if we are compiling keyspan_pda or xircom support */ #if defined(CONFIG_USB_SERIAL_KEYSPAN_PDA) || defined(CONFIG_USB_SERIAL_KEYSPAN_PDA_MODULE) @@ -98,10 +41,6 @@ static int debug; #undef XIRCOM #endif -/* - * Version Information - */ -#define DRIVER_VERSION "v1.1" #define DRIVER_AUTHOR "Brian Warner <warner@lothar.com>" #define DRIVER_DESC "USB Keyspan PDA Converter driver" @@ -139,14 +78,6 @@ static const struct usb_device_id id_table_combined[] = { MODULE_DEVICE_TABLE(usb, id_table_combined); -static struct usb_driver keyspan_pda_driver = { - .name = "keyspan_pda", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table_combined, - .no_dynamic_id = 1, -}; - static const struct usb_device_id id_table_std[] = { { USB_DEVICE(KEYSPAN_VENDOR_ID, KEYSPAN_PDA_ID) }, { } /* Terminating entry */ @@ -172,9 +103,8 @@ static void keyspan_pda_wakeup_write(struct work_struct *work) struct keyspan_pda_private *priv = container_of(work, struct keyspan_pda_private, wakeup_work); struct usb_serial_port *port = priv->port; - struct tty_struct *tty = tty_port_tty_get(&port->port); - tty_wakeup(tty); - tty_kref_put(tty); + + tty_port_tty_wakeup(&port->port); } static void keyspan_pda_request_unthrottle(struct work_struct *work) @@ -184,7 +114,6 @@ static void keyspan_pda_request_unthrottle(struct work_struct *work) struct usb_serial *serial = priv->serial; int result; - dbg(" request_unthrottle"); /* ask the device to tell us when the tx buffer becomes sufficiently empty */ result = usb_control_msg(serial->dev, @@ -198,15 +127,14 @@ static void keyspan_pda_request_unthrottle(struct work_struct *work) 0, 2000); if (result < 0) - dbg("%s - error %d from usb_control_msg", - __func__, result); + dev_dbg(&serial->dev->dev, "%s - error %d from usb_control_msg\n", + __func__, result); } static void keyspan_pda_rx_interrupt(struct urb *urb) { struct usb_serial_port *port = urb->context; - struct tty_struct *tty = tty_port_tty_get(&port->port); unsigned char *data = urb->transfer_buffer; int retval; int status = urb->status; @@ -221,28 +149,26 @@ static void keyspan_pda_rx_interrupt(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", - __func__, status); - goto out; + dev_dbg(&urb->dev->dev, "%s - urb shutting down with status: %d\n", __func__, status); + return; default: - dbg("%s - nonzero urb status received: %d", - __func__, status); + dev_dbg(&urb->dev->dev, "%s - nonzero urb status received: %d\n", __func__, status); goto exit; } /* see if the message is data or a status interrupt */ switch (data[0]) { case 0: - /* rest of message is rx data */ + /* rest of message is rx data */ if (urb->actual_length) { - tty_insert_flip_string(tty, data + 1, + tty_insert_flip_string(&port->port, data + 1, urb->actual_length - 1); - tty_flip_buffer_push(tty); + tty_flip_buffer_push(&port->port); } break; case 1: /* status interrupt */ - dbg(" rx int, d1=%d, d2=%d", data[1], data[2]); + dev_dbg(&port->dev, "rx int, d1=%d, d2=%d\n", data[1], data[2]); switch (data[1]) { case 1: /* modemline change */ break; @@ -263,10 +189,8 @@ exit: retval = usb_submit_urb(urb, GFP_ATOMIC); if (retval) dev_err(&port->dev, - "%s - usb_submit_urb failed with result %d", + "%s - usb_submit_urb failed with result %d\n", __func__, retval); -out: - tty_kref_put(tty); } @@ -279,7 +203,7 @@ static void keyspan_pda_rx_throttle(struct tty_struct *tty) send an XOFF, although it might make sense to foist that off upon the device too. */ struct usb_serial_port *port = tty->driver_data; - dbg("keyspan_pda_rx_throttle port %d", port->number); + usb_kill_urb(port->interrupt_in_urb); } @@ -288,10 +212,9 @@ static void keyspan_pda_rx_unthrottle(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; /* just restart the receive interrupt URB */ - dbg("keyspan_pda_rx_unthrottle port %d", port->number); - port->interrupt_in_urb->dev = port->serial->dev; + if (usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL)) - dbg(" usb_submit_urb(read urb) failed"); + dev_dbg(&port->dev, "usb_submit_urb(read urb) failed\n"); } @@ -370,8 +293,8 @@ static void keyspan_pda_break_ctl(struct tty_struct *tty, int break_state) USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT, value, 0, NULL, 0, 2000); if (result < 0) - dbg("%s - error %d from usb_control_msg", - __func__, result); + dev_dbg(&port->dev, "%s - error %d from usb_control_msg\n", + __func__, result); /* there is something funky about this.. the TCSBRK that 'cu' performs ought to translate into a break_ctl(-1),break_ctl(0) pair HZ/4 seconds apart, but it feels like the break sent isn't as long as it @@ -400,7 +323,7 @@ static void keyspan_pda_set_termios(struct tty_struct *tty, 7[EOMS]1: 10 bit, b0/b7 is parity 7[EOMS]2: 11 bit, b0/b7 is parity, extra bit always (mark?) - HW flow control is dictated by the tty->termios->c_cflags & CRTSCTS + HW flow control is dictated by the tty->termios.c_cflags & CRTSCTS bit. For now, just do baud. */ @@ -409,13 +332,13 @@ static void keyspan_pda_set_termios(struct tty_struct *tty, speed = keyspan_pda_setbaud(serial, speed); if (speed == 0) { - dbg("can't handle requested baud rate"); + dev_dbg(&port->dev, "can't handle requested baud rate\n"); /* It hasn't changed so.. */ speed = tty_termios_baud_rate(old_termios); } /* Only speed can change so copy the old h/w parameters then encode the new speed */ - tty_termios_copy_hw(tty->termios, old_termios); + tty_termios_copy_hw(&tty->termios, old_termios); tty_encode_baud_rate(tty, speed, speed); } @@ -457,7 +380,7 @@ static int keyspan_pda_set_modem_info(struct usb_serial *serial, return rc; } -static int keyspan_pda_tiocmget(struct tty_struct *tty, struct file *file) +static int keyspan_pda_tiocmget(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; struct usb_serial *serial = port->serial; @@ -478,7 +401,7 @@ static int keyspan_pda_tiocmget(struct tty_struct *tty, struct file *file) return value; } -static int keyspan_pda_tiocmset(struct tty_struct *tty, struct file *file, +static int keyspan_pda_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) { struct usb_serial_port *port = tty->driver_data; @@ -520,9 +443,8 @@ static int keyspan_pda_write(struct tty_struct *tty, select() or poll() too) until we receive that unthrottle interrupt. Block if we can't write anything at all, otherwise write as much as we can. */ - dbg("keyspan_pda_write(%d)", count); if (count == 0) { - dbg(" write request of 0 bytes"); + dev_dbg(&port->dev, "write request of 0 bytes\n"); return 0; } @@ -531,11 +453,11 @@ static int keyspan_pda_write(struct tty_struct *tty, the device is full (wait until it says there is room) */ spin_lock_bh(&port->lock); - if (port->write_urb_busy || priv->tx_throttled) { + if (!test_bit(0, &port->write_urbs_free) || priv->tx_throttled) { spin_unlock_bh(&port->lock); return 0; } - port->write_urb_busy = 1; + clear_bit(0, &port->write_urbs_free); spin_unlock_bh(&port->lock); /* At this point the URB is in our control, nobody else can submit it @@ -568,16 +490,16 @@ static int keyspan_pda_write(struct tty_struct *tty, 1, 2000); if (rc > 0) { - dbg(" roomquery says %d", *room); + dev_dbg(&port->dev, "roomquery says %d\n", *room); priv->tx_room = *room; } kfree(room); if (rc < 0) { - dbg(" roomquery failed"); + dev_dbg(&port->dev, "roomquery failed\n"); goto exit; } if (rc == 0) { - dbg(" roomquery returned 0 bytes"); + dev_dbg(&port->dev, "roomquery returned 0 bytes\n"); rc = -EIO; /* device didn't return any data */ goto exit; } @@ -597,10 +519,9 @@ static int keyspan_pda_write(struct tty_struct *tty, priv->tx_room -= count; - port->write_urb->dev = port->serial->dev; rc = usb_submit_urb(port->write_urb, GFP_ATOMIC); if (rc) { - dbg(" usb_submit_urb(write bulk) failed"); + dev_dbg(&port->dev, "usb_submit_urb(write bulk) failed\n"); goto exit; } } else { @@ -617,7 +538,7 @@ static int keyspan_pda_write(struct tty_struct *tty, rc = count; exit: if (rc < 0) - port->write_urb_busy = 0; + set_bit(0, &port->write_urbs_free); return rc; } @@ -627,7 +548,7 @@ static void keyspan_pda_write_bulk_callback(struct urb *urb) struct usb_serial_port *port = urb->context; struct keyspan_pda_private *priv; - port->write_urb_busy = 0; + set_bit(0, &port->write_urbs_free); priv = usb_get_serial_port_data(port); /* queue up a wakeup at scheduler time */ @@ -660,7 +581,7 @@ static int keyspan_pda_chars_in_buffer(struct tty_struct *tty) n_tty.c:normal_poll() ) that we're not writeable. */ spin_lock_irqsave(&port->lock, flags); - if (port->write_urb_busy || priv->tx_throttled) + if (!test_bit(0, &port->write_urbs_free) || priv->tx_throttled) ret = 256; spin_unlock_irqrestore(&port->lock, flags); return ret; @@ -671,28 +592,10 @@ static void keyspan_pda_dtr_rts(struct usb_serial_port *port, int on) { struct usb_serial *serial = port->serial; - if (serial->dev) { - if (on) - keyspan_pda_set_modem_info(serial, (1<<7) | (1<< 2)); - else - keyspan_pda_set_modem_info(serial, 0); - } -} - -static int keyspan_pda_carrier_raised(struct usb_serial_port *port) -{ - struct usb_serial *serial = port->serial; - unsigned char modembits; - - /* If we can read the modem status and the DCD is low then - carrier is not raised yet */ - if (keyspan_pda_get_modem_info(serial, &modembits) >= 0) { - if (!(modembits & (1>>6))) - return 0; - } - /* Carrier raised, or we failed (eg disconnected) so - progress accordingly */ - return 1; + if (on) + keyspan_pda_set_modem_info(serial, (1 << 7) | (1 << 2)); + else + keyspan_pda_set_modem_info(serial, 0); } @@ -719,11 +622,11 @@ static int keyspan_pda_open(struct tty_struct *tty, 1, 2000); if (rc < 0) { - dbg("%s - roomquery failed", __func__); + dev_dbg(&port->dev, "%s - roomquery failed\n", __func__); goto error; } if (rc == 0) { - dbg("%s - roomquery returned 0 bytes", __func__); + dev_dbg(&port->dev, "%s - roomquery returned 0 bytes\n", __func__); rc = -EIO; goto error; } @@ -732,10 +635,9 @@ static int keyspan_pda_open(struct tty_struct *tty, priv->tx_throttled = *room ? 0 : 1; /*Start reading from the device*/ - port->interrupt_in_urb->dev = serial->dev; rc = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); if (rc) { - dbg("%s - usb_submit_urb(read int) failed", __func__); + dev_dbg(&port->dev, "%s - usb_submit_urb(read int) failed\n", __func__); goto error; } error: @@ -744,13 +646,8 @@ error: } static void keyspan_pda_close(struct usb_serial_port *port) { - struct usb_serial *serial = port->serial; - - if (serial->dev) { - /* shutdown our bulk reads and writes */ - usb_kill_urb(port->write_urb); - usb_kill_urb(port->interrupt_in_urb); - } + usb_kill_urb(port->write_urb); + usb_kill_urb(port->interrupt_in_urb); } @@ -759,11 +656,9 @@ static int keyspan_pda_fake_startup(struct usb_serial *serial) { int response; const char *fw_name; - const struct ihex_binrec *record; - const struct firmware *fw; /* download the firmware here ... */ - response = ezusb_set_reset(serial, 1); + response = ezusb_fx1_set_reset(serial->dev, 1); if (0) { ; } #ifdef KEYSPAN @@ -780,30 +675,15 @@ static int keyspan_pda_fake_startup(struct usb_serial *serial) __func__); return -ENODEV; } - if (request_ihex_firmware(&fw, fw_name, &serial->dev->dev)) { + + if (ezusb_fx1_ihex_firmware_download(serial->dev, fw_name) < 0) { dev_err(&serial->dev->dev, "failed to load firmware \"%s\"\n", fw_name); return -ENOENT; } - record = (const struct ihex_binrec *)fw->data; - - while (record) { - response = ezusb_writememory(serial, be32_to_cpu(record->addr), - (unsigned char *)record->data, - be16_to_cpu(record->len), 0xa0); - if (response < 0) { - dev_err(&serial->dev->dev, "ezusb_writememory failed " - "for Keyspan PDA firmware (%d %04X %p %d)\n", - response, be32_to_cpu(record->addr), - record->data, be16_to_cpu(record->len)); - break; - } - record = ihex_next_binrec(record); - } - release_firmware(fw); - /* bring device out of reset. Renumeration will occur in a moment - and the new device will bind to the real driver */ - response = ezusb_set_reset(serial, 0); + + /* after downloading firmware Renumeration will occur in a + moment and the new device will bind to the real driver */ /* we want this device to fail to have a driver assigned to it. */ return 1; @@ -816,31 +696,33 @@ MODULE_FIRMWARE("keyspan_pda/keyspan_pda.fw"); MODULE_FIRMWARE("keyspan_pda/xircom_pgs.fw"); #endif -static int keyspan_pda_startup(struct usb_serial *serial) +static int keyspan_pda_port_probe(struct usb_serial_port *port) { struct keyspan_pda_private *priv; - /* allocate the private data structures for all ports. Well, for all - one ports. */ - priv = kmalloc(sizeof(struct keyspan_pda_private), GFP_KERNEL); if (!priv) - return 1; /* error */ - usb_set_serial_port_data(serial->port[0], priv); - init_waitqueue_head(&serial->port[0]->write_wait); + return -ENOMEM; + INIT_WORK(&priv->wakeup_work, keyspan_pda_wakeup_write); INIT_WORK(&priv->unthrottle_work, keyspan_pda_request_unthrottle); - priv->serial = serial; - priv->port = serial->port[0]; + priv->serial = port->serial; + priv->port = port; + + usb_set_serial_port_data(port, priv); + return 0; } -static void keyspan_pda_release(struct usb_serial *serial) +static int keyspan_pda_port_remove(struct usb_serial_port *port) { - dbg("%s", __func__); + struct keyspan_pda_private *priv; + + priv = usb_get_serial_port_data(port); + kfree(priv); - kfree(usb_get_serial_port_data(serial->port[0])); + return 0; } #ifdef KEYSPAN @@ -850,7 +732,6 @@ static struct usb_serial_driver keyspan_pda_fake_device = { .name = "keyspan_pda_pre", }, .description = "Keyspan PDA - (prerenumeration)", - .usb_driver = &keyspan_pda_driver, .id_table = id_table_fake, .num_ports = 1, .attach = keyspan_pda_fake_startup, @@ -864,7 +745,6 @@ static struct usb_serial_driver xircom_pgs_fake_device = { .name = "xircom_no_firm", }, .description = "Xircom / Entregra PGS - (prerenumeration)", - .usb_driver = &keyspan_pda_driver, .id_table = id_table_fake_xircom, .num_ports = 1, .attach = keyspan_pda_fake_startup, @@ -877,11 +757,9 @@ static struct usb_serial_driver keyspan_pda_device = { .name = "keyspan_pda", }, .description = "Keyspan PDA", - .usb_driver = &keyspan_pda_driver, .id_table = id_table_std, .num_ports = 1, .dtr_rts = keyspan_pda_dtr_rts, - .carrier_raised = keyspan_pda_carrier_raised, .open = keyspan_pda_open, .close = keyspan_pda_close, .write = keyspan_pda_write, @@ -895,70 +773,23 @@ static struct usb_serial_driver keyspan_pda_device = { .break_ctl = keyspan_pda_break_ctl, .tiocmget = keyspan_pda_tiocmget, .tiocmset = keyspan_pda_tiocmset, - .attach = keyspan_pda_startup, - .release = keyspan_pda_release, + .port_probe = keyspan_pda_port_probe, + .port_remove = keyspan_pda_port_remove, }; - -static int __init keyspan_pda_init(void) -{ - int retval; - retval = usb_serial_register(&keyspan_pda_device); - if (retval) - goto failed_pda_register; -#ifdef KEYSPAN - retval = usb_serial_register(&keyspan_pda_fake_device); - if (retval) - goto failed_pda_fake_register; -#endif -#ifdef XIRCOM - retval = usb_serial_register(&xircom_pgs_fake_device); - if (retval) - goto failed_xircom_register; -#endif - retval = usb_register(&keyspan_pda_driver); - if (retval) - goto failed_usb_register; - printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" - DRIVER_DESC "\n"); - return 0; -failed_usb_register: -#ifdef XIRCOM - usb_serial_deregister(&xircom_pgs_fake_device); -failed_xircom_register: -#endif /* XIRCOM */ -#ifdef KEYSPAN - usb_serial_deregister(&keyspan_pda_fake_device); -#endif -#ifdef KEYSPAN -failed_pda_fake_register: -#endif - usb_serial_deregister(&keyspan_pda_device); -failed_pda_register: - return retval; -} - - -static void __exit keyspan_pda_exit(void) -{ - usb_deregister(&keyspan_pda_driver); - usb_serial_deregister(&keyspan_pda_device); +static struct usb_serial_driver * const serial_drivers[] = { + &keyspan_pda_device, #ifdef KEYSPAN - usb_serial_deregister(&keyspan_pda_fake_device); + &keyspan_pda_fake_device, #endif #ifdef XIRCOM - usb_serial_deregister(&xircom_pgs_fake_device); + &xircom_pgs_fake_device, #endif -} - + NULL +}; -module_init(keyspan_pda_init); -module_exit(keyspan_pda_exit); +module_usb_serial_driver(serial_drivers, id_table_combined); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); - diff --git a/drivers/usb/serial/keyspan_usa26msg.h b/drivers/usb/serial/keyspan_usa26msg.h index 3808727db65..09e21e84fc4 100644 --- a/drivers/usb/serial/keyspan_usa26msg.h +++ b/drivers/usb/serial/keyspan_usa26msg.h @@ -62,7 +62,7 @@ or: (b) 0x80 bit set - indiates that the bytes following alternate data and + indicates that the bytes following alternate data and status bytes: STAT DATA STAT DATA STAT DATA STAT DATA ... diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c index e8a65ce45a2..d7440b7557a 100644 --- a/drivers/usb/serial/kl5kusb105.c +++ b/drivers/usb/serial/kl5kusb105.c @@ -37,7 +37,6 @@ #include <linux/kernel.h> #include <linux/errno.h> -#include <linux/init.h> #include <linux/slab.h> #include <linux/tty.h> #include <linux/tty_driver.h> @@ -49,12 +48,6 @@ #include <linux/usb/serial.h> #include "kl5kusb105.h" -static int debug; - -/* - * Version Information - */ -#define DRIVER_VERSION "v0.4" #define DRIVER_AUTHOR "Utz-Uwe Haus <haus@uuhaus.de>, Johan Hovold <jhovold@gmail.com>" #define DRIVER_DESC "KLSI KL5KUSB105 chipset USB->Serial Converter driver" @@ -62,14 +55,14 @@ static int debug; /* * Function prototypes */ -static int klsi_105_startup(struct usb_serial *serial); -static void klsi_105_release(struct usb_serial *serial); +static int klsi_105_port_probe(struct usb_serial_port *port); +static int klsi_105_port_remove(struct usb_serial_port *port); static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port); static void klsi_105_close(struct usb_serial_port *port); static void klsi_105_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old); -static int klsi_105_tiocmget(struct tty_struct *tty, struct file *file); -static int klsi_105_tiocmset(struct tty_struct *tty, struct file *file, +static int klsi_105_tiocmget(struct tty_struct *tty); +static int klsi_105_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear); static void klsi_105_process_read_urb(struct urb *urb); static int klsi_105_prepare_write_buffer(struct usb_serial_port *port, @@ -86,21 +79,12 @@ static const struct usb_device_id id_table[] = { MODULE_DEVICE_TABLE(usb, id_table); -static struct usb_driver kl5kusb105d_driver = { - .name = "kl5kusb105d", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, - .no_dynamic_id = 1, -}; - static struct usb_serial_driver kl5kusb105d_device = { .driver = { .owner = THIS_MODULE, .name = "kl5kusb105d", }, .description = "KL5KUSB105D / PalmConnect", - .usb_driver = &kl5kusb105d_driver, .id_table = id_table, .num_ports = 1, .bulk_out_size = 64, @@ -110,14 +94,18 @@ static struct usb_serial_driver kl5kusb105d_device = { /*.break_ctl = klsi_105_break_ctl,*/ .tiocmget = klsi_105_tiocmget, .tiocmset = klsi_105_tiocmset, - .attach = klsi_105_startup, - .release = klsi_105_release, + .port_probe = klsi_105_port_probe, + .port_remove = klsi_105_port_remove, .throttle = usb_serial_generic_throttle, .unthrottle = usb_serial_generic_unthrottle, .process_read_urb = klsi_105_process_read_urb, .prepare_write_buffer = klsi_105_prepare_write_buffer, }; +static struct usb_serial_driver * const serial_drivers[] = { + &kl5kusb105d_device, NULL +}; + struct klsi_105_port_settings { __u8 pktlen; /* always 5, it seems */ __u8 baudrate; @@ -193,11 +181,9 @@ static int klsi_105_get_line_state(struct usb_serial_port *port, dev_info(&port->serial->dev->dev, "sending SIO Poll request\n"); status_buf = kmalloc(KLSI_STATUSBUF_LEN, GFP_KERNEL); - if (!status_buf) { - dev_err(&port->dev, "%s - out of memory for status buffer.\n", - __func__); + if (!status_buf) return -ENOMEM; - } + status_buf[0] = 0xff; status_buf[1] = 0xff; rc = usb_control_msg(port->serial->dev, @@ -215,7 +201,7 @@ static int klsi_105_get_line_state(struct usb_serial_port *port, else { status = get_unaligned_le16(status_buf); - dev_info(&port->serial->dev->dev, "read status %x %x", + dev_info(&port->serial->dev->dev, "read status %x %x\n", status_buf[0], status_buf[1]); *line_state_p = klsi_105_status2linestate(status); @@ -230,60 +216,40 @@ static int klsi_105_get_line_state(struct usb_serial_port *port, * Driver's tty interface functions */ -static int klsi_105_startup(struct usb_serial *serial) +static int klsi_105_port_probe(struct usb_serial_port *port) { struct klsi_105_private *priv; - int i; - /* check if we support the product id (see keyspan.c) - * FIXME - */ + priv = kmalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; - /* allocate the private data structure */ - for (i = 0; i < serial->num_ports; i++) { - priv = kmalloc(sizeof(struct klsi_105_private), - GFP_KERNEL); - if (!priv) { - dbg("%skmalloc for klsi_105_private failed.", __func__); - i--; - goto err_cleanup; - } - /* set initial values for control structures */ - priv->cfg.pktlen = 5; - priv->cfg.baudrate = kl5kusb105a_sio_b9600; - priv->cfg.databits = kl5kusb105a_dtb_8; - priv->cfg.unknown1 = 0; - priv->cfg.unknown2 = 1; + /* set initial values for control structures */ + priv->cfg.pktlen = 5; + priv->cfg.baudrate = kl5kusb105a_sio_b9600; + priv->cfg.databits = kl5kusb105a_dtb_8; + priv->cfg.unknown1 = 0; + priv->cfg.unknown2 = 1; - priv->line_state = 0; + priv->line_state = 0; - usb_set_serial_port_data(serial->port[i], priv); + spin_lock_init(&priv->lock); - spin_lock_init(&priv->lock); + /* priv->termios is left uninitialized until port opening */ - /* priv->termios is left uninitialized until port opening */ - init_waitqueue_head(&serial->port[i]->write_wait); - } + usb_set_serial_port_data(port, priv); return 0; - -err_cleanup: - for (; i >= 0; i--) { - priv = usb_get_serial_port_data(serial->port[i]); - kfree(priv); - usb_set_serial_port_data(serial->port[i], NULL); - } - return -ENOMEM; } -static void klsi_105_release(struct usb_serial *serial) +static int klsi_105_port_remove(struct usb_serial_port *port) { - int i; + struct klsi_105_private *priv; - dbg("%s", __func__); + priv = usb_get_serial_port_data(port); + kfree(priv); - for (i = 0; i < serial->num_ports; ++i) - kfree(usb_get_serial_port_data(serial->port[i])); + return 0; } static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port) @@ -296,8 +262,6 @@ static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port) struct klsi_105_port_settings *cfg; unsigned long flags; - dbg("%s port %d", __func__, port->number); - /* Do a defined restart: * Set up sane default baud rate and send the 'READ_ON' * vendor command. @@ -306,11 +270,9 @@ static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port) * priv->line_state. */ cfg = kmalloc(sizeof(*cfg), GFP_KERNEL); - if (!cfg) { - dev_err(&port->dev, "%s - out of memory for config buffer.\n", - __func__); + if (!cfg) return -ENOMEM; - } + cfg->pktlen = 5; cfg->baudrate = kl5kusb105a_sio_b9600; cfg->databits = kl5kusb105a_dtb_8; @@ -320,12 +282,12 @@ static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port) /* set up termios structure */ spin_lock_irqsave(&priv->lock, flags); - priv->termios.c_iflag = tty->termios->c_iflag; - priv->termios.c_oflag = tty->termios->c_oflag; - priv->termios.c_cflag = tty->termios->c_cflag; - priv->termios.c_lflag = tty->termios->c_lflag; + priv->termios.c_iflag = tty->termios.c_iflag; + priv->termios.c_oflag = tty->termios.c_oflag; + priv->termios.c_cflag = tty->termios.c_cflag; + priv->termios.c_lflag = tty->termios.c_lflag; for (i = 0; i < NCCS; i++) - priv->termios.c_cc[i] = tty->termios->c_cc[i]; + priv->termios.c_cc[i] = tty->termios.c_cc[i]; priv->cfg.pktlen = cfg->pktlen; priv->cfg.baudrate = cfg->baudrate; priv->cfg.databits = cfg->databits; @@ -353,14 +315,14 @@ static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port) dev_err(&port->dev, "Enabling read failed (error = %d)\n", rc); retval = rc; } else - dbg("%s - enabled reading", __func__); + dev_dbg(&port->dev, "%s - enabled reading\n", __func__); rc = klsi_105_get_line_state(port, &line_state); if (rc >= 0) { spin_lock_irqsave(&priv->lock, flags); priv->line_state = line_state; spin_unlock_irqrestore(&priv->lock, flags); - dbg("%s - read line state 0x%lx", __func__, line_state); + dev_dbg(&port->dev, "%s - read line state 0x%lx\n", __func__, line_state); retval = 0; } else retval = rc; @@ -374,30 +336,20 @@ static void klsi_105_close(struct usb_serial_port *port) { int rc; - dbg("%s port %d", __func__, port->number); - - mutex_lock(&port->serial->disc_mutex); - if (!port->serial->disconnected) { - /* send READ_OFF */ - rc = usb_control_msg(port->serial->dev, - usb_sndctrlpipe(port->serial->dev, 0), - KL5KUSB105A_SIO_CONFIGURE, - USB_TYPE_VENDOR | USB_DIR_OUT, - KL5KUSB105A_SIO_CONFIGURE_READ_OFF, - 0, /* index */ - NULL, 0, - KLSI_TIMEOUT); - if (rc < 0) - dev_err(&port->dev, - "Disabling read failed (error = %d)\n", rc); - } - mutex_unlock(&port->serial->disc_mutex); + /* send READ_OFF */ + rc = usb_control_msg(port->serial->dev, + usb_sndctrlpipe(port->serial->dev, 0), + KL5KUSB105A_SIO_CONFIGURE, + USB_TYPE_VENDOR | USB_DIR_OUT, + KL5KUSB105A_SIO_CONFIGURE_READ_OFF, + 0, /* index */ + NULL, 0, + KLSI_TIMEOUT); + if (rc < 0) + dev_err(&port->dev, "failed to disable read: %d\n", rc); /* shutdown our bulk reads and writes */ usb_serial_generic_close(port); - - /* wgg - do I need this? I think so. */ - usb_kill_urb(port->interrupt_in_urb); } /* We need to write a complete 64-byte data block and encode the @@ -424,7 +376,6 @@ static void klsi_105_process_read_urb(struct urb *urb) { struct usb_serial_port *port = urb->context; unsigned char *data = urb->transfer_buffer; - struct tty_struct *tty; unsigned len; /* empty urbs seem to happen, we ignore them */ @@ -432,23 +383,18 @@ static void klsi_105_process_read_urb(struct urb *urb) return; if (urb->actual_length <= KLSI_HDR_LEN) { - dbg("%s - malformed packet", __func__); + dev_dbg(&port->dev, "%s - malformed packet\n", __func__); return; } - tty = tty_port_tty_get(&port->port); - if (!tty) - return; - len = get_unaligned_le16(data); if (len > urb->actual_length - KLSI_HDR_LEN) { - dbg("%s - packet length mismatch", __func__); + dev_dbg(&port->dev, "%s - packet length mismatch\n", __func__); len = urb->actual_length - KLSI_HDR_LEN; } - tty_insert_flip_string(tty, data + KLSI_HDR_LEN, len); - tty_flip_buffer_push(tty); - tty_kref_put(tty); + tty_insert_flip_string(&port->port, data + KLSI_HDR_LEN, len); + tty_flip_buffer_push(&port->port); } static void klsi_105_set_termios(struct tty_struct *tty, @@ -456,20 +402,18 @@ static void klsi_105_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { struct klsi_105_private *priv = usb_get_serial_port_data(port); - unsigned int iflag = tty->termios->c_iflag; + struct device *dev = &port->dev; + unsigned int iflag = tty->termios.c_iflag; unsigned int old_iflag = old_termios->c_iflag; - unsigned int cflag = tty->termios->c_cflag; + unsigned int cflag = tty->termios.c_cflag; unsigned int old_cflag = old_termios->c_cflag; struct klsi_105_port_settings *cfg; unsigned long flags; speed_t baud; cfg = kmalloc(sizeof(*cfg), GFP_KERNEL); - if (!cfg) { - dev_err(&port->dev, "%s - out of memory for config buffer.\n", - __func__); + if (!cfg) return; - } /* lock while we are modifying the settings */ spin_lock_irqsave(&priv->lock, flags); @@ -482,7 +426,7 @@ static void klsi_105_set_termios(struct tty_struct *tty, if ((cflag & CBAUD) != (old_cflag & CBAUD)) { /* reassert DTR and (maybe) RTS on transition from B0 */ if ((old_cflag & CBAUD) == B0) { - dbg("%s: baud was B0", __func__); + dev_dbg(dev, "%s: baud was B0\n", __func__); #if 0 priv->control_state |= TIOCM_DTR; /* don't set RTS if using hardware flow control */ @@ -520,14 +464,13 @@ static void klsi_105_set_termios(struct tty_struct *tty, priv->cfg.baudrate = kl5kusb105a_sio_b115200; break; default: - dbg("KLSI USB->Serial converter:" - " unsupported baudrate request, using default of 9600"); - priv->cfg.baudrate = kl5kusb105a_sio_b9600; + dev_dbg(dev, "unsupported baudrate, using 9600\n"); + priv->cfg.baudrate = kl5kusb105a_sio_b9600; baud = 9600; break; } if ((cflag & CBAUD) == B0) { - dbg("%s: baud is B0", __func__); + dev_dbg(dev, "%s: baud is B0\n", __func__); /* Drop RTS and DTR */ /* maybe this should be simulated by sending read * disable and read enable messages? @@ -544,11 +487,11 @@ static void klsi_105_set_termios(struct tty_struct *tty, /* set the number of data bits */ switch (cflag & CSIZE) { case CS5: - dbg("%s - 5 bits/byte not supported", __func__); + dev_dbg(dev, "%s - 5 bits/byte not supported\n", __func__); spin_unlock_irqrestore(&priv->lock, flags); goto err; case CS6: - dbg("%s - 6 bits/byte not supported", __func__); + dev_dbg(dev, "%s - 6 bits/byte not supported\n", __func__); spin_unlock_irqrestore(&priv->lock, flags); goto err; case CS7: @@ -558,8 +501,7 @@ static void klsi_105_set_termios(struct tty_struct *tty, priv->cfg.databits = kl5kusb105a_dtb_8; break; default: - dev_err(&port->dev, - "CSIZE was not CS5-CS8, using default of 8\n"); + dev_err(dev, "CSIZE was not CS5-CS8, using default of 8\n"); priv->cfg.databits = kl5kusb105a_dtb_8; break; } @@ -571,7 +513,7 @@ static void klsi_105_set_termios(struct tty_struct *tty, if ((cflag & (PARENB|PARODD)) != (old_cflag & (PARENB|PARODD)) || (cflag & CSTOPB) != (old_cflag & CSTOPB)) { /* Not currently supported */ - tty->termios->c_cflag &= ~(PARENB|PARODD|CSTOPB); + tty->termios.c_cflag &= ~(PARENB|PARODD|CSTOPB); #if 0 priv->last_lcr = 0; @@ -598,7 +540,7 @@ static void klsi_105_set_termios(struct tty_struct *tty, || (iflag & IXON) != (old_iflag & IXON) || (cflag & CRTSCTS) != (old_cflag & CRTSCTS)) { /* Not currently supported */ - tty->termios->c_cflag &= ~CRTSCTS; + tty->termios.c_cflag &= ~CRTSCTS; /* Drop DTR/RTS if no flow control otherwise assert */ #if 0 if ((iflag & IXOFF) || (iflag & IXON) || (cflag & CRTSCTS)) @@ -627,7 +569,7 @@ static void mct_u232_break_ctl(struct tty_struct *tty, int break_state) (struct mct_u232_private *)port->private; unsigned char lcr = priv->last_lcr; - dbg("%sstate=%d", __func__, break_state); + dev_dbg(&port->dev, "%s - state=%d\n", __func__, break_state); /* LOCKING */ if (break_state) @@ -637,14 +579,13 @@ static void mct_u232_break_ctl(struct tty_struct *tty, int break_state) } #endif -static int klsi_105_tiocmget(struct tty_struct *tty, struct file *file) +static int klsi_105_tiocmget(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; struct klsi_105_private *priv = usb_get_serial_port_data(port); unsigned long flags; int rc; unsigned long line_state; - dbg("%s - request, just guessing", __func__); rc = klsi_105_get_line_state(port, &line_state); if (rc < 0) { @@ -657,17 +598,15 @@ static int klsi_105_tiocmget(struct tty_struct *tty, struct file *file) spin_lock_irqsave(&priv->lock, flags); priv->line_state = line_state; spin_unlock_irqrestore(&priv->lock, flags); - dbg("%s - read line state 0x%lx", __func__, line_state); + dev_dbg(&port->dev, "%s - read line state 0x%lx\n", __func__, line_state); return (int)line_state; } -static int klsi_105_tiocmset(struct tty_struct *tty, struct file *file, +static int klsi_105_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) { int retval = -EINVAL; - dbg("%s", __func__); - /* if this ever gets implemented, it should be done something like this: struct usb_serial *serial = port->serial; struct klsi_105_private *priv = usb_get_serial_port_data(port); @@ -690,40 +629,8 @@ static int klsi_105_tiocmset(struct tty_struct *tty, struct file *file, return retval; } - -static int __init klsi_105_init(void) -{ - int retval; - retval = usb_serial_register(&kl5kusb105d_device); - if (retval) - goto failed_usb_serial_register; - retval = usb_register(&kl5kusb105d_driver); - if (retval) - goto failed_usb_register; - - printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" - DRIVER_DESC "\n"); - return 0; -failed_usb_register: - usb_serial_deregister(&kl5kusb105d_device); -failed_usb_serial_register: - return retval; -} - -static void __exit klsi_105_exit(void) -{ - usb_deregister(&kl5kusb105d_driver); - usb_serial_deregister(&kl5kusb105d_device); -} - - -module_init(klsi_105_init); -module_exit(klsi_105_exit); +module_usb_serial_driver(serial_drivers, id_table); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); - - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "enable extensive debugging messages"); diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c index bd5bd8589e0..078f9ed419c 100644 --- a/drivers/usb/serial/kobil_sct.c +++ b/drivers/usb/serial/kobil_sct.c @@ -20,24 +20,11 @@ * * Supported readers: USB TWIN, KAAN Standard Plus and SecOVID Reader Plus * (Adapter K), B1 Professional and KAAN Professional (Adapter B) - * - * (21/05/2004) tw - * Fix bug with P'n'P readers - * - * (28/05/2003) tw - * Add support for KAAN SIM - * - * (12/09/2002) tw - * Adapted to 2.5. - * - * (11/08/2002) tw - * Initial version. */ #include <linux/kernel.h> #include <linux/errno.h> -#include <linux/init.h> #include <linux/slab.h> #include <linux/tty.h> #include <linux/tty_driver.h> @@ -50,10 +37,6 @@ #include <linux/ioctl.h> #include "kobil_sct.h" -static int debug; - -/* Version Information */ -#define DRIVER_VERSION "21/05/2004" #define DRIVER_AUTHOR "KOBIL Systems GmbH - http://www.kobil.com" #define DRIVER_DESC "KOBIL USB Smart Card Terminal Driver (experimental)" @@ -68,20 +51,20 @@ static int debug; /* Function prototypes */ -static int kobil_startup(struct usb_serial *serial); -static void kobil_release(struct usb_serial *serial); +static int kobil_port_probe(struct usb_serial_port *probe); +static int kobil_port_remove(struct usb_serial_port *probe); static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port); static void kobil_close(struct usb_serial_port *port); static int kobil_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count); static int kobil_write_room(struct tty_struct *tty); -static int kobil_ioctl(struct tty_struct *tty, struct file *file, +static int kobil_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg); -static int kobil_tiocmget(struct tty_struct *tty, struct file *file); -static int kobil_tiocmset(struct tty_struct *tty, struct file *file, +static int kobil_tiocmget(struct tty_struct *tty); +static int kobil_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear); static void kobil_read_int_callback(struct urb *urb); -static void kobil_write_callback(struct urb *purb); +static void kobil_write_int_callback(struct urb *urb); static void kobil_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old); static void kobil_init_termios(struct tty_struct *tty); @@ -93,30 +76,18 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(KOBIL_VENDOR_ID, KOBIL_KAAN_SIM_PRODUCT_ID) }, { } /* Terminating entry */ }; - - MODULE_DEVICE_TABLE(usb, id_table); -static struct usb_driver kobil_driver = { - .name = "kobil", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, - .no_dynamic_id = 1, -}; - - static struct usb_serial_driver kobil_device = { .driver = { .owner = THIS_MODULE, .name = "kobil", }, .description = "KOBIL USB smart card terminal", - .usb_driver = &kobil_driver, .id_table = id_table, .num_ports = 1, - .attach = kobil_startup, - .release = kobil_release, + .port_probe = kobil_port_probe, + .port_remove = kobil_port_remove, .ioctl = kobil_ioctl, .set_termios = kobil_set_termios, .init_termios = kobil_init_termios, @@ -127,12 +98,14 @@ static struct usb_serial_driver kobil_device = { .write = kobil_write, .write_room = kobil_write_room, .read_int_callback = kobil_read_int_callback, + .write_int_callback = kobil_write_int_callback, }; +static struct usb_serial_driver * const serial_drivers[] = { + &kobil_device, NULL +}; struct kobil_private { - int write_int_endpoint_address; - int read_int_endpoint_address; unsigned char buf[KOBIL_BUF_LENGTH]; /* buffer for the APDU to send */ int filled; /* index of the last char in buf */ int cur_pos; /* index of the next char to send in buf */ @@ -140,15 +113,10 @@ struct kobil_private { }; -static int kobil_startup(struct usb_serial *serial) +static int kobil_port_probe(struct usb_serial_port *port) { - int i; + struct usb_serial *serial = port->serial; struct kobil_private *priv; - struct usb_device *pdev; - struct usb_host_config *actconfig; - struct usb_interface *interface; - struct usb_host_interface *altsetting; - struct usb_host_endpoint *endpoint; priv = kmalloc(sizeof(struct kobil_private), GFP_KERNEL); if (!priv) @@ -160,108 +128,59 @@ static int kobil_startup(struct usb_serial *serial) switch (priv->device_type) { case KOBIL_ADAPTER_B_PRODUCT_ID: - printk(KERN_DEBUG "KOBIL B1 PRO / KAAN PRO detected\n"); + dev_dbg(&serial->dev->dev, "KOBIL B1 PRO / KAAN PRO detected\n"); break; case KOBIL_ADAPTER_K_PRODUCT_ID: - printk(KERN_DEBUG - "KOBIL KAAN Standard Plus / SecOVID Reader Plus detected\n"); + dev_dbg(&serial->dev->dev, "KOBIL KAAN Standard Plus / SecOVID Reader Plus detected\n"); break; case KOBIL_USBTWIN_PRODUCT_ID: - printk(KERN_DEBUG "KOBIL USBTWIN detected\n"); + dev_dbg(&serial->dev->dev, "KOBIL USBTWIN detected\n"); break; case KOBIL_KAAN_SIM_PRODUCT_ID: - printk(KERN_DEBUG "KOBIL KAAN SIM detected\n"); + dev_dbg(&serial->dev->dev, "KOBIL KAAN SIM detected\n"); break; } - usb_set_serial_port_data(serial->port[0], priv); - - /* search for the necessary endpoints */ - pdev = serial->dev; - actconfig = pdev->actconfig; - interface = actconfig->interface[0]; - altsetting = interface->cur_altsetting; - endpoint = altsetting->endpoint; - - for (i = 0; i < altsetting->desc.bNumEndpoints; i++) { - endpoint = &altsetting->endpoint[i]; - if (usb_endpoint_is_int_out(&endpoint->desc)) { - dbg("%s Found interrupt out endpoint. Address: %d", - __func__, endpoint->desc.bEndpointAddress); - priv->write_int_endpoint_address = - endpoint->desc.bEndpointAddress; - } - if (usb_endpoint_is_int_in(&endpoint->desc)) { - dbg("%s Found interrupt in endpoint. Address: %d", - __func__, endpoint->desc.bEndpointAddress); - priv->read_int_endpoint_address = - endpoint->desc.bEndpointAddress; - } - } + usb_set_serial_port_data(port, priv); + return 0; } -static void kobil_release(struct usb_serial *serial) +static int kobil_port_remove(struct usb_serial_port *port) { - int i; - dbg("%s - port %d", __func__, serial->port[0]->number); + struct kobil_private *priv; - for (i = 0; i < serial->num_ports; ++i) - kfree(usb_get_serial_port_data(serial->port[i])); + priv = usb_get_serial_port_data(port); + kfree(priv); + + return 0; } static void kobil_init_termios(struct tty_struct *tty) { /* Default to echo off and other sane device settings */ - tty->termios->c_lflag = 0; - tty->termios->c_lflag &= ~(ISIG | ICANON | ECHO | IEXTEN | XCASE); - tty->termios->c_iflag = IGNBRK | IGNPAR | IXOFF; + tty->termios.c_lflag = 0; + tty->termios.c_iflag &= ~(ISIG | ICANON | ECHO | IEXTEN | XCASE); + tty->termios.c_iflag |= IGNBRK | IGNPAR | IXOFF; /* do NOT translate CR to CR-NL (0x0A -> 0x0A 0x0D) */ - tty->termios->c_oflag &= ~ONLCR; + tty->termios.c_oflag &= ~ONLCR; } static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port) { + struct device *dev = &port->dev; int result = 0; struct kobil_private *priv; unsigned char *transfer_buffer; int transfer_buffer_length = 8; - int write_urb_transfer_buffer_length = 8; - dbg("%s - port %d", __func__, port->number); priv = usb_get_serial_port_data(port); - /* someone sets the dev to 0 if the close method has been called */ - port->interrupt_in_urb->dev = port->serial->dev; - /* allocate memory for transfer buffer */ transfer_buffer = kzalloc(transfer_buffer_length, GFP_KERNEL); if (!transfer_buffer) return -ENOMEM; - /* allocate write_urb */ - if (!port->write_urb) { - dbg("%s - port %d Allocating port->write_urb", - __func__, port->number); - port->write_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!port->write_urb) { - dbg("%s - port %d usb_alloc_urb failed", - __func__, port->number); - kfree(transfer_buffer); - return -ENOMEM; - } - } - - /* allocate memory for write_urb transfer buffer */ - port->write_urb->transfer_buffer = - kmalloc(write_urb_transfer_buffer_length, GFP_KERNEL); - if (!port->write_urb->transfer_buffer) { - kfree(transfer_buffer); - usb_free_urb(port->write_urb); - port->write_urb = NULL; - return -ENOMEM; - } - /* get hardware version */ result = usb_control_msg(port->serial->dev, usb_rcvctrlpipe(port->serial->dev, 0), @@ -273,10 +192,9 @@ static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port) transfer_buffer_length, KOBIL_TIMEOUT ); - dbg("%s - port %d Send get_HW_version URB returns: %i", - __func__, port->number, result); - dbg("Harware version: %i.%i.%i", - transfer_buffer[0], transfer_buffer[1], transfer_buffer[2]); + dev_dbg(dev, "%s - Send get_HW_version URB returns: %i\n", __func__, result); + dev_dbg(dev, "Hardware version: %i.%i.%i\n", transfer_buffer[0], + transfer_buffer[1], transfer_buffer[2]); /* get firmware version */ result = usb_control_msg(port->serial->dev, @@ -289,49 +207,45 @@ static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port) transfer_buffer_length, KOBIL_TIMEOUT ); - dbg("%s - port %d Send get_FW_version URB returns: %i", - __func__, port->number, result); - dbg("Firmware version: %i.%i.%i", - transfer_buffer[0], transfer_buffer[1], transfer_buffer[2]); + dev_dbg(dev, "%s - Send get_FW_version URB returns: %i\n", __func__, result); + dev_dbg(dev, "Firmware version: %i.%i.%i\n", transfer_buffer[0], + transfer_buffer[1], transfer_buffer[2]); if (priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID || priv->device_type == KOBIL_ADAPTER_K_PRODUCT_ID) { /* Setting Baudrate, Parity and Stopbits */ result = usb_control_msg(port->serial->dev, - usb_rcvctrlpipe(port->serial->dev, 0), + usb_sndctrlpipe(port->serial->dev, 0), SUSBCRequest_SetBaudRateParityAndStopBits, USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT, SUSBCR_SBR_9600 | SUSBCR_SPASB_EvenParity | SUSBCR_SPASB_1StopBit, 0, - transfer_buffer, + NULL, 0, KOBIL_TIMEOUT ); - dbg("%s - port %d Send set_baudrate URB returns: %i", - __func__, port->number, result); + dev_dbg(dev, "%s - Send set_baudrate URB returns: %i\n", __func__, result); /* reset all queues */ result = usb_control_msg(port->serial->dev, - usb_rcvctrlpipe(port->serial->dev, 0), + usb_sndctrlpipe(port->serial->dev, 0), SUSBCRequest_Misc, USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT, SUSBCR_MSC_ResetAllQueues, 0, - transfer_buffer, + NULL, 0, KOBIL_TIMEOUT ); - dbg("%s - port %d Send reset_all_queues URB returns: %i", - __func__, port->number, result); + dev_dbg(dev, "%s - Send reset_all_queues URB returns: %i\n", __func__, result); } if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID || priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID || priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID) { /* start reading (Adapter B 'cause PNP string) */ result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC); - dbg("%s - port %d Send read URB returns: %i", - __func__, port->number, result); + dev_dbg(dev, "%s - Send read URB returns: %i\n", __func__, result); } kfree(transfer_buffer); @@ -341,15 +255,8 @@ static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port) static void kobil_close(struct usb_serial_port *port) { - dbg("%s - port %d", __func__, port->number); - /* FIXME: Add rts/dtr methods */ - if (port->write_urb) { - usb_poison_urb(port->write_urb); - kfree(port->write_urb->transfer_buffer); - usb_free_urb(port->write_urb); - port->write_urb = NULL; - } + usb_kill_urb(port->interrupt_out_urb); usb_kill_urb(port->interrupt_in_urb); } @@ -358,51 +265,27 @@ static void kobil_read_int_callback(struct urb *urb) { int result; struct usb_serial_port *port = urb->context; - struct tty_struct *tty; unsigned char *data = urb->transfer_buffer; int status = urb->status; -/* char *dbg_data; */ - - dbg("%s - port %d", __func__, port->number); if (status) { - dbg("%s - port %d Read int status not zero: %d", - __func__, port->number, status); + dev_dbg(&port->dev, "%s - Read int status not zero: %d\n", __func__, status); return; } - tty = tty_port_tty_get(&port->port); if (urb->actual_length) { - - /* BEGIN DEBUG */ - /* - dbg_data = kzalloc((3 * purb->actual_length + 10) - * sizeof(char), GFP_KERNEL); - if (! dbg_data) { - return; - } - for (i = 0; i < purb->actual_length; i++) { - sprintf(dbg_data +3*i, "%02X ", data[i]); - } - dbg(" <-- %s", dbg_data); - kfree(dbg_data); - */ - /* END DEBUG */ - - tty_insert_flip_string(tty, data, urb->actual_length); - tty_flip_buffer_push(tty); + usb_serial_debug_data(&port->dev, __func__, urb->actual_length, + data); + tty_insert_flip_string(&port->port, data, urb->actual_length); + tty_flip_buffer_push(&port->port); } - tty_kref_put(tty); - /* someone sets the dev to 0 if the close method has been called */ - port->interrupt_in_urb->dev = port->serial->dev; result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC); - dbg("%s - port %d Send read URB returns: %i", - __func__, port->number, result); + dev_dbg(&port->dev, "%s - Send read URB returns: %i\n", __func__, result); } -static void kobil_write_callback(struct urb *purb) +static void kobil_write_int_callback(struct urb *urb) { } @@ -416,22 +299,20 @@ static int kobil_write(struct tty_struct *tty, struct usb_serial_port *port, struct kobil_private *priv; if (count == 0) { - dbg("%s - port %d write request of 0 bytes", - __func__, port->number); + dev_dbg(&port->dev, "%s - write request of 0 bytes\n", __func__); return 0; } priv = usb_get_serial_port_data(port); if (count > (KOBIL_BUF_LENGTH - priv->filled)) { - dbg("%s - port %d Error: write request bigger than buffer size", __func__, port->number); + dev_dbg(&port->dev, "%s - Error: write request bigger than buffer size\n", __func__); return -ENOMEM; } /* Copy data to buffer */ memcpy(priv->buf + priv->filled, buf, count); - usb_serial_debug_data(debug, &port->dev, __func__, count, - priv->buf + priv->filled); + usb_serial_debug_data(&port->dev, __func__, count, priv->buf + priv->filled); priv->filled = priv->filled + count; /* only send complete block. TWIN, KAAN SIM and adapter K @@ -447,25 +328,15 @@ static int kobil_write(struct tty_struct *tty, struct usb_serial_port *port, while (todo > 0) { /* max 8 byte in one urb (endpoint size) */ - length = (todo < 8) ? todo : 8; + length = min(todo, port->interrupt_out_size); /* copy data to transfer buffer */ - memcpy(port->write_urb->transfer_buffer, + memcpy(port->interrupt_out_buffer, priv->buf + priv->cur_pos, length); - usb_fill_int_urb(port->write_urb, - port->serial->dev, - usb_sndintpipe(port->serial->dev, - priv->write_int_endpoint_address), - port->write_urb->transfer_buffer, - length, - kobil_write_callback, - port, - 8 - ); + port->interrupt_out_urb->transfer_buffer_length = length; priv->cur_pos = priv->cur_pos + length; - result = usb_submit_urb(port->write_urb, GFP_NOIO); - dbg("%s - port %d Send write URB returns: %i", - __func__, port->number, result); + result = usb_submit_urb(port->interrupt_out_urb, GFP_NOIO); + dev_dbg(&port->dev, "%s - Send write URB returns: %i\n", __func__, result); todo = priv->filled - priv->cur_pos; if (todo > 0) @@ -475,21 +346,12 @@ static int kobil_write(struct tty_struct *tty, struct usb_serial_port *port, priv->filled = 0; priv->cur_pos = 0; - /* someone sets the dev to 0 if the close method - has been called */ - port->interrupt_in_urb->dev = port->serial->dev; - /* start reading (except TWIN and KAAN SIM) */ if (priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID || priv->device_type == KOBIL_ADAPTER_K_PRODUCT_ID) { - /* someone sets the dev to 0 if the close method has - been called */ - port->interrupt_in_urb->dev = port->serial->dev; - result = usb_submit_urb(port->interrupt_in_urb, GFP_NOIO); - dbg("%s - port %d Send read URB returns: %i", - __func__, port->number, result); + dev_dbg(&port->dev, "%s - Send read URB returns: %i\n", __func__, result); } } return count; @@ -498,13 +360,12 @@ static int kobil_write(struct tty_struct *tty, struct usb_serial_port *port, static int kobil_write_room(struct tty_struct *tty) { - /* dbg("%s - port %d", __func__, port->number); */ /* FIXME */ return 8; } -static int kobil_tiocmget(struct tty_struct *tty, struct file *file) +static int kobil_tiocmget(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; struct kobil_private *priv; @@ -534,8 +395,8 @@ static int kobil_tiocmget(struct tty_struct *tty, struct file *file) transfer_buffer_length, KOBIL_TIMEOUT); - dbg("%s - port %d Send get_status_line_state URB returns: %i. Statusline: %02x", - __func__, port->number, result, transfer_buffer[0]); + dev_dbg(&port->dev, "%s - Send get_status_line_state URB returns: %i. Statusline: %02x\n", + __func__, result, transfer_buffer[0]); result = 0; if ((transfer_buffer[0] & SUSBCR_GSL_DSR) != 0) @@ -544,10 +405,11 @@ static int kobil_tiocmget(struct tty_struct *tty, struct file *file) return result; } -static int kobil_tiocmset(struct tty_struct *tty, struct file *file, +static int kobil_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) { struct usb_serial_port *port = tty->driver_data; + struct device *dev = &port->dev; struct kobil_private *priv; int result; int dtr = 0; @@ -579,39 +441,34 @@ static int kobil_tiocmset(struct tty_struct *tty, struct file *file, if (priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID) { if (dtr != 0) - dbg("%s - port %d Setting DTR", - __func__, port->number); + dev_dbg(dev, "%s - Setting DTR\n", __func__); else - dbg("%s - port %d Clearing DTR", - __func__, port->number); + dev_dbg(dev, "%s - Clearing DTR\n", __func__); result = usb_control_msg(port->serial->dev, - usb_rcvctrlpipe(port->serial->dev, 0), + usb_sndctrlpipe(port->serial->dev, 0), SUSBCRequest_SetStatusLinesOrQueues, USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT, ((dtr != 0) ? SUSBCR_SSL_SETDTR : SUSBCR_SSL_CLRDTR), 0, - transfer_buffer, + NULL, 0, KOBIL_TIMEOUT); } else { if (rts != 0) - dbg("%s - port %d Setting RTS", - __func__, port->number); + dev_dbg(dev, "%s - Setting RTS\n", __func__); else - dbg("%s - port %d Clearing RTS", - __func__, port->number); + dev_dbg(dev, "%s - Clearing RTS\n", __func__); result = usb_control_msg(port->serial->dev, - usb_rcvctrlpipe(port->serial->dev, 0), + usb_sndctrlpipe(port->serial->dev, 0), SUSBCRequest_SetStatusLinesOrQueues, USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT, ((rts != 0) ? SUSBCR_SSL_SETRTS : SUSBCR_SSL_CLRRTS), 0, - transfer_buffer, + NULL, 0, KOBIL_TIMEOUT); } - dbg("%s - port %d Send set_status_line URB returns: %i", - __func__, port->number, result); + dev_dbg(dev, "%s - Send set_status_line URB returns: %i\n", __func__, result); kfree(transfer_buffer); return (result < 0) ? result : 0; } @@ -622,14 +479,14 @@ static void kobil_set_termios(struct tty_struct *tty, struct kobil_private *priv; int result; unsigned short urb_val = 0; - int c_cflag = tty->termios->c_cflag; + int c_cflag = tty->termios.c_cflag; speed_t speed; priv = usb_get_serial_port_data(port); if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID || priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID) { /* This device doesn't support ioctl calls */ - *tty->termios = *old; + tty_termios_copy_hw(&tty->termios, old); return; } @@ -653,11 +510,11 @@ static void kobil_set_termios(struct tty_struct *tty, urb_val |= SUSBCR_SPASB_EvenParity; } else urb_val |= SUSBCR_SPASB_NoParity; - tty->termios->c_cflag &= ~CMSPAR; + tty->termios.c_cflag &= ~CMSPAR; tty_encode_baud_rate(tty, speed, speed); result = usb_control_msg(port->serial->dev, - usb_rcvctrlpipe(port->serial->dev, 0), + usb_sndctrlpipe(port->serial->dev, 0), SUSBCRequest_SetBaudRateParityAndStopBits, USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT, urb_val, @@ -668,7 +525,7 @@ static void kobil_set_termios(struct tty_struct *tty, ); } -static int kobil_ioctl(struct tty_struct *tty, struct file *file, +static int kobil_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { struct usb_serial_port *port = tty->driver_data; @@ -689,17 +546,19 @@ static int kobil_ioctl(struct tty_struct *tty, struct file *file, return -ENOBUFS; result = usb_control_msg(port->serial->dev, - usb_rcvctrlpipe(port->serial->dev, 0), + usb_sndctrlpipe(port->serial->dev, 0), SUSBCRequest_Misc, USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT, SUSBCR_MSC_ResetAllQueues, 0, - NULL, /* transfer_buffer, */ + NULL, 0, KOBIL_TIMEOUT ); - dbg("%s - port %d Send reset_all_queues (FLUSH) URB returns: %i", __func__, port->number, result); + dev_dbg(&port->dev, + "%s - Send reset_all_queues (FLUSH) URB returns: %i\n", + __func__, result); kfree(transfer_buffer); return (result < 0) ? -EIO: 0; default: @@ -707,39 +566,8 @@ static int kobil_ioctl(struct tty_struct *tty, struct file *file, } } -static int __init kobil_init(void) -{ - int retval; - retval = usb_serial_register(&kobil_device); - if (retval) - goto failed_usb_serial_register; - retval = usb_register(&kobil_driver); - if (retval) - goto failed_usb_register; - - printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" - DRIVER_DESC "\n"); - - return 0; -failed_usb_register: - usb_serial_deregister(&kobil_device); -failed_usb_serial_register: - return retval; -} - - -static void __exit kobil_exit(void) -{ - usb_deregister(&kobil_driver); - usb_serial_deregister(&kobil_device); -} - -module_init(kobil_init); -module_exit(kobil_exit); +module_usb_serial_driver(serial_drivers, id_table); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c index 2849f8c3201..fd707d6a10e 100644 --- a/drivers/usb/serial/mct_u232.c +++ b/drivers/usb/serial/mct_u232.c @@ -19,55 +19,10 @@ * DTR/RTS signal handling may be incomplete or incorrect. I have mainly * implemented what I have seen with SniffUSB or found in belkin_sa.c. * For further TODOs check also belkin_sa.c. - * - * TEST STATUS: - * Basic tests have been performed with minicom/zmodem transfers and - * modem dialing under Linux 2.4.0-test10 (for me it works fine). - * - * 04-Nov-2003 Bill Marr <marr at flex dot com> - * - Mimic Windows driver by sending 2 USB 'device request' messages - * following normal 'baud rate change' message. This allows data to be - * transmitted to RS-232 devices which don't assert the 'CTS' signal. - * - * 10-Nov-2001 Wolfgang Grandegger - * - Fixed an endianess problem with the baudrate selection for PowerPC. - * - * 06-Dec-2001 Martin Hamilton <martinh@gnu.org> - * - Added support for the Belkin F5U109 DB9 adaptor - * - * 30-May-2001 Greg Kroah-Hartman - * - switched from using spinlock to a semaphore, which fixes lots of - * problems. - * - * 04-May-2001 Stelian Pop - * - Set the maximum bulk output size for Sitecom U232-P25 model to 16 bytes - * instead of the device reported 32 (using 32 bytes causes many data - * loss, Windows driver uses 16 too). - * - * 02-May-2001 Stelian Pop - * - Fixed the baud calculation for Sitecom U232-P25 model - * - * 08-Apr-2001 gb - * - Identify version on module load. - * - * 06-Jan-2001 Cornel Ciocirlan - * - Added support for Sitecom U232-P25 model (Product Id 0x0230) - * - Added support for D-Link DU-H3SP USB BAY (Product Id 0x0200) - * - * 29-Nov-2000 Greg Kroah-Hartman - * - Added device id table to fit with 2.4.0-test11 structure. - * - took out DEAL_WITH_TWO_INT_IN_ENDPOINTS #define as it's not needed - * (lots of things will change if/when the usb-serial core changes to - * handle these issues. - * - * 27-Nov-2000 Wolfgang Grandegge - * A version for kernel 2.4.0-test10 released to the Linux community - * (via linux-usb-devel). */ #include <linux/kernel.h> #include <linux/errno.h> -#include <linux/init.h> #include <linux/slab.h> #include <linux/tty.h> #include <linux/tty_driver.h> @@ -78,22 +33,17 @@ #include <asm/unaligned.h> #include <linux/usb.h> #include <linux/usb/serial.h> +#include <linux/serial.h> #include "mct_u232.h" -/* - * Version Information - */ -#define DRIVER_VERSION "z2.1" /* Linux in-kernel version */ #define DRIVER_AUTHOR "Wolfgang Grandegger <wolfgang@ces.ch>" #define DRIVER_DESC "Magic Control Technology USB-RS232 converter driver" -static int debug; - /* * Function prototypes */ -static int mct_u232_startup(struct usb_serial *serial); -static void mct_u232_release(struct usb_serial *serial); +static int mct_u232_port_probe(struct usb_serial_port *port); +static int mct_u232_port_remove(struct usb_serial_port *remove); static int mct_u232_open(struct tty_struct *tty, struct usb_serial_port *port); static void mct_u232_close(struct usb_serial_port *port); static void mct_u232_dtr_rts(struct usb_serial_port *port, int on); @@ -101,8 +51,8 @@ static void mct_u232_read_int_callback(struct urb *urb); static void mct_u232_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old); static void mct_u232_break_ctl(struct tty_struct *tty, int break_state); -static int mct_u232_tiocmget(struct tty_struct *tty, struct file *file); -static int mct_u232_tiocmset(struct tty_struct *tty, struct file *file, +static int mct_u232_tiocmget(struct tty_struct *tty); +static int mct_u232_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear); static void mct_u232_throttle(struct tty_struct *tty); static void mct_u232_unthrottle(struct tty_struct *tty); @@ -111,23 +61,14 @@ static void mct_u232_unthrottle(struct tty_struct *tty); /* * All of the device info needed for the MCT USB-RS232 converter. */ -static const struct usb_device_id id_table_combined[] = { +static const struct usb_device_id id_table[] = { { USB_DEVICE(MCT_U232_VID, MCT_U232_PID) }, { USB_DEVICE(MCT_U232_VID, MCT_U232_SITECOM_PID) }, { USB_DEVICE(MCT_U232_VID, MCT_U232_DU_H3SP_PID) }, { USB_DEVICE(MCT_U232_BELKIN_F5U109_VID, MCT_U232_BELKIN_F5U109_PID) }, { } /* Terminating entry */ }; - -MODULE_DEVICE_TABLE(usb, id_table_combined); - -static struct usb_driver mct_u232_driver = { - .name = "mct_u232", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table_combined, - .no_dynamic_id = 1, -}; +MODULE_DEVICE_TABLE(usb, id_table); static struct usb_serial_driver mct_u232_device = { .driver = { @@ -135,8 +76,7 @@ static struct usb_serial_driver mct_u232_device = { .name = "mct_u232", }, .description = "MCT U232", - .usb_driver = &mct_u232_driver, - .id_table = id_table_combined, + .id_table = id_table, .num_ports = 1, .open = mct_u232_open, .close = mct_u232_close, @@ -148,12 +88,18 @@ static struct usb_serial_driver mct_u232_device = { .break_ctl = mct_u232_break_ctl, .tiocmget = mct_u232_tiocmget, .tiocmset = mct_u232_tiocmset, - .attach = mct_u232_startup, - .release = mct_u232_release, + .tiocmiwait = usb_serial_generic_tiocmiwait, + .port_probe = mct_u232_port_probe, + .port_remove = mct_u232_port_remove, + .get_icount = usb_serial_generic_get_icount, }; +static struct usb_serial_driver * const serial_drivers[] = { + &mct_u232_device, NULL +}; struct mct_u232_private { + struct urb *read_urb; spinlock_t lock; unsigned int control_state; /* Modem Line Setting (TIOCM) */ unsigned char last_lcr; /* Line Control Register */ @@ -254,7 +200,7 @@ static int mct_u232_set_baud_rate(struct tty_struct *tty, value, rc); else tty_encode_baud_rate(tty, speed, speed); - dbg("set_baud_rate: value: 0x%x, divisor: 0x%x", value, divisor); + dev_dbg(&port->dev, "set_baud_rate: value: 0x%x, divisor: 0x%x\n", value, divisor); /* Mimic the MCT-supplied Windows driver (version 1.21P.0104), which always sends two extra USB 'device request' messages after the @@ -287,8 +233,8 @@ static int mct_u232_set_baud_rate(struct tty_struct *tty, if (port && C_CRTSCTS(tty)) cts_enable_byte = 1; - dbg("set_baud_rate: send second control message, data = %02X", - cts_enable_byte); + dev_dbg(&port->dev, "set_baud_rate: send second control message, data = %02X\n", + cts_enable_byte); buf[0] = cts_enable_byte; rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), MCT_U232_SET_CTS_REQUEST, @@ -303,7 +249,8 @@ static int mct_u232_set_baud_rate(struct tty_struct *tty, return rc; } /* mct_u232_set_baud_rate */ -static int mct_u232_set_line_ctrl(struct usb_serial *serial, unsigned char lcr) +static int mct_u232_set_line_ctrl(struct usb_serial_port *port, + unsigned char lcr) { int rc; unsigned char *buf; @@ -313,20 +260,19 @@ static int mct_u232_set_line_ctrl(struct usb_serial *serial, unsigned char lcr) return -ENOMEM; buf[0] = lcr; - rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + rc = usb_control_msg(port->serial->dev, usb_sndctrlpipe(port->serial->dev, 0), MCT_U232_SET_LINE_CTRL_REQUEST, MCT_U232_SET_REQUEST_TYPE, 0, 0, buf, MCT_U232_SET_LINE_CTRL_SIZE, WDR_TIMEOUT); if (rc < 0) - dev_err(&serial->dev->dev, - "Set LINE CTRL 0x%x failed (error = %d)\n", lcr, rc); - dbg("set_line_ctrl: 0x%x", lcr); + dev_err(&port->dev, "Set LINE CTRL 0x%x failed (error = %d)\n", lcr, rc); + dev_dbg(&port->dev, "set_line_ctrl: 0x%x\n", lcr); kfree(buf); return rc; } /* mct_u232_set_line_ctrl */ -static int mct_u232_set_modem_ctrl(struct usb_serial *serial, +static int mct_u232_set_modem_ctrl(struct usb_serial_port *port, unsigned int control_state) { int rc; @@ -344,22 +290,24 @@ static int mct_u232_set_modem_ctrl(struct usb_serial *serial, mcr |= MCT_U232_MCR_RTS; buf[0] = mcr; - rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + rc = usb_control_msg(port->serial->dev, usb_sndctrlpipe(port->serial->dev, 0), MCT_U232_SET_MODEM_CTRL_REQUEST, MCT_U232_SET_REQUEST_TYPE, 0, 0, buf, MCT_U232_SET_MODEM_CTRL_SIZE, WDR_TIMEOUT); - if (rc < 0) - dev_err(&serial->dev->dev, - "Set MODEM CTRL 0x%x failed (error = %d)\n", mcr, rc); - dbg("set_modem_ctrl: state=0x%x ==> mcr=0x%x", control_state, mcr); - kfree(buf); - return rc; + + dev_dbg(&port->dev, "set_modem_ctrl: state=0x%x ==> mcr=0x%x\n", control_state, mcr); + + if (rc < 0) { + dev_err(&port->dev, "Set MODEM CTRL 0x%x failed (error = %d)\n", mcr, rc); + return rc; + } + return 0; } /* mct_u232_set_modem_ctrl */ -static int mct_u232_get_modem_stat(struct usb_serial *serial, - unsigned char *msr) +static int mct_u232_get_modem_stat(struct usb_serial_port *port, + unsigned char *msr) { int rc; unsigned char *buf; @@ -369,27 +317,40 @@ static int mct_u232_get_modem_stat(struct usb_serial *serial, *msr = 0; return -ENOMEM; } - rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), + rc = usb_control_msg(port->serial->dev, usb_rcvctrlpipe(port->serial->dev, 0), MCT_U232_GET_MODEM_STAT_REQUEST, MCT_U232_GET_REQUEST_TYPE, 0, 0, buf, MCT_U232_GET_MODEM_STAT_SIZE, WDR_TIMEOUT); if (rc < 0) { - dev_err(&serial->dev->dev, - "Get MODEM STATus failed (error = %d)\n", rc); + dev_err(&port->dev, "Get MODEM STATus failed (error = %d)\n", rc); *msr = 0; } else { *msr = buf[0]; } - dbg("get_modem_stat: 0x%x", *msr); + dev_dbg(&port->dev, "get_modem_stat: 0x%x\n", *msr); kfree(buf); return rc; } /* mct_u232_get_modem_stat */ -static void mct_u232_msr_to_state(unsigned int *control_state, +static void mct_u232_msr_to_icount(struct async_icount *icount, unsigned char msr) { /* Translate Control Line states */ + if (msr & MCT_U232_MSR_DDSR) + icount->dsr++; + if (msr & MCT_U232_MSR_DCTS) + icount->cts++; + if (msr & MCT_U232_MSR_DRI) + icount->rng++; + if (msr & MCT_U232_MSR_DCD) + icount->dcd++; +} /* mct_u232_msr_to_icount */ + +static void mct_u232_msr_to_state(struct usb_serial_port *port, + unsigned int *control_state, unsigned char msr) +{ + /* Translate Control Line states */ if (msr & MCT_U232_MSR_DSR) *control_state |= TIOCM_DSR; else @@ -406,52 +367,41 @@ static void mct_u232_msr_to_state(unsigned int *control_state, *control_state |= TIOCM_CD; else *control_state &= ~TIOCM_CD; - dbg("msr_to_state: msr=0x%x ==> state=0x%x", msr, *control_state); + dev_dbg(&port->dev, "msr_to_state: msr=0x%x ==> state=0x%x\n", msr, *control_state); } /* mct_u232_msr_to_state */ /* * Driver's tty interface functions */ -static int mct_u232_startup(struct usb_serial *serial) +static int mct_u232_port_probe(struct usb_serial_port *port) { struct mct_u232_private *priv; - struct usb_serial_port *port, *rport; - priv = kzalloc(sizeof(struct mct_u232_private), GFP_KERNEL); + priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; - spin_lock_init(&priv->lock); - usb_set_serial_port_data(serial->port[0], priv); - init_waitqueue_head(&serial->port[0]->write_wait); + /* Use second interrupt-in endpoint for reading. */ + priv->read_urb = port->serial->port[1]->interrupt_in_urb; + priv->read_urb->context = port; - /* Puh, that's dirty */ - port = serial->port[0]; - rport = serial->port[1]; - /* No unlinking, it wasn't submitted yet. */ - usb_free_urb(port->read_urb); - port->read_urb = rport->interrupt_in_urb; - rport->interrupt_in_urb = NULL; - port->read_urb->context = port; + spin_lock_init(&priv->lock); - return 0; -} /* mct_u232_startup */ + usb_set_serial_port_data(port, priv); + return 0; +} -static void mct_u232_release(struct usb_serial *serial) +static int mct_u232_port_remove(struct usb_serial_port *port) { struct mct_u232_private *priv; - int i; - dbg("%s", __func__); + priv = usb_get_serial_port_data(port); + kfree(priv); - for (i = 0; i < serial->num_ports; ++i) { - /* My special items, the standard routines free my urbs */ - priv = usb_get_serial_port_data(serial->port[i]); - kfree(priv); - } -} /* mct_u232_release */ + return 0; +} static int mct_u232_open(struct tty_struct *tty, struct usb_serial_port *port) { @@ -463,8 +413,6 @@ static int mct_u232_open(struct tty_struct *tty, struct usb_serial_port *port) unsigned char last_lcr; unsigned char last_msr; - dbg("%s port %d", __func__, port->number); - /* Compensate for a hardware bug: although the Sitecom U232-P25 * device reports a maximum output packet size of 32 bytes, * it seems to be able to accept only 16 bytes (and that's what @@ -480,7 +428,7 @@ static int mct_u232_open(struct tty_struct *tty, struct usb_serial_port *port) * either. */ spin_lock_irqsave(&priv->lock, flags); - if (tty && (tty->termios->c_cflag & CBAUD)) + if (tty && (tty->termios.c_cflag & CBAUD)) priv->control_state = TIOCM_DTR | TIOCM_RTS; else priv->control_state = 0; @@ -491,29 +439,27 @@ static int mct_u232_open(struct tty_struct *tty, struct usb_serial_port *port) control_state = priv->control_state; last_lcr = priv->last_lcr; spin_unlock_irqrestore(&priv->lock, flags); - mct_u232_set_modem_ctrl(serial, control_state); - mct_u232_set_line_ctrl(serial, last_lcr); + mct_u232_set_modem_ctrl(port, control_state); + mct_u232_set_line_ctrl(port, last_lcr); /* Read modem status and update control state */ - mct_u232_get_modem_stat(serial, &last_msr); + mct_u232_get_modem_stat(port, &last_msr); spin_lock_irqsave(&priv->lock, flags); priv->last_msr = last_msr; - mct_u232_msr_to_state(&priv->control_state, priv->last_msr); + mct_u232_msr_to_state(port, &priv->control_state, priv->last_msr); spin_unlock_irqrestore(&priv->lock, flags); - port->read_urb->dev = port->serial->dev; - retval = usb_submit_urb(port->read_urb, GFP_KERNEL); + retval = usb_submit_urb(priv->read_urb, GFP_KERNEL); if (retval) { dev_err(&port->dev, - "usb_submit_urb(read bulk) failed pipe 0x%x err %d\n", + "usb_submit_urb(read) failed pipe 0x%x err %d\n", port->read_urb->pipe, retval); goto error; } - port->interrupt_in_urb->dev = port->serial->dev; retval = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); if (retval) { - usb_kill_urb(port->read_urb); + usb_kill_urb(priv->read_urb); dev_err(&port->dev, "usb_submit_urb(read int) failed pipe 0x%x err %d", port->interrupt_in_urb->pipe, retval); @@ -530,31 +476,25 @@ static void mct_u232_dtr_rts(struct usb_serial_port *port, int on) unsigned int control_state; struct mct_u232_private *priv = usb_get_serial_port_data(port); - mutex_lock(&port->serial->disc_mutex); - if (!port->serial->disconnected) { - /* drop DTR and RTS */ - spin_lock_irq(&priv->lock); - if (on) - priv->control_state |= TIOCM_DTR | TIOCM_RTS; - else - priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS); - control_state = priv->control_state; - spin_unlock_irq(&priv->lock); - mct_u232_set_modem_ctrl(port->serial, control_state); - } - mutex_unlock(&port->serial->disc_mutex); + spin_lock_irq(&priv->lock); + if (on) + priv->control_state |= TIOCM_DTR | TIOCM_RTS; + else + priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS); + control_state = priv->control_state; + spin_unlock_irq(&priv->lock); + + mct_u232_set_modem_ctrl(port, control_state); } static void mct_u232_close(struct usb_serial_port *port) { - dbg("%s port %d", __func__, port->number); + struct mct_u232_private *priv = usb_get_serial_port_data(port); - if (port->serial->dev) { - /* shutdown our urbs */ - usb_kill_urb(port->write_urb); - usb_kill_urb(port->read_urb); - usb_kill_urb(port->interrupt_in_urb); - } + usb_kill_urb(priv->read_urb); + usb_kill_urb(port->interrupt_in_urb); + + usb_serial_generic_close(port); } /* mct_u232_close */ @@ -562,8 +502,6 @@ static void mct_u232_read_int_callback(struct urb *urb) { struct usb_serial_port *port = urb->context; struct mct_u232_private *priv = usb_get_serial_port_data(port); - struct usb_serial *serial = port->serial; - struct tty_struct *tty; unsigned char *data = urb->transfer_buffer; int retval; int status = urb->status; @@ -577,36 +515,25 @@ static void mct_u232_read_int_callback(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", - __func__, status); + dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n", + __func__, status); return; default: - dbg("%s - nonzero urb status received: %d", - __func__, status); + dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n", + __func__, status); goto exit; } - if (!serial) { - dbg("%s - bad serial pointer, exiting", __func__); - return; - } - - dbg("%s - port %d", __func__, port->number); - usb_serial_debug_data(debug, &port->dev, __func__, - urb->actual_length, data); + usb_serial_debug_data(&port->dev, __func__, urb->actual_length, data); /* * Work-a-round: handle the 'usual' bulk-in pipe here */ if (urb->transfer_buffer_length > 2) { if (urb->actual_length) { - tty = tty_port_tty_get(&port->port); - if (tty) { - tty_insert_flip_string(tty, data, - urb->actual_length); - tty_flip_buffer_push(tty); - } - tty_kref_put(tty); + tty_insert_flip_string(&port->port, data, + urb->actual_length); + tty_flip_buffer_push(&port->port); } goto exit; } @@ -619,7 +546,9 @@ static void mct_u232_read_int_callback(struct urb *urb) priv->last_msr = data[MCT_U232_MSR_INDEX]; /* Record Control Line states */ - mct_u232_msr_to_state(&priv->control_state, priv->last_msr); + mct_u232_msr_to_state(port, &priv->control_state, priv->last_msr); + + mct_u232_msr_to_icount(&port->icount, priv->last_msr); #if 0 /* Not yet handled. See belkin_sa.c for further information */ @@ -647,6 +576,7 @@ static void mct_u232_read_int_callback(struct urb *urb) tty_kref_put(tty); } #endif + wake_up_interruptible(&port->port.delta_msr_wait); spin_unlock_irqrestore(&priv->lock, flags); exit: retval = usb_submit_urb(urb, GFP_ATOMIC); @@ -662,7 +592,7 @@ static void mct_u232_set_termios(struct tty_struct *tty, { struct usb_serial *serial = port->serial; struct mct_u232_private *priv = usb_get_serial_port_data(port); - struct ktermios *termios = tty->termios; + struct ktermios *termios = &tty->termios; unsigned int cflag = termios->c_cflag; unsigned int old_cflag = old_termios->c_cflag; unsigned long flags; @@ -684,18 +614,18 @@ static void mct_u232_set_termios(struct tty_struct *tty, /* reassert DTR and RTS on transition from B0 */ if ((old_cflag & CBAUD) == B0) { - dbg("%s: baud was B0", __func__); + dev_dbg(&port->dev, "%s: baud was B0\n", __func__); control_state |= TIOCM_DTR | TIOCM_RTS; - mct_u232_set_modem_ctrl(serial, control_state); + mct_u232_set_modem_ctrl(port, control_state); } mct_u232_set_baud_rate(tty, serial, port, tty_get_baud_rate(tty)); if ((cflag & CBAUD) == B0) { - dbg("%s: baud is B0", __func__); + dev_dbg(&port->dev, "%s: baud is B0\n", __func__); /* Drop RTS and DTR */ control_state &= ~(TIOCM_DTR | TIOCM_RTS); - mct_u232_set_modem_ctrl(serial, control_state); + mct_u232_set_modem_ctrl(port, control_state); } /* @@ -732,7 +662,7 @@ static void mct_u232_set_termios(struct tty_struct *tty, last_lcr |= (cflag & CSTOPB) ? MCT_U232_STOP_BITS_2 : MCT_U232_STOP_BITS_1; - mct_u232_set_line_ctrl(serial, last_lcr); + mct_u232_set_line_ctrl(port, last_lcr); /* save off the modified port settings */ spin_lock_irqsave(&priv->lock, flags); @@ -744,13 +674,10 @@ static void mct_u232_set_termios(struct tty_struct *tty, static void mct_u232_break_ctl(struct tty_struct *tty, int break_state) { struct usb_serial_port *port = tty->driver_data; - struct usb_serial *serial = port->serial; struct mct_u232_private *priv = usb_get_serial_port_data(port); unsigned char lcr; unsigned long flags; - dbg("%sstate=%d", __func__, break_state); - spin_lock_irqsave(&priv->lock, flags); lcr = priv->last_lcr; @@ -758,19 +685,17 @@ static void mct_u232_break_ctl(struct tty_struct *tty, int break_state) lcr |= MCT_U232_SET_BREAK; spin_unlock_irqrestore(&priv->lock, flags); - mct_u232_set_line_ctrl(serial, lcr); + mct_u232_set_line_ctrl(port, lcr); } /* mct_u232_break_ctl */ -static int mct_u232_tiocmget(struct tty_struct *tty, struct file *file) +static int mct_u232_tiocmget(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; struct mct_u232_private *priv = usb_get_serial_port_data(port); unsigned int control_state; unsigned long flags; - dbg("%s", __func__); - spin_lock_irqsave(&priv->lock, flags); control_state = priv->control_state; spin_unlock_irqrestore(&priv->lock, flags); @@ -778,17 +703,14 @@ static int mct_u232_tiocmget(struct tty_struct *tty, struct file *file) return control_state; } -static int mct_u232_tiocmset(struct tty_struct *tty, struct file *file, +static int mct_u232_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) { struct usb_serial_port *port = tty->driver_data; - struct usb_serial *serial = port->serial; struct mct_u232_private *priv = usb_get_serial_port_data(port); unsigned int control_state; unsigned long flags; - dbg("%s", __func__); - spin_lock_irqsave(&priv->lock, flags); control_state = priv->control_state; @@ -803,7 +725,7 @@ static int mct_u232_tiocmset(struct tty_struct *tty, struct file *file, priv->control_state = control_state; spin_unlock_irqrestore(&priv->lock, flags); - return mct_u232_set_modem_ctrl(serial, control_state); + return mct_u232_set_modem_ctrl(port, control_state); } static void mct_u232_throttle(struct tty_struct *tty) @@ -812,72 +734,38 @@ static void mct_u232_throttle(struct tty_struct *tty) struct mct_u232_private *priv = usb_get_serial_port_data(port); unsigned int control_state; - dbg("%s - port %d", __func__, port->number); - spin_lock_irq(&priv->lock); priv->rx_flags |= THROTTLED; if (C_CRTSCTS(tty)) { priv->control_state &= ~TIOCM_RTS; control_state = priv->control_state; spin_unlock_irq(&priv->lock); - (void) mct_u232_set_modem_ctrl(port->serial, control_state); + mct_u232_set_modem_ctrl(port, control_state); } else { spin_unlock_irq(&priv->lock); } } - static void mct_u232_unthrottle(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; struct mct_u232_private *priv = usb_get_serial_port_data(port); unsigned int control_state; - dbg("%s - port %d", __func__, port->number); - spin_lock_irq(&priv->lock); if ((priv->rx_flags & THROTTLED) && C_CRTSCTS(tty)) { priv->rx_flags &= ~THROTTLED; priv->control_state |= TIOCM_RTS; control_state = priv->control_state; spin_unlock_irq(&priv->lock); - (void) mct_u232_set_modem_ctrl(port->serial, control_state); + mct_u232_set_modem_ctrl(port, control_state); } else { spin_unlock_irq(&priv->lock); } } -static int __init mct_u232_init(void) -{ - int retval; - retval = usb_serial_register(&mct_u232_device); - if (retval) - goto failed_usb_serial_register; - retval = usb_register(&mct_u232_driver); - if (retval) - goto failed_usb_register; - printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" - DRIVER_DESC "\n"); - return 0; -failed_usb_register: - usb_serial_deregister(&mct_u232_device); -failed_usb_serial_register: - return retval; -} - - -static void __exit mct_u232_exit(void) -{ - usb_deregister(&mct_u232_driver); - usb_serial_deregister(&mct_u232_device); -} - -module_init(mct_u232_init); -module_exit(mct_u232_exit); +module_usb_serial_driver(serial_drivers, id_table); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/drivers/usb/serial/metro-usb.c b/drivers/usb/serial/metro-usb.c new file mode 100644 index 00000000000..39e683096e9 --- /dev/null +++ b/drivers/usb/serial/metro-usb.c @@ -0,0 +1,399 @@ +/* + Some of this code is credited to Linux USB open source files that are + distributed with Linux. + + Copyright: 2007 Metrologic Instruments. All rights reserved. + Copyright: 2011 Azimut Ltd. <http://azimutrzn.ru/> +*/ + +#include <linux/kernel.h> +#include <linux/tty.h> +#include <linux/module.h> +#include <linux/usb.h> +#include <linux/errno.h> +#include <linux/slab.h> +#include <linux/tty_driver.h> +#include <linux/tty_flip.h> +#include <linux/moduleparam.h> +#include <linux/spinlock.h> +#include <linux/uaccess.h> +#include <linux/usb/serial.h> + +#define DRIVER_DESC "Metrologic Instruments Inc. - USB-POS driver" + +/* Product information. */ +#define FOCUS_VENDOR_ID 0x0C2E +#define FOCUS_PRODUCT_ID_BI 0x0720 +#define FOCUS_PRODUCT_ID_UNI 0x0700 + +#define METROUSB_SET_REQUEST_TYPE 0x40 +#define METROUSB_SET_MODEM_CTRL_REQUEST 10 +#define METROUSB_SET_BREAK_REQUEST 0x40 +#define METROUSB_MCR_NONE 0x08 /* Deactivate DTR and RTS. */ +#define METROUSB_MCR_RTS 0x0a /* Activate RTS. */ +#define METROUSB_MCR_DTR 0x09 /* Activate DTR. */ +#define WDR_TIMEOUT 5000 /* default urb timeout. */ + +/* Private data structure. */ +struct metrousb_private { + spinlock_t lock; + int throttled; + unsigned long control_state; +}; + +/* Device table list. */ +static const struct usb_device_id id_table[] = { + { USB_DEVICE(FOCUS_VENDOR_ID, FOCUS_PRODUCT_ID_BI) }, + { USB_DEVICE(FOCUS_VENDOR_ID, FOCUS_PRODUCT_ID_UNI) }, + { }, /* Terminating entry. */ +}; +MODULE_DEVICE_TABLE(usb, id_table); + +/* UNI-Directional mode commands for device configure */ +#define UNI_CMD_OPEN 0x80 +#define UNI_CMD_CLOSE 0xFF + +static inline int metrousb_is_unidirectional_mode(struct usb_serial_port *port) +{ + __u16 product_id = le16_to_cpu( + port->serial->dev->descriptor.idProduct); + + return product_id == FOCUS_PRODUCT_ID_UNI; +} + +static int metrousb_send_unidirectional_cmd(u8 cmd, struct usb_serial_port *port) +{ + int ret; + int actual_len; + u8 *buffer_cmd = NULL; + + if (!metrousb_is_unidirectional_mode(port)) + return 0; + + buffer_cmd = kzalloc(sizeof(cmd), GFP_KERNEL); + if (!buffer_cmd) + return -ENOMEM; + + *buffer_cmd = cmd; + + ret = usb_interrupt_msg(port->serial->dev, + usb_sndintpipe(port->serial->dev, port->interrupt_out_endpointAddress), + buffer_cmd, sizeof(cmd), + &actual_len, USB_CTRL_SET_TIMEOUT); + + kfree(buffer_cmd); + + if (ret < 0) + return ret; + else if (actual_len != sizeof(cmd)) + return -EIO; + return 0; +} + +static void metrousb_read_int_callback(struct urb *urb) +{ + struct usb_serial_port *port = urb->context; + struct metrousb_private *metro_priv = usb_get_serial_port_data(port); + unsigned char *data = urb->transfer_buffer; + int throttled = 0; + int result = 0; + unsigned long flags = 0; + + dev_dbg(&port->dev, "%s\n", __func__); + + switch (urb->status) { + case 0: + /* Success status, read from the port. */ + break; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + /* urb has been terminated. */ + dev_dbg(&port->dev, + "%s - urb shutting down, error code=%d\n", + __func__, urb->status); + return; + default: + dev_dbg(&port->dev, + "%s - non-zero urb received, error code=%d\n", + __func__, urb->status); + goto exit; + } + + + /* Set the data read from the usb port into the serial port buffer. */ + if (urb->actual_length) { + /* Loop through the data copying each byte to the tty layer. */ + tty_insert_flip_string(&port->port, data, urb->actual_length); + + /* Force the data to the tty layer. */ + tty_flip_buffer_push(&port->port); + } + + /* Set any port variables. */ + spin_lock_irqsave(&metro_priv->lock, flags); + throttled = metro_priv->throttled; + spin_unlock_irqrestore(&metro_priv->lock, flags); + + /* Continue trying to read if set. */ + if (!throttled) { + usb_fill_int_urb(port->interrupt_in_urb, port->serial->dev, + usb_rcvintpipe(port->serial->dev, port->interrupt_in_endpointAddress), + port->interrupt_in_urb->transfer_buffer, + port->interrupt_in_urb->transfer_buffer_length, + metrousb_read_int_callback, port, 1); + + result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC); + + if (result) + dev_err(&port->dev, + "%s - failed submitting interrupt in urb, error code=%d\n", + __func__, result); + } + return; + +exit: + /* Try to resubmit the urb. */ + result = usb_submit_urb(urb, GFP_ATOMIC); + if (result) + dev_err(&port->dev, + "%s - failed submitting interrupt in urb, error code=%d\n", + __func__, result); +} + +static void metrousb_write_int_callback(struct urb *urb) +{ + struct usb_serial_port *port = urb->context; + + dev_warn(&port->dev, "%s not implemented yet.\n", + __func__); +} + +static void metrousb_cleanup(struct usb_serial_port *port) +{ + dev_dbg(&port->dev, "%s\n", __func__); + + usb_unlink_urb(port->interrupt_in_urb); + usb_kill_urb(port->interrupt_in_urb); + + metrousb_send_unidirectional_cmd(UNI_CMD_CLOSE, port); +} + +static int metrousb_open(struct tty_struct *tty, struct usb_serial_port *port) +{ + struct usb_serial *serial = port->serial; + struct metrousb_private *metro_priv = usb_get_serial_port_data(port); + unsigned long flags = 0; + int result = 0; + + dev_dbg(&port->dev, "%s\n", __func__); + + /* Make sure the urb is initialized. */ + if (!port->interrupt_in_urb) { + dev_err(&port->dev, "%s - interrupt urb not initialized\n", + __func__); + return -ENODEV; + } + + /* Set the private data information for the port. */ + spin_lock_irqsave(&metro_priv->lock, flags); + metro_priv->control_state = 0; + metro_priv->throttled = 0; + spin_unlock_irqrestore(&metro_priv->lock, flags); + + /* Clear the urb pipe. */ + usb_clear_halt(serial->dev, port->interrupt_in_urb->pipe); + + /* Start reading from the device */ + usb_fill_int_urb(port->interrupt_in_urb, serial->dev, + usb_rcvintpipe(serial->dev, port->interrupt_in_endpointAddress), + port->interrupt_in_urb->transfer_buffer, + port->interrupt_in_urb->transfer_buffer_length, + metrousb_read_int_callback, port, 1); + result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); + + if (result) { + dev_err(&port->dev, + "%s - failed submitting interrupt in urb, error code=%d\n", + __func__, result); + goto exit; + } + + /* Send activate cmd to device */ + result = metrousb_send_unidirectional_cmd(UNI_CMD_OPEN, port); + if (result) { + dev_err(&port->dev, + "%s - failed to configure device, error code=%d\n", + __func__, result); + goto exit; + } + + dev_dbg(&port->dev, "%s - port open\n", __func__); +exit: + return result; +} + +static int metrousb_set_modem_ctrl(struct usb_serial *serial, unsigned int control_state) +{ + int retval = 0; + unsigned char mcr = METROUSB_MCR_NONE; + + dev_dbg(&serial->dev->dev, "%s - control state = %d\n", + __func__, control_state); + + /* Set the modem control value. */ + if (control_state & TIOCM_DTR) + mcr |= METROUSB_MCR_DTR; + if (control_state & TIOCM_RTS) + mcr |= METROUSB_MCR_RTS; + + /* Send the command to the usb port. */ + retval = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + METROUSB_SET_REQUEST_TYPE, METROUSB_SET_MODEM_CTRL_REQUEST, + control_state, 0, NULL, 0, WDR_TIMEOUT); + if (retval < 0) + dev_err(&serial->dev->dev, + "%s - set modem ctrl=0x%x failed, error code=%d\n", + __func__, mcr, retval); + + return retval; +} + +static int metrousb_port_probe(struct usb_serial_port *port) +{ + struct metrousb_private *metro_priv; + + metro_priv = kzalloc(sizeof(*metro_priv), GFP_KERNEL); + if (!metro_priv) + return -ENOMEM; + + spin_lock_init(&metro_priv->lock); + + usb_set_serial_port_data(port, metro_priv); + + return 0; +} + +static int metrousb_port_remove(struct usb_serial_port *port) +{ + struct metrousb_private *metro_priv; + + metro_priv = usb_get_serial_port_data(port); + kfree(metro_priv); + + return 0; +} + +static void metrousb_throttle(struct tty_struct *tty) +{ + struct usb_serial_port *port = tty->driver_data; + struct metrousb_private *metro_priv = usb_get_serial_port_data(port); + unsigned long flags = 0; + + dev_dbg(tty->dev, "%s\n", __func__); + + /* Set the private information for the port to stop reading data. */ + spin_lock_irqsave(&metro_priv->lock, flags); + metro_priv->throttled = 1; + spin_unlock_irqrestore(&metro_priv->lock, flags); +} + +static int metrousb_tiocmget(struct tty_struct *tty) +{ + unsigned long control_state = 0; + struct usb_serial_port *port = tty->driver_data; + struct metrousb_private *metro_priv = usb_get_serial_port_data(port); + unsigned long flags = 0; + + dev_dbg(tty->dev, "%s\n", __func__); + + spin_lock_irqsave(&metro_priv->lock, flags); + control_state = metro_priv->control_state; + spin_unlock_irqrestore(&metro_priv->lock, flags); + + return control_state; +} + +static int metrousb_tiocmset(struct tty_struct *tty, + unsigned int set, unsigned int clear) +{ + struct usb_serial_port *port = tty->driver_data; + struct usb_serial *serial = port->serial; + struct metrousb_private *metro_priv = usb_get_serial_port_data(port); + unsigned long flags = 0; + unsigned long control_state = 0; + + dev_dbg(tty->dev, "%s - set=%d, clear=%d\n", __func__, set, clear); + + spin_lock_irqsave(&metro_priv->lock, flags); + control_state = metro_priv->control_state; + + /* Set the RTS and DTR values. */ + if (set & TIOCM_RTS) + control_state |= TIOCM_RTS; + if (set & TIOCM_DTR) + control_state |= TIOCM_DTR; + if (clear & TIOCM_RTS) + control_state &= ~TIOCM_RTS; + if (clear & TIOCM_DTR) + control_state &= ~TIOCM_DTR; + + metro_priv->control_state = control_state; + spin_unlock_irqrestore(&metro_priv->lock, flags); + return metrousb_set_modem_ctrl(serial, control_state); +} + +static void metrousb_unthrottle(struct tty_struct *tty) +{ + struct usb_serial_port *port = tty->driver_data; + struct metrousb_private *metro_priv = usb_get_serial_port_data(port); + unsigned long flags = 0; + int result = 0; + + dev_dbg(tty->dev, "%s\n", __func__); + + /* Set the private information for the port to resume reading data. */ + spin_lock_irqsave(&metro_priv->lock, flags); + metro_priv->throttled = 0; + spin_unlock_irqrestore(&metro_priv->lock, flags); + + /* Submit the urb to read from the port. */ + port->interrupt_in_urb->dev = port->serial->dev; + result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC); + if (result) + dev_err(tty->dev, + "failed submitting interrupt in urb error code=%d\n", + result); +} + +static struct usb_serial_driver metrousb_device = { + .driver = { + .owner = THIS_MODULE, + .name = "metro-usb", + }, + .description = "Metrologic USB to Serial", + .id_table = id_table, + .num_ports = 1, + .open = metrousb_open, + .close = metrousb_cleanup, + .read_int_callback = metrousb_read_int_callback, + .write_int_callback = metrousb_write_int_callback, + .port_probe = metrousb_port_probe, + .port_remove = metrousb_port_remove, + .throttle = metrousb_throttle, + .unthrottle = metrousb_unthrottle, + .tiocmget = metrousb_tiocmget, + .tiocmset = metrousb_tiocmset, +}; + +static struct usb_serial_driver * const serial_drivers[] = { + &metrousb_device, + NULL, +}; + +module_usb_serial_driver(serial_drivers, id_table); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Philip Nicastro"); +MODULE_AUTHOR("Aleksey Babahin <tamerlan311@gmail.com>"); +MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index 7d3bc9a3e2b..dfd728a263d 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -1,6 +1,6 @@ /* * mos7720.c - * Controls the Moschip 7720 usb to dual port serial convertor + * Controls the Moschip 7720 usb to dual port serial converter * * Copyright 2006 Moschip Semiconductor Tech. Ltd. * @@ -22,7 +22,6 @@ */ #include <linux/kernel.h> #include <linux/errno.h> -#include <linux/init.h> #include <linux/slab.h> #include <linux/tty.h> #include <linux/tty_driver.h> @@ -36,21 +35,17 @@ #include <linux/uaccess.h> #include <linux/parport.h> -/* - * Version Information - */ -#define DRIVER_VERSION "2.1" #define DRIVER_AUTHOR "Aspire Communications pvt Ltd." #define DRIVER_DESC "Moschip USB Serial Driver" /* default urb timeout */ -#define MOS_WDR_TIMEOUT (HZ * 5) +#define MOS_WDR_TIMEOUT 5000 #define MOS_MAX_PORT 0x02 #define MOS_WRITE 0x0E #define MOS_READ 0x0D -/* Interrupt Rotinue Defines */ +/* Interrupt Routines Defines */ #define SERIAL_IIR_RLS 0x06 #define SERIAL_IIR_RDA 0x04 #define SERIAL_IIR_CTI 0x0c @@ -66,25 +61,22 @@ struct moschip_port { __u8 shadowMCR; /* last MCR value received */ __u8 shadowMSR; /* last MSR value received */ char open; - struct async_icount icount; struct usb_serial_port *port; /* loop back to the owner */ struct urb *write_urb_pool[NUM_URBS]; }; -static int debug; - static struct usb_serial_driver moschip7720_2port_driver; #define USB_VENDOR_ID_MOSCHIP 0x9710 #define MOSCHIP_DEVICE_ID_7720 0x7720 #define MOSCHIP_DEVICE_ID_7715 0x7715 -static const struct usb_device_id moschip_port_id_table[] = { +static const struct usb_device_id id_table[] = { { USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7720) }, { USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7715) }, { } /* terminating entry */ }; -MODULE_DEVICE_TABLE(usb, moschip_port_id_table); +MODULE_DEVICE_TABLE(usb, id_table); #ifdef CONFIG_USB_SERIAL_MOS7715_PARPORT @@ -97,6 +89,7 @@ struct urbtracker { struct list_head urblist_entry; struct kref ref_count; struct urb *urb; + struct usb_ctrlrequest *setup; }; enum mos7715_pp_modes { @@ -216,7 +209,7 @@ static int write_mos_reg(struct usb_serial *serial, unsigned int serial_portnum, index, NULL, 0, MOS_WDR_TIMEOUT); if (status < 0) dev_err(&usbdev->dev, - "mos7720: usb_control_msg() failed: %d", status); + "mos7720: usb_control_msg() failed: %d\n", status); return status; } @@ -234,11 +227,22 @@ static int read_mos_reg(struct usb_serial *serial, unsigned int serial_portnum, __u8 requesttype = (__u8)0xc0; __u16 index = get_reg_index(reg); __u16 value = get_reg_value(reg, serial_portnum); - int status = usb_control_msg(usbdev, pipe, request, requesttype, value, - index, data, 1, MOS_WDR_TIMEOUT); - if (status < 0) + u8 *buf; + int status; + + buf = kmalloc(1, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + status = usb_control_msg(usbdev, pipe, request, requesttype, value, + index, buf, 1, MOS_WDR_TIMEOUT); + if (status == 1) + *data = *buf; + else if (status < 0) dev_err(&usbdev->dev, - "mos7720: usb_control_msg() failed: %d", status); + "mos7720: usb_control_msg() failed: %d\n", status); + kfree(buf); + return status; } @@ -257,7 +261,6 @@ static void destroy_mos_parport(struct kref *kref) struct mos7715_parport *mos_parport = container_of(kref, struct mos7715_parport, ref_count); - dbg("%s called", __func__); kfree(mos_parport); } @@ -266,8 +269,9 @@ static void destroy_urbtracker(struct kref *kref) struct urbtracker *urbtrack = container_of(kref, struct urbtracker, ref_count); struct mos7715_parport *mos_parport = urbtrack->mos_parport; - dbg("%s called", __func__); + usb_free_urb(urbtrack->urb); + kfree(urbtrack->setup); kfree(urbtrack); kref_put(&mos_parport->ref_count, destroy_mos_parport); } @@ -282,18 +286,19 @@ static void send_deferred_urbs(unsigned long _mos_parport) int ret_val; unsigned long flags; struct mos7715_parport *mos_parport = (void *)_mos_parport; - struct urbtracker *urbtrack; + struct urbtracker *urbtrack, *tmp; struct list_head *cursor, *next; - - dbg("%s called", __func__); + struct device *dev; /* if release function ran, game over */ if (unlikely(mos_parport->serial == NULL)) return; + dev = &mos_parport->serial->dev->dev; + /* try again to get the mutex */ if (!mutex_trylock(&mos_parport->serial->disc_mutex)) { - dbg("%s: rescheduling tasklet", __func__); + dev_dbg(dev, "%s: rescheduling tasklet\n", __func__); tasklet_schedule(&mos_parport->urb_tasklet); return; } @@ -308,20 +313,19 @@ static void send_deferred_urbs(unsigned long _mos_parport) if (list_empty(&mos_parport->deferred_urbs)) { spin_unlock_irqrestore(&mos_parport->listlock, flags); mutex_unlock(&mos_parport->serial->disc_mutex); - dbg("%s: deferred_urbs list empty", __func__); + dev_dbg(dev, "%s: deferred_urbs list empty\n", __func__); return; } /* move contents of deferred_urbs list to active_urbs list and submit */ list_for_each_safe(cursor, next, &mos_parport->deferred_urbs) list_move_tail(cursor, &mos_parport->active_urbs); - list_for_each_entry(urbtrack, &mos_parport->active_urbs, + list_for_each_entry_safe(urbtrack, tmp, &mos_parport->active_urbs, urblist_entry) { ret_val = usb_submit_urb(urbtrack->urb, GFP_ATOMIC); - dbg("%s: urb submitted", __func__); + dev_dbg(dev, "%s: urb submitted\n", __func__); if (ret_val) { - dev_err(&mos_parport->serial->dev->dev, - "usb_submit_urb() failed: %d", ret_val); + dev_err(dev, "usb_submit_urb() failed: %d\n", ret_val); list_del(&urbtrack->urblist_entry); kref_put(&urbtrack->ref_count, destroy_urbtracker); } @@ -335,9 +339,9 @@ static void async_complete(struct urb *urb) { struct urbtracker *urbtrack = urb->context; int status = urb->status; - dbg("%s called", __func__); + if (unlikely(status)) - dbg("%s - nonzero urb status received: %d", __func__, status); + dev_dbg(&urb->dev->dev, "%s - nonzero urb status received: %d\n", __func__, status); /* remove the urbtracker from the active_urbs list */ spin_lock(&urbtrack->mos_parport->listlock); @@ -352,33 +356,35 @@ static int write_parport_reg_nonblock(struct mos7715_parport *mos_parport, struct urbtracker *urbtrack; int ret_val; unsigned long flags; - struct usb_ctrlrequest setup; struct usb_serial *serial = mos_parport->serial; struct usb_device *usbdev = serial->dev; - dbg("%s called", __func__); /* create and initialize the control urb and containing urbtracker */ urbtrack = kmalloc(sizeof(struct urbtracker), GFP_ATOMIC); - if (urbtrack == NULL) { - dev_err(&usbdev->dev, "out of memory"); + if (!urbtrack) return -ENOMEM; - } + kref_get(&mos_parport->ref_count); urbtrack->mos_parport = mos_parport; urbtrack->urb = usb_alloc_urb(0, GFP_ATOMIC); - if (urbtrack->urb == NULL) { - dev_err(&usbdev->dev, "out of urbs"); + if (!urbtrack->urb) { kfree(urbtrack); return -ENOMEM; } - setup.bRequestType = (__u8)0x40; - setup.bRequest = (__u8)0x0e; - setup.wValue = get_reg_value(reg, dummy); - setup.wIndex = get_reg_index(reg); - setup.wLength = 0; + urbtrack->setup = kmalloc(sizeof(*urbtrack->setup), GFP_ATOMIC); + if (!urbtrack->setup) { + usb_free_urb(urbtrack->urb); + kfree(urbtrack); + return -ENOMEM; + } + urbtrack->setup->bRequestType = (__u8)0x40; + urbtrack->setup->bRequest = (__u8)0x0e; + urbtrack->setup->wValue = cpu_to_le16(get_reg_value(reg, dummy)); + urbtrack->setup->wIndex = cpu_to_le16(get_reg_index(reg)); + urbtrack->setup->wLength = 0; usb_fill_control_urb(urbtrack->urb, usbdev, usb_sndctrlpipe(usbdev, 0), - (unsigned char *)&setup, + (unsigned char *)urbtrack->setup, NULL, 0, async_complete, urbtrack); kref_init(&urbtrack->ref_count); INIT_LIST_HEAD(&urbtrack->urblist_entry); @@ -393,7 +399,7 @@ static int write_parport_reg_nonblock(struct mos7715_parport *mos_parport, &mos_parport->deferred_urbs); spin_unlock_irqrestore(&mos_parport->listlock, flags); tasklet_schedule(&mos_parport->urb_tasklet); - dbg("tasklet scheduled"); + dev_dbg(&usbdev->dev, "tasklet scheduled\n"); return 0; } @@ -412,7 +418,7 @@ static int write_parport_reg_nonblock(struct mos7715_parport *mos_parport, mutex_unlock(&serial->disc_mutex); if (ret_val) { dev_err(&usbdev->dev, - "%s: submit_urb() failed: %d", __func__, ret_val); + "%s: submit_urb() failed: %d\n", __func__, ret_val); spin_lock_irqsave(&mos_parport->listlock, flags); list_del(&urbtrack->urblist_entry); spin_unlock_irqrestore(&mos_parport->listlock, flags); @@ -431,7 +437,7 @@ static int write_parport_reg_nonblock(struct mos7715_parport *mos_parport, * not called the release function yet because someone has a serial port open. * The shared release_lock prevents the first, and the mutex and disconnected * flag maintained by usbserial covers the second. We also use the msg_pending - * flag to ensure that all synchronous usb messgage calls have completed before + * flag to ensure that all synchronous usb message calls have completed before * our release function can return. */ static int parport_prologue(struct parport *pp) @@ -446,7 +452,7 @@ static int parport_prologue(struct parport *pp) return -1; } mos_parport->msg_pending = true; /* synch usb call pending */ - INIT_COMPLETION(mos_parport->syncmsg_compl); + reinit_completion(&mos_parport->syncmsg_compl); spin_unlock(&release_lock); mutex_lock(&mos_parport->serial->disc_mutex); @@ -462,7 +468,7 @@ static int parport_prologue(struct parport *pp) } /* - * This is the the common bottom part of all parallel port functions that send + * This is the common bottom part of all parallel port functions that send * synchronous messages to the device. */ static inline void parport_epilogue(struct parport *pp) @@ -476,7 +482,7 @@ static inline void parport_epilogue(struct parport *pp) static void parport_mos7715_write_data(struct parport *pp, unsigned char d) { struct mos7715_parport *mos_parport = pp->private_data; - dbg("%s called: %2.2x", __func__, d); + if (parport_prologue(pp) < 0) return; mos7715_change_mode(mos_parport, SPP); @@ -488,7 +494,7 @@ static unsigned char parport_mos7715_read_data(struct parport *pp) { struct mos7715_parport *mos_parport = pp->private_data; unsigned char d; - dbg("%s called", __func__); + if (parport_prologue(pp) < 0) return 0; read_mos_reg(mos_parport->serial, dummy, DPR, &d); @@ -500,7 +506,7 @@ static void parport_mos7715_write_control(struct parport *pp, unsigned char d) { struct mos7715_parport *mos_parport = pp->private_data; __u8 data; - dbg("%s called: %2.2x", __func__, d); + if (parport_prologue(pp) < 0) return; data = ((__u8)d & 0x0f) | (mos_parport->shadowDCR & 0xf0); @@ -513,7 +519,7 @@ static unsigned char parport_mos7715_read_control(struct parport *pp) { struct mos7715_parport *mos_parport = pp->private_data; __u8 dcr; - dbg("%s called", __func__); + spin_lock(&release_lock); mos_parport = pp->private_data; if (unlikely(mos_parport == NULL)) { @@ -531,7 +537,7 @@ static unsigned char parport_mos7715_frob_control(struct parport *pp, { struct mos7715_parport *mos_parport = pp->private_data; __u8 dcr; - dbg("%s called", __func__); + mask &= 0x0f; val &= 0x0f; if (parport_prologue(pp) < 0) @@ -547,7 +553,7 @@ static unsigned char parport_mos7715_read_status(struct parport *pp) { unsigned char status; struct mos7715_parport *mos_parport = pp->private_data; - dbg("%s called", __func__); + spin_lock(&release_lock); mos_parport = pp->private_data; if (unlikely(mos_parport == NULL)) { /* release called */ @@ -561,17 +567,16 @@ static unsigned char parport_mos7715_read_status(struct parport *pp) static void parport_mos7715_enable_irq(struct parport *pp) { - dbg("%s called", __func__); } + static void parport_mos7715_disable_irq(struct parport *pp) { - dbg("%s called", __func__); } static void parport_mos7715_data_forward(struct parport *pp) { struct mos7715_parport *mos_parport = pp->private_data; - dbg("%s called", __func__); + if (parport_prologue(pp) < 0) return; mos7715_change_mode(mos_parport, PS2); @@ -583,7 +588,7 @@ static void parport_mos7715_data_forward(struct parport *pp) static void parport_mos7715_data_reverse(struct parport *pp) { struct mos7715_parport *mos_parport = pp->private_data; - dbg("%s called", __func__); + if (parport_prologue(pp) < 0) return; mos7715_change_mode(mos_parport, PS2); @@ -595,7 +600,6 @@ static void parport_mos7715_data_reverse(struct parport *pp) static void parport_mos7715_init_state(struct pardevice *dev, struct parport_state *s) { - dbg("%s called", __func__); s->u.pc.ctr = DCR_INIT_VAL; s->u.pc.ecr = ECR_INIT_VAL; } @@ -605,7 +609,7 @@ static void parport_mos7715_save_state(struct parport *pp, struct parport_state *s) { struct mos7715_parport *mos_parport; - dbg("%s called", __func__); + spin_lock(&release_lock); mos_parport = pp->private_data; if (unlikely(mos_parport == NULL)) { /* release called */ @@ -622,7 +626,7 @@ static void parport_mos7715_restore_state(struct parport *pp, struct parport_state *s) { struct mos7715_parport *mos_parport; - dbg("%s called", __func__); + spin_lock(&release_lock); mos_parport = pp->private_data; if (unlikely(mos_parport == NULL)) { /* release called */ @@ -641,7 +645,7 @@ static size_t parport_mos7715_write_compat(struct parport *pp, int retval; struct mos7715_parport *mos_parport = pp->private_data; int actual_len; - dbg("%s called: %u chars", __func__, (unsigned int)len); + if (parport_prologue(pp) < 0) return 0; mos7715_change_mode(mos_parport, PPF); @@ -652,7 +656,7 @@ static size_t parport_mos7715_write_compat(struct parport *pp, parport_epilogue(pp); if (retval) { dev_err(&mos_parport->serial->dev->dev, - "mos7720: usb_bulk_msg() failed: %d", retval); + "mos7720: usb_bulk_msg() failed: %d\n", retval); return 0; } return actual_len; @@ -695,10 +699,9 @@ static int mos7715_parport_init(struct usb_serial *serial) /* allocate and initialize parallel port control struct */ mos_parport = kzalloc(sizeof(struct mos7715_parport), GFP_KERNEL); - if (mos_parport == NULL) { - dbg("mos7715_parport_init: kzalloc failed"); + if (!mos_parport) return -ENOMEM; - } + mos_parport->msg_pending = false; kref_init(&mos_parport->ref_count); spin_lock_init(&mos_parport->listlock); @@ -749,6 +752,7 @@ static void mos7720_interrupt_callback(struct urb *urb) int result; int length; int status = urb->status; + struct device *dev = &urb->dev->dev; __u8 *data; __u8 sp1; __u8 sp2; @@ -761,12 +765,10 @@ static void mos7720_interrupt_callback(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", __func__, - status); + dev_dbg(dev, "%s - urb shutting down with status: %d\n", __func__, status); return; default: - dbg("%s - nonzero urb status received: %d", __func__, - status); + dev_dbg(dev, "%s - nonzero urb status received: %d\n", __func__, status); goto exit; } @@ -783,7 +785,7 @@ static void mos7720_interrupt_callback(struct urb *urb) * oneukum 2007-03-14 */ if (unlikely(length != 4)) { - dbg("Wrong data !!!"); + dev_dbg(dev, "Wrong data !!!\n"); return; } @@ -792,31 +794,29 @@ static void mos7720_interrupt_callback(struct urb *urb) if ((sp1 | sp2) & 0x01) { /* No Interrupt Pending in both the ports */ - dbg("No Interrupt !!!"); + dev_dbg(dev, "No Interrupt !!!\n"); } else { switch (sp1 & 0x0f) { case SERIAL_IIR_RLS: - dbg("Serial Port 1: Receiver status error or address " - "bit detected in 9-bit mode\n"); + dev_dbg(dev, "Serial Port 1: Receiver status error or address bit detected in 9-bit mode\n"); break; case SERIAL_IIR_CTI: - dbg("Serial Port 1: Receiver time out"); + dev_dbg(dev, "Serial Port 1: Receiver time out\n"); break; case SERIAL_IIR_MS: - /* dbg("Serial Port 1: Modem status change"); */ + /* dev_dbg(dev, "Serial Port 1: Modem status change\n"); */ break; } switch (sp2 & 0x0f) { case SERIAL_IIR_RLS: - dbg("Serial Port 2: Receiver status error or address " - "bit detected in 9-bit mode"); + dev_dbg(dev, "Serial Port 2: Receiver status error or address bit detected in 9-bit mode\n"); break; case SERIAL_IIR_CTI: - dbg("Serial Port 2: Receiver time out"); + dev_dbg(dev, "Serial Port 2: Receiver time out\n"); break; case SERIAL_IIR_MS: - /* dbg("Serial Port 2: Modem status change"); */ + /* dev_dbg(dev, "Serial Port 2: Modem status change\n"); */ break; } } @@ -824,9 +824,7 @@ static void mos7720_interrupt_callback(struct urb *urb) exit: result = usb_submit_urb(urb, GFP_ATOMIC); if (result) - dev_err(&urb->dev->dev, - "%s - Error %d submitting control urb\n", - __func__, result); + dev_err(dev, "%s - Error %d submitting control urb\n", __func__, result); } /* @@ -839,6 +837,7 @@ static void mos7715_interrupt_callback(struct urb *urb) int result; int length; int status = urb->status; + struct device *dev = &urb->dev->dev; __u8 *data; __u8 iir; @@ -851,12 +850,10 @@ static void mos7715_interrupt_callback(struct urb *urb) case -ESHUTDOWN: case -ENODEV: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", __func__, - status); + dev_dbg(dev, "%s - urb shutting down with status: %d\n", __func__, status); return; default: - dbg("%s - nonzero urb status received: %d", __func__, - status); + dev_dbg(dev, "%s - nonzero urb status received: %d\n", __func__, status); goto exit; } @@ -870,7 +867,7 @@ static void mos7715_interrupt_callback(struct urb *urb) * Byte 4: FIFO status for both */ if (unlikely(length != 4)) { - dbg("Wrong data !!!"); + dev_dbg(dev, "Wrong data !!!\n"); return; } @@ -878,14 +875,13 @@ static void mos7715_interrupt_callback(struct urb *urb) if (!(iir & 0x01)) { /* serial port interrupt pending */ switch (iir & 0x0f) { case SERIAL_IIR_RLS: - dbg("Serial Port: Receiver status error or address " - "bit detected in 9-bit mode\n"); + dev_dbg(dev, "Serial Port: Receiver status error or address bit detected in 9-bit mode\n"); break; case SERIAL_IIR_CTI: - dbg("Serial Port: Receiver time out"); + dev_dbg(dev, "Serial Port: Receiver time out\n"); break; case SERIAL_IIR_MS: - /* dbg("Serial Port: Modem status change"); */ + /* dev_dbg(dev, "Serial Port: Modem status change\n"); */ break; } } @@ -903,9 +899,7 @@ static void mos7715_interrupt_callback(struct urb *urb) exit: result = usb_submit_urb(urb, GFP_ATOMIC); if (result) - dev_err(&urb->dev->dev, - "%s - Error %d submitting control urb\n", - __func__, result); + dev_err(dev, "%s - Error %d submitting control urb\n", __func__, result); } /* @@ -918,39 +912,28 @@ static void mos7720_bulk_in_callback(struct urb *urb) int retval; unsigned char *data ; struct usb_serial_port *port; - struct tty_struct *tty; int status = urb->status; if (status) { - dbg("nonzero read bulk status received: %d", status); + dev_dbg(&urb->dev->dev, "nonzero read bulk status received: %d\n", status); return; } port = urb->context; - dbg("Entering...%s", __func__); + dev_dbg(&port->dev, "Entering...%s\n", __func__); data = urb->transfer_buffer; - tty = tty_port_tty_get(&port->port); - if (tty && urb->actual_length) { - tty_insert_flip_string(tty, data, urb->actual_length); - tty_flip_buffer_push(tty); - } - tty_kref_put(tty); - - if (!port->read_urb) { - dbg("URB KILLED !!!"); - return; + if (urb->actual_length) { + tty_insert_flip_string(&port->port, data, urb->actual_length); + tty_flip_buffer_push(&port->port); } if (port->read_urb->status != -EINPROGRESS) { - port->read_urb->dev = port->serial->dev; - retval = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (retval) - dbg("usb_submit_urb(read bulk) failed, retval = %d", - retval); + dev_dbg(&port->dev, "usb_submit_urb(read bulk) failed, retval = %d\n", retval); } } @@ -962,25 +945,21 @@ static void mos7720_bulk_in_callback(struct urb *urb) static void mos7720_bulk_out_data_callback(struct urb *urb) { struct moschip_port *mos7720_port; - struct tty_struct *tty; int status = urb->status; if (status) { - dbg("nonzero write bulk status received:%d", status); + dev_dbg(&urb->dev->dev, "nonzero write bulk status received:%d\n", status); return; } mos7720_port = urb->context; if (!mos7720_port) { - dbg("NULL mos7720_port pointer"); + dev_dbg(&urb->dev->dev, "NULL mos7720_port pointer\n"); return ; } - tty = tty_port_tty_get(&mos7720_port->port->port); - - if (tty && mos7720_port->open) - tty_wakeup(tty); - tty_kref_put(tty); + if (mos7720_port->open) + tty_port_tty_wakeup(&mos7720_port->port->port); } /* @@ -1014,7 +993,6 @@ static int mos77xx_calc_num_ports(struct usb_serial *serial) static int mos7720_open(struct tty_struct *tty, struct usb_serial_port *port) { struct usb_serial *serial; - struct usb_serial_port *port0; struct urb *urb; struct moschip_port *mos7720_port; int response; @@ -1029,8 +1007,6 @@ static int mos7720_open(struct tty_struct *tty, struct usb_serial_port *port) if (mos7720_port == NULL) return -ENODEV; - port0 = serial->port[0]; - usb_clear_halt(serial->dev, port->write_urb->pipe); usb_clear_halt(serial->dev, port->read_urb->pipe); @@ -1038,18 +1014,12 @@ static int mos7720_open(struct tty_struct *tty, struct usb_serial_port *port) for (j = 0; j < NUM_URBS; ++j) { urb = usb_alloc_urb(0, GFP_KERNEL); mos7720_port->write_urb_pool[j] = urb; - - if (urb == NULL) { - dev_err(&port->dev, "No more urbs???\n"); + if (!urb) continue; - } urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL); if (!urb->transfer_buffer) { - dev_err(&port->dev, - "%s-out of memory for urb buffers.\n", - __func__); usb_free_urb(mos7720_port->write_urb_pool[j]); mos7720_port->write_urb_pool[j] = NULL; continue; @@ -1074,12 +1044,10 @@ static int mos7720_open(struct tty_struct *tty, struct usb_serial_port *port) * * 0x08 : SP1/2 Control Reg */ - port_number = port->number - port->serial->minor; + port_number = port->port_number; read_mos_reg(serial, port_number, LSR, &data); - dbg("SS::%p LSR:%x", mos7720_port, data); - - dbg("Check:Sending Command .........."); + dev_dbg(&port->dev, "SS::%p LSR:%x\n", mos7720_port, data); write_mos_reg(serial, dummy, SP1_REG, 0x02); write_mos_reg(serial, dummy, SP2_REG, 0x02); @@ -1095,7 +1063,7 @@ static int mos7720_open(struct tty_struct *tty, struct usb_serial_port *port) write_mos_reg(serial, port_number, SP_CONTROL_REG, 0x00); read_mos_reg(serial, dummy, SP_CONTROL_REG, &data); - data = data | (port->number - port->serial->minor + 1); + data = data | (port->port_number + 1); write_mos_reg(serial, dummy, SP_CONTROL_REG, data); mos7720_port->shadowLCR = 0x83; write_mos_reg(serial, port_number, LCR, mos7720_port->shadowLCR); @@ -1110,9 +1078,6 @@ static int mos7720_open(struct tty_struct *tty, struct usb_serial_port *port) dev_err(&port->dev, "%s - Error %d submitting read urb\n", __func__, response); - /* initialize our icount structure */ - memset(&(mos7720_port->icount), 0x00, sizeof(mos7720_port->icount)); - /* initialize our port settings */ mos7720_port->shadowMCR = UART_MCR_OUT2; /* Must set to enable ints! */ @@ -1138,20 +1103,16 @@ static int mos7720_chars_in_buffer(struct tty_struct *tty) int chars = 0; struct moschip_port *mos7720_port; - dbg("%s:entering ...........", __func__); - mos7720_port = usb_get_serial_port_data(port); - if (mos7720_port == NULL) { - dbg("%s:leaving ...........", __func__); + if (mos7720_port == NULL) return 0; - } for (i = 0; i < NUM_URBS; ++i) { if (mos7720_port->write_urb_pool[i] && mos7720_port->write_urb_pool[i]->status == -EINPROGRESS) chars += URB_TRANSFER_BUFFER_SIZE; } - dbg("%s - returns %d", __func__, chars); + dev_dbg(&port->dev, "%s - returns %d\n", __func__, chars); return chars; } @@ -1161,8 +1122,6 @@ static void mos7720_close(struct usb_serial_port *port) struct moschip_port *mos7720_port; int j; - dbg("mos7720_close:entering..."); - serial = port->serial; mos7720_port = usb_get_serial_port_data(port); @@ -1182,24 +1141,13 @@ static void mos7720_close(struct usb_serial_port *port) /* While closing port, shutdown all bulk read, write * * and interrupt read if they exists, otherwise nop */ - dbg("Shutdown bulk write"); usb_kill_urb(port->write_urb); - dbg("Shutdown bulk read"); usb_kill_urb(port->read_urb); - mutex_lock(&serial->disc_mutex); - /* these commands must not be issued if the device has - * been disconnected */ - if (!serial->disconnected) { - write_mos_reg(serial, port->number - port->serial->minor, - MCR, 0x00); - write_mos_reg(serial, port->number - port->serial->minor, - IER, 0x00); - } - mutex_unlock(&serial->disc_mutex); - mos7720_port->open = 0; + write_mos_reg(serial, port->port_number, MCR, 0x00); + write_mos_reg(serial, port->port_number, IER, 0x00); - dbg("Leaving %s", __func__); + mos7720_port->open = 0; } static void mos7720_break(struct tty_struct *tty, int break_state) @@ -1209,8 +1157,6 @@ static void mos7720_break(struct tty_struct *tty, int break_state) struct usb_serial *serial; struct moschip_port *mos7720_port; - dbg("Entering %s", __func__); - serial = port->serial; mos7720_port = usb_get_serial_port_data(port); @@ -1223,8 +1169,7 @@ static void mos7720_break(struct tty_struct *tty, int break_state) data = mos7720_port->shadowLCR & ~UART_LCR_SBC; mos7720_port->shadowLCR = data; - write_mos_reg(serial, port->number - port->serial->minor, - LCR, mos7720_port->shadowLCR); + write_mos_reg(serial, port->port_number, LCR, mos7720_port->shadowLCR); } /* @@ -1241,13 +1186,9 @@ static int mos7720_write_room(struct tty_struct *tty) int room = 0; int i; - dbg("%s:entering ...........", __func__); - mos7720_port = usb_get_serial_port_data(port); - if (mos7720_port == NULL) { - dbg("%s:leaving ...........", __func__); + if (mos7720_port == NULL) return -ENODEV; - } /* FIXME: Locking */ for (i = 0; i < NUM_URBS; ++i) { @@ -1256,7 +1197,7 @@ static int mos7720_write_room(struct tty_struct *tty) room += URB_TRANSFER_BUFFER_SIZE; } - dbg("%s - returns %d", __func__, room); + dev_dbg(&port->dev, "%s - returns %d\n", __func__, room); return room; } @@ -1273,15 +1214,11 @@ static int mos7720_write(struct tty_struct *tty, struct usb_serial_port *port, struct urb *urb; const unsigned char *current_position = data; - dbg("%s:entering ...........", __func__); - serial = port->serial; mos7720_port = usb_get_serial_port_data(port); - if (mos7720_port == NULL) { - dbg("mos7720_port is NULL"); + if (mos7720_port == NULL) return -ENODEV; - } /* try to find a free urb in the list */ urb = NULL; @@ -1290,29 +1227,26 @@ static int mos7720_write(struct tty_struct *tty, struct usb_serial_port *port, if (mos7720_port->write_urb_pool[i] && mos7720_port->write_urb_pool[i]->status != -EINPROGRESS) { urb = mos7720_port->write_urb_pool[i]; - dbg("URB:%d", i); + dev_dbg(&port->dev, "URB:%d\n", i); break; } } if (urb == NULL) { - dbg("%s - no more free urbs", __func__); + dev_dbg(&port->dev, "%s - no more free urbs\n", __func__); goto exit; } if (urb->transfer_buffer == NULL) { urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL); - if (urb->transfer_buffer == NULL) { - dev_err(&port->dev, "%s no more kernel memory...\n", - __func__); + if (!urb->transfer_buffer) goto exit; - } } transfer_size = min(count, URB_TRANSFER_BUFFER_SIZE); memcpy(urb->transfer_buffer, current_position, transfer_size); - usb_serial_debug_data(debug, &port->dev, __func__, transfer_size, + usb_serial_debug_data(&port->dev, __func__, transfer_size, urb->transfer_buffer); /* fill urb with data and submit */ @@ -1325,7 +1259,7 @@ static int mos7720_write(struct tty_struct *tty, struct usb_serial_port *port, /* send it down the pipe */ status = usb_submit_urb(urb, GFP_ATOMIC); if (status) { - dev_err(&port->dev, "%s - usb_submit_urb(write bulk) failed " + dev_err_console(port, "%s - usb_submit_urb(write bulk) failed " "with status = %d\n", __func__, status); bytes_sent = status; goto exit; @@ -1342,20 +1276,16 @@ static void mos7720_throttle(struct tty_struct *tty) struct moschip_port *mos7720_port; int status; - dbg("%s- port %d", __func__, port->number); - mos7720_port = usb_get_serial_port_data(port); if (mos7720_port == NULL) return; if (!mos7720_port->open) { - dbg("port not opened"); + dev_dbg(&port->dev, "%s - port not opened\n", __func__); return; } - dbg("%s: Entering ..........", __func__); - /* if we are implementing XON/XOFF, send the stop character */ if (I_IXOFF(tty)) { unsigned char stop_char = STOP_CHAR(tty); @@ -1365,10 +1295,10 @@ static void mos7720_throttle(struct tty_struct *tty) } /* if we are implementing RTS/CTS, toggle that line */ - if (tty->termios->c_cflag & CRTSCTS) { + if (tty->termios.c_cflag & CRTSCTS) { mos7720_port->shadowMCR &= ~UART_MCR_RTS; - write_mos_reg(port->serial, port->number - port->serial->minor, - MCR, mos7720_port->shadowMCR); + write_mos_reg(port->serial, port->port_number, MCR, + mos7720_port->shadowMCR); if (status != 0) return; } @@ -1384,12 +1314,10 @@ static void mos7720_unthrottle(struct tty_struct *tty) return; if (!mos7720_port->open) { - dbg("%s - port not opened", __func__); + dev_dbg(&port->dev, "%s - port not opened\n", __func__); return; } - dbg("%s: Entering ..........", __func__); - /* if we are implementing XON/XOFF, send the start character */ if (I_IXOFF(tty)) { unsigned char start_char = START_CHAR(tty); @@ -1399,10 +1327,10 @@ static void mos7720_unthrottle(struct tty_struct *tty) } /* if we are implementing RTS/CTS, toggle that line */ - if (tty->termios->c_cflag & CRTSCTS) { + if (tty->termios.c_cflag & CRTSCTS) { mos7720_port->shadowMCR |= UART_MCR_RTS; - write_mos_reg(port->serial, port->number - port->serial->minor, - MCR, mos7720_port->shadowMCR); + write_mos_reg(port->serial, port->port_number, MCR, + mos7720_port->shadowMCR); if (status != 0) return; } @@ -1425,8 +1353,8 @@ static int set_higher_rates(struct moschip_port *mos7720_port, /*********************************************** * Init Sequence for higher rates ***********************************************/ - dbg("Sending Setting Commands .........."); - port_number = port->number - port->serial->minor; + dev_dbg(&port->dev, "Sending Setting Commands ..........\n"); + port_number = port->port_number; write_mos_reg(serial, port_number, IER, 0x00); write_mos_reg(serial, port_number, FCR, 0x00); @@ -1494,7 +1422,7 @@ static struct divisor_table_entry divisor_table[] = { * this function calculates the proper baud rate divisor for the specified * baud rate. *****************************************************************************/ -static int calc_baud_rate_divisor(int baudrate, int *divisor) +static int calc_baud_rate_divisor(struct usb_serial_port *port, int baudrate, int *divisor) { int i; __u16 custom; @@ -1502,7 +1430,7 @@ static int calc_baud_rate_divisor(int baudrate, int *divisor) __u16 round; - dbg("%s - %d", __func__, baudrate); + dev_dbg(&port->dev, "%s - %d\n", __func__, baudrate); for (i = 0; i < ARRAY_SIZE(divisor_table); i++) { if (divisor_table[i].baudrate == baudrate) { @@ -1524,11 +1452,11 @@ static int calc_baud_rate_divisor(int baudrate, int *divisor) custom++; *divisor = custom; - dbg("Baud %d = %d", baudrate, custom); + dev_dbg(&port->dev, "Baud %d = %d\n", baudrate, custom); return 0; } - dbg("Baud calculation Failed..."); + dev_dbg(&port->dev, "Baud calculation Failed...\n"); return -EINVAL; } @@ -1552,13 +1480,11 @@ static int send_cmd_write_baud_rate(struct moschip_port *mos7720_port, port = mos7720_port->port; serial = port->serial; - dbg("%s: Entering ..........", __func__); - - number = port->number - port->serial->minor; - dbg("%s - port = %d, baud = %d", __func__, port->number, baudrate); + number = port->port_number; + dev_dbg(&port->dev, "%s - baud = %d\n", __func__, baudrate); /* Calculate the Divisor */ - status = calc_baud_rate_divisor(baudrate, &divisor); + status = calc_baud_rate_divisor(port, baudrate, &divisor); if (status) { dev_err(&port->dev, "%s - bad baud rate\n", __func__); return status; @@ -1605,23 +1531,19 @@ static void change_port_settings(struct tty_struct *tty, port = mos7720_port->port; serial = port->serial; - port_number = port->number - port->serial->minor; - - dbg("%s - port %d", __func__, port->number); + port_number = port->port_number; if (!mos7720_port->open) { - dbg("%s - port not opened", __func__); + dev_dbg(&port->dev, "%s - port not opened\n", __func__); return; } - dbg("%s: Entering ..........", __func__); - lData = UART_LCR_WLEN8; lStop = 0x00; /* 1 stop bit */ lParity = 0x00; /* No parity */ - cflag = tty->termios->c_cflag; - iflag = tty->termios->c_iflag; + cflag = tty->termios.c_cflag; + iflag = tty->termios.c_iflag; /* Change the number of bits */ switch (cflag & CSIZE) { @@ -1649,14 +1571,14 @@ static void change_port_settings(struct tty_struct *tty, if (cflag & PARENB) { if (cflag & PARODD) { lParity = UART_LCR_PARITY; - dbg("%s - parity = odd", __func__); + dev_dbg(&port->dev, "%s - parity = odd\n", __func__); } else { lParity = (UART_LCR_EPAR | UART_LCR_PARITY); - dbg("%s - parity = even", __func__); + dev_dbg(&port->dev, "%s - parity = even\n", __func__); } } else { - dbg("%s - parity = none", __func__); + dev_dbg(&port->dev, "%s - parity = none\n", __func__); } if (cflag & CMSPAR) @@ -1665,10 +1587,10 @@ static void change_port_settings(struct tty_struct *tty, /* Change the Stop bit */ if (cflag & CSTOPB) { lStop = UART_LCR_STOP; - dbg("%s - stop bits = 2", __func__); + dev_dbg(&port->dev, "%s - stop bits = 2\n", __func__); } else { lStop = 0x00; - dbg("%s - stop bits = 1", __func__); + dev_dbg(&port->dev, "%s - stop bits = 1\n", __func__); } #define LCR_BITS_MASK 0x03 /* Mask for bits/char field */ @@ -1700,7 +1622,7 @@ static void change_port_settings(struct tty_struct *tty, mos7720_port->shadowMCR |= (UART_MCR_XONANY); /* To set hardware flow control to the specified * * serial port, in SP1/2_CONTROL_REG */ - if (port->number) + if (port_number) write_mos_reg(serial, dummy, SP_CONTROL_REG, 0x01); else write_mos_reg(serial, dummy, SP_CONTROL_REG, 0x02); @@ -1714,7 +1636,7 @@ static void change_port_settings(struct tty_struct *tty, baud = tty_get_baud_rate(tty); if (!baud) { /* pick a default, any default... */ - dbg("Picked default baud..."); + dev_dbg(&port->dev, "Picked default baud...\n"); baud = 9600; } @@ -1725,7 +1647,7 @@ static void change_port_settings(struct tty_struct *tty, return; } - dbg("%s - baud rate = %d", __func__, baud); + dev_dbg(&port->dev, "%s - baud rate = %d\n", __func__, baud); status = send_cmd_write_baud_rate(mos7720_port, baud); /* FIXME: needs to write actual resulting baud back not just blindly do so */ @@ -1735,12 +1657,9 @@ static void change_port_settings(struct tty_struct *tty, write_mos_reg(serial, port_number, IER, 0x0c); if (port->read_urb->status != -EINPROGRESS) { - port->read_urb->dev = serial->dev; - status = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (status) - dbg("usb_submit_urb(read bulk) failed, status = %d", - status); + dev_dbg(&port->dev, "usb_submit_urb(read bulk) failed, status = %d\n", status); } } @@ -1765,38 +1684,27 @@ static void mos7720_set_termios(struct tty_struct *tty, return; if (!mos7720_port->open) { - dbg("%s - port not opened", __func__); + dev_dbg(&port->dev, "%s - port not opened\n", __func__); return; } - dbg("%s\n", "setting termios - ASPIRE"); - - cflag = tty->termios->c_cflag; + dev_dbg(&port->dev, "setting termios - ASPIRE\n"); - dbg("%s - cflag %08x iflag %08x", __func__, - tty->termios->c_cflag, - RELEVANT_IFLAG(tty->termios->c_iflag)); + cflag = tty->termios.c_cflag; - dbg("%s - old cflag %08x old iflag %08x", __func__, - old_termios->c_cflag, - RELEVANT_IFLAG(old_termios->c_iflag)); + dev_dbg(&port->dev, "%s - cflag %08x iflag %08x\n", __func__, + tty->termios.c_cflag, RELEVANT_IFLAG(tty->termios.c_iflag)); - dbg("%s - port %d", __func__, port->number); + dev_dbg(&port->dev, "%s - old cflag %08x old iflag %08x\n", __func__, + old_termios->c_cflag, RELEVANT_IFLAG(old_termios->c_iflag)); /* change the port settings to the new ones specified */ change_port_settings(tty, mos7720_port, old_termios); - if (!port->read_urb) { - dbg("%s", "URB KILLED !!!!!"); - return; - } - if (port->read_urb->status != -EINPROGRESS) { - port->read_urb->dev = serial->dev; status = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (status) - dbg("usb_submit_urb(read bulk) failed, status = %d", - status); + dev_dbg(&port->dev, "usb_submit_urb(read bulk) failed, status = %d\n", status); } } @@ -1816,7 +1724,7 @@ static int get_lsr_info(struct tty_struct *tty, struct usb_serial_port *port = tty->driver_data; unsigned int result = 0; unsigned char data = 0; - int port_number = port->number - port->serial->minor; + int port_number = port->port_number; int count; count = mos7720_chars_in_buffer(tty); @@ -1824,7 +1732,7 @@ static int get_lsr_info(struct tty_struct *tty, read_mos_reg(port->serial, port_number, LSR, &data); if ((data & (UART_LSR_TEMT | UART_LSR_THRE)) == (UART_LSR_TEMT | UART_LSR_THRE)) { - dbg("%s -- Empty", __func__); + dev_dbg(&port->dev, "%s -- Empty\n", __func__); result = TIOCSER_TEMT; } } @@ -1833,7 +1741,7 @@ static int get_lsr_info(struct tty_struct *tty, return 0; } -static int mos7720_tiocmget(struct tty_struct *tty, struct file *file) +static int mos7720_tiocmget(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; struct moschip_port *mos7720_port = usb_get_serial_port_data(port); @@ -1841,8 +1749,6 @@ static int mos7720_tiocmget(struct tty_struct *tty, struct file *file) unsigned int mcr ; unsigned int msr ; - dbg("%s - port %d", __func__, port->number); - mcr = mos7720_port->shadowMCR; msr = mos7720_port->shadowMSR; @@ -1853,19 +1759,15 @@ static int mos7720_tiocmget(struct tty_struct *tty, struct file *file) | ((msr & UART_MSR_RI) ? TIOCM_RI : 0) /* 0x080 */ | ((msr & UART_MSR_DSR) ? TIOCM_DSR : 0); /* 0x100 */ - dbg("%s -- %x", __func__, result); - return result; } -static int mos7720_tiocmset(struct tty_struct *tty, struct file *file, +static int mos7720_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) { struct usb_serial_port *port = tty->driver_data; struct moschip_port *mos7720_port = usb_get_serial_port_data(port); unsigned int mcr ; - dbg("%s - port %d", __func__, port->number); - dbg("he was at tiocmget"); mcr = mos7720_port->shadowMCR; @@ -1884,36 +1786,9 @@ static int mos7720_tiocmset(struct tty_struct *tty, struct file *file, mcr &= ~UART_MCR_LOOP; mos7720_port->shadowMCR = mcr; - write_mos_reg(port->serial, port->number - port->serial->minor, - MCR, mos7720_port->shadowMCR); - - return 0; -} - -static int mos7720_get_icount(struct tty_struct *tty, - struct serial_icounter_struct *icount) -{ - struct usb_serial_port *port = tty->driver_data; - struct moschip_port *mos7720_port; - struct async_icount cnow; + write_mos_reg(port->serial, port->port_number, MCR, + mos7720_port->shadowMCR); - mos7720_port = usb_get_serial_port_data(port); - cnow = mos7720_port->icount; - - icount->cts = cnow.cts; - icount->dsr = cnow.dsr; - icount->rng = cnow.rng; - icount->dcd = cnow.dcd; - icount->rx = cnow.rx; - icount->tx = cnow.tx; - icount->frame = cnow.frame; - icount->overrun = cnow.overrun; - icount->parity = cnow.parity; - icount->brk = cnow.brk; - icount->buf_overrun = cnow.buf_overrun; - - dbg("%s (%d) TIOCGICOUNT RX=%d, TX=%d", __func__, - port->number, icount->rx, icount->tx); return 0; } @@ -1956,8 +1831,8 @@ static int set_modem_info(struct moschip_port *mos7720_port, unsigned int cmd, } mos7720_port->shadowMCR = mcr; - write_mos_reg(port->serial, port->number - port->serial->minor, - MCR, mos7720_port->shadowMCR); + write_mos_reg(port->serial, port->port_number, MCR, + mos7720_port->shadowMCR); return 0; } @@ -1973,8 +1848,8 @@ static int get_serial_info(struct moschip_port *mos7720_port, memset(&tmp, 0, sizeof(tmp)); tmp.type = PORT_16550A; - tmp.line = mos7720_port->port->serial->minor; - tmp.port = mos7720_port->port->number; + tmp.line = mos7720_port->port->minor; + tmp.port = mos7720_port->port->port_number; tmp.irq = 0; tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ; tmp.xmit_fifo_size = NUM_URBS * URB_TRANSFER_BUFFER_SIZE; @@ -1987,60 +1862,33 @@ static int get_serial_info(struct moschip_port *mos7720_port, return 0; } -static int mos7720_ioctl(struct tty_struct *tty, struct file *file, +static int mos7720_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { struct usb_serial_port *port = tty->driver_data; struct moschip_port *mos7720_port; - struct async_icount cnow; - struct async_icount cprev; mos7720_port = usb_get_serial_port_data(port); if (mos7720_port == NULL) return -ENODEV; - dbg("%s - port %d, cmd = 0x%x", __func__, port->number, cmd); - switch (cmd) { case TIOCSERGETLSR: - dbg("%s (%d) TIOCSERGETLSR", __func__, port->number); + dev_dbg(&port->dev, "%s TIOCSERGETLSR\n", __func__); return get_lsr_info(tty, mos7720_port, (unsigned int __user *)arg); - return 0; /* FIXME: These should be using the mode methods */ case TIOCMBIS: case TIOCMBIC: - dbg("%s (%d) TIOCMSET/TIOCMBIC/TIOCMSET", - __func__, port->number); + dev_dbg(&port->dev, "%s TIOCMSET/TIOCMBIC/TIOCMSET\n", __func__); return set_modem_info(mos7720_port, cmd, (unsigned int __user *)arg); case TIOCGSERIAL: - dbg("%s (%d) TIOCGSERIAL", __func__, port->number); + dev_dbg(&port->dev, "%s TIOCGSERIAL\n", __func__); return get_serial_info(mos7720_port, (struct serial_struct __user *)arg); - - case TIOCMIWAIT: - dbg("%s (%d) TIOCMIWAIT", __func__, port->number); - cprev = mos7720_port->icount; - while (1) { - if (signal_pending(current)) - return -ERESTARTSYS; - cnow = mos7720_port->icount; - if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && - cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) - return -EIO; /* no change => error */ - if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || - ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || - ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || - ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) { - return 0; - } - cprev = cnow; - } - /* NOTREACHED */ - break; } return -ENOIOCTLCMD; @@ -2048,20 +1896,12 @@ static int mos7720_ioctl(struct tty_struct *tty, struct file *file, static int mos7720_startup(struct usb_serial *serial) { - struct moschip_port *mos7720_port; struct usb_device *dev; - int i; char data; - u16 product = le16_to_cpu(serial->dev->descriptor.idProduct); + u16 product; int ret_val; - dbg("%s: Entering ..........", __func__); - - if (!serial) { - dbg("Invalid Handler"); - return -ENODEV; - } - + product = le16_to_cpu(serial->dev->descriptor.idProduct); dev = serial->dev; /* @@ -2087,32 +1927,9 @@ static int mos7720_startup(struct usb_serial *serial) serial->port[1]->interrupt_in_buffer = NULL; } - - /* set up serial port private structures */ - for (i = 0; i < serial->num_ports; ++i) { - mos7720_port = kzalloc(sizeof(struct moschip_port), GFP_KERNEL); - if (mos7720_port == NULL) { - dev_err(&dev->dev, "%s - Out of memory\n", __func__); - return -ENOMEM; - } - - /* Initialize all port interrupt end point to port 0 int - * endpoint. Our device has only one interrupt endpoint - * common to all ports */ - serial->port[i]->interrupt_in_endpointAddress = - serial->port[0]->interrupt_in_endpointAddress; - - mos7720_port->port = serial->port[i]; - usb_set_serial_port_data(serial->port[i], mos7720_port); - - dbg("port number is %d", serial->port[i]->number); - dbg("serial number is %d", serial->minor); - } - - /* setting configuration feature to one */ usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - (__u8)0x03, 0x00, 0x01, 0x00, NULL, 0x00, 5*HZ); + (__u8)0x03, 0x00, 0x01, 0x00, NULL, 0x00, 5000); /* start the interrupt urb */ ret_val = usb_submit_urb(serial->port[0]->interrupt_in_urb, GFP_KERNEL); @@ -2130,15 +1947,13 @@ static int mos7720_startup(struct usb_serial *serial) #endif /* LSR For Port 1 */ read_mos_reg(serial, 0, LSR, &data); - dbg("LSR:%x", data); + dev_dbg(&dev->dev, "LSR:%x\n", data); return 0; } static void mos7720_release(struct usb_serial *serial) { - int i; - #ifdef CONFIG_USB_SERIAL_MOS7715_PARPORT /* close the parallel port */ @@ -2157,7 +1972,7 @@ static void mos7720_release(struct usb_serial *serial) /* wait for synchronous usb calls to return */ if (mos_parport->msg_pending) wait_for_completion_timeout(&mos_parport->syncmsg_compl, - MOS_WDR_TIMEOUT); + msecs_to_jiffies(MOS_WDR_TIMEOUT)); parport_remove_port(mos_parport->pp); usb_set_serial_data(serial, NULL); @@ -2177,18 +1992,37 @@ static void mos7720_release(struct usb_serial *serial) kref_put(&mos_parport->ref_count, destroy_mos_parport); } #endif - /* free private structure allocated for serial port */ - for (i = 0; i < serial->num_ports; ++i) - kfree(usb_get_serial_port_data(serial->port[i])); } -static struct usb_driver usb_driver = { - .name = "moschip7720", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = moschip_port_id_table, - .no_dynamic_id = 1, -}; +static int mos7720_port_probe(struct usb_serial_port *port) +{ + struct moschip_port *mos7720_port; + + mos7720_port = kzalloc(sizeof(*mos7720_port), GFP_KERNEL); + if (!mos7720_port) + return -ENOMEM; + + /* Initialize all port interrupt end point to port 0 int endpoint. + * Our device has only one interrupt endpoint common to all ports. + */ + port->interrupt_in_endpointAddress = + port->serial->port[0]->interrupt_in_endpointAddress; + mos7720_port->port = port; + + usb_set_serial_port_data(port, mos7720_port); + + return 0; +} + +static int mos7720_port_remove(struct usb_serial_port *port) +{ + struct moschip_port *mos7720_port; + + mos7720_port = usb_get_serial_port_data(port); + kfree(mos7720_port); + + return 0; +} static struct usb_serial_driver moschip7720_2port_driver = { .driver = { @@ -2196,8 +2030,7 @@ static struct usb_serial_driver moschip7720_2port_driver = { .name = "moschip7720", }, .description = "Moschip 2 port adapter", - .usb_driver = &usb_driver, - .id_table = moschip_port_id_table, + .id_table = id_table, .calc_num_ports = mos77xx_calc_num_ports, .open = mos7720_open, .close = mos7720_close, @@ -2206,10 +2039,11 @@ static struct usb_serial_driver moschip7720_2port_driver = { .probe = mos77xx_probe, .attach = mos7720_startup, .release = mos7720_release, + .port_probe = mos7720_port_probe, + .port_remove = mos7720_port_remove, .ioctl = mos7720_ioctl, .tiocmget = mos7720_tiocmget, .tiocmset = mos7720_tiocmset, - .get_icount = mos7720_get_icount, .set_termios = mos7720_set_termios, .write = mos7720_write, .write_room = mos7720_write_room, @@ -2219,47 +2053,12 @@ static struct usb_serial_driver moschip7720_2port_driver = { .read_int_callback = NULL /* dynamically assigned in probe() */ }; -static int __init moschip7720_init(void) -{ - int retval; - - dbg("%s: Entering ..........", __func__); - - /* Register with the usb serial */ - retval = usb_serial_register(&moschip7720_2port_driver); - if (retval) - goto failed_port_device_register; - - printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" - DRIVER_DESC "\n"); - - /* Register with the usb */ - retval = usb_register(&usb_driver); - if (retval) - goto failed_usb_register; - - return 0; - -failed_usb_register: - usb_serial_deregister(&moschip7720_2port_driver); - -failed_port_device_register: - return retval; -} - -static void __exit moschip7720_exit(void) -{ - usb_deregister(&usb_driver); - usb_serial_deregister(&moschip7720_2port_driver); -} +static struct usb_serial_driver * const serial_drivers[] = { + &moschip7720_2port_driver, NULL +}; -module_init(moschip7720_init); -module_exit(moschip7720_exit); +module_usb_serial_driver(serial_drivers, id_table); -/* Module information */ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index 5627993f9e4..393be562d87 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -24,7 +24,6 @@ #include <linux/kernel.h> #include <linux/errno.h> -#include <linux/init.h> #include <linux/slab.h> #include <linux/tty.h> #include <linux/tty_driver.h> @@ -35,10 +34,6 @@ #include <linux/usb/serial.h> #include <linux/uaccess.h> -/* - * Version Information - */ -#define DRIVER_VERSION "1.3.2" #define DRIVER_DESC "Moschip 7840/7820 USB Serial Driver" /* @@ -82,8 +77,7 @@ * Defines used for sending commands to port */ -#define WAIT_FOR_EVER (HZ * 0) /* timeout urb is wait for ever */ -#define MOS_WDR_TIMEOUT (HZ * 5) /* default urb timeout */ +#define MOS_WDR_TIMEOUT 5000 /* default urb timeout */ #define MOS_PORT1 0x0200 #define MOS_PORT2 0x0300 @@ -114,10 +108,10 @@ #define USB_VENDOR_ID_MOSCHIP 0x9710 #define MOSCHIP_DEVICE_ID_7840 0x7840 #define MOSCHIP_DEVICE_ID_7820 0x7820 +#define MOSCHIP_DEVICE_ID_7810 0x7810 /* The native component can have its vendor/device id's overridden * in vendor-specific implementations. Such devices can be handled - * by making a change here, in moschip_port_id_table, and in - * moschip_id_table_combined + * by making a change here, in id_table. */ #define USB_VENDOR_ID_BANDB 0x0856 #define BANDB_DEVICE_ID_USO9ML2_2 0xAC22 @@ -174,6 +168,7 @@ #define CLK_MULTI_REGISTER ((__u16)(0x02)) #define CLK_START_VALUE_REGISTER ((__u16)(0x03)) +#define GPIO_REGISTER ((__u16)(0x07)) #define SERIAL_LCR_DLAB ((__u16)(0x0080)) @@ -183,31 +178,19 @@ #define NUM_URBS 16 /* URB Count */ #define URB_TRANSFER_BUFFER_SIZE 32 /* URB Size */ +/* LED on/off milliseconds*/ +#define LED_ON_MS 500 +#define LED_OFF_MS 500 -static const struct usb_device_id moschip_port_id_table[] = { - {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7840)}, - {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7820)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2P)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_4)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_4P)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_US9ML2_2)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_US9ML2_4)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USPTL4_2)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USPTL4_4)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_2)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_2P)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_4)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_4P)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL2_4)}, - {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2324)}, - {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2322)}, - {} /* terminating entry */ +enum mos7840_flag { + MOS7840_FLAG_CTRL_BUSY, + MOS7840_FLAG_LED_BUSY, }; -static const struct usb_device_id moschip_id_table_combined[] __devinitconst = { +static const struct usb_device_id id_table[] = { {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7840)}, {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7820)}, + {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7810)}, {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2)}, {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2P)}, {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_4)}, @@ -225,8 +208,7 @@ static const struct usb_device_id moschip_id_table_combined[] __devinitconst = { {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2322)}, {} /* terminating entry */ }; - -MODULE_DEVICE_TABLE(usb, moschip_id_table_combined); +MODULE_DEVICE_TABLE(usb, id_table); /* This structure holds all of the local port information */ @@ -234,16 +216,10 @@ struct moschip_port { int port_num; /*Actual port number in the device(1,2,etc) */ struct urb *write_urb; /* write URB for this port */ struct urb *read_urb; /* read URB for this port */ - struct urb *int_urb; __u8 shadowLCR; /* last LCR value received */ __u8 shadowMCR; /* last MCR value received */ char open; char open_ports; - char zombie; - wait_queue_head_t wait_chase; /* for handling sleeping while waiting for chase to finish */ - wait_queue_head_t delta_msr_wait; /* for handling sleeping while waiting for msr change to happen */ - int delta_msr_cond; - struct async_icount icount; struct usb_serial_port *port; /* loop back to the owner of this object */ /* Offsets */ @@ -260,10 +236,16 @@ struct moschip_port { struct urb *write_urb_pool[NUM_URBS]; char busy[NUM_URBS]; bool read_urb_busy; -}; + /* For device(s) with LED indicator */ + bool has_led; + struct timer_list led_timer1; /* Timer for LED on */ + struct timer_list led_timer2; /* Timer for LED off */ + struct urb *led_urb; + struct usb_ctrlrequest *led_dr; -static int debug; + unsigned long flags; +}; /* * mos7840_set_reg_sync @@ -276,7 +258,7 @@ static int mos7840_set_reg_sync(struct usb_serial_port *port, __u16 reg, { struct usb_device *dev = port->serial->dev; val = val & 0x00ff; - dbg("mos7840_set_reg_sync offset is %x, value %x", reg, val); + dev_dbg(&port->dev, "mos7840_set_reg_sync offset is %x, value %x\n", reg, val); return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), MCS_WRREQ, MCS_WR_RTYPE, val, reg, NULL, 0, @@ -304,7 +286,7 @@ static int mos7840_get_reg_sync(struct usb_serial_port *port, __u16 reg, MCS_RD_RTYPE, 0, reg, buf, VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT); *val = buf[0]; - dbg("mos7840_get_reg_sync offset is %x, return val %x", reg, *val); + dev_dbg(&port->dev, "%s offset is %x, return val %x\n", __func__, reg, *val); kfree(buf); return ret; @@ -325,23 +307,15 @@ static int mos7840_set_uart_reg(struct usb_serial_port *port, __u16 reg, /* For the UART control registers, the application number need to be Or'ed */ if (port->serial->num_ports == 4) { - val |= (((__u16) port->number - - (__u16) (port->serial->minor)) + 1) << 8; - dbg("mos7840_set_uart_reg application number is %x", val); + val |= ((__u16)port->port_number + 1) << 8; } else { - if (((__u16) port->number - (__u16) (port->serial->minor)) == 0) { - val |= (((__u16) port->number - - (__u16) (port->serial->minor)) + 1) << 8; - dbg("mos7840_set_uart_reg application number is %x", - val); + if (port->port_number == 0) { + val |= ((__u16)port->port_number + 1) << 8; } else { - val |= - (((__u16) port->number - - (__u16) (port->serial->minor)) + 2) << 8; - dbg("mos7840_set_uart_reg application number is %x", - val); + val |= ((__u16)port->port_number + 2) << 8; } } + dev_dbg(&port->dev, "%s application number is %x\n", __func__, val); return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), MCS_WRREQ, MCS_WR_RTYPE, val, reg, NULL, 0, MOS_WDR_TIMEOUT); @@ -365,27 +339,17 @@ static int mos7840_get_uart_reg(struct usb_serial_port *port, __u16 reg, if (!buf) return -ENOMEM; - /* dbg("application number is %4x", - (((__u16)port->number - (__u16)(port->serial->minor))+1)<<8); */ /* Wval is same as application number */ if (port->serial->num_ports == 4) { - Wval = - (((__u16) port->number - (__u16) (port->serial->minor)) + - 1) << 8; - dbg("mos7840_get_uart_reg application number is %x", Wval); + Wval = ((__u16)port->port_number + 1) << 8; } else { - if (((__u16) port->number - (__u16) (port->serial->minor)) == 0) { - Wval = (((__u16) port->number - - (__u16) (port->serial->minor)) + 1) << 8; - dbg("mos7840_get_uart_reg application number is %x", - Wval); + if (port->port_number == 0) { + Wval = ((__u16)port->port_number + 1) << 8; } else { - Wval = (((__u16) port->number - - (__u16) (port->serial->minor)) + 2) << 8; - dbg("mos7840_get_uart_reg application number is %x", - Wval); + Wval = ((__u16)port->port_number + 2) << 8; } } + dev_dbg(&port->dev, "%s application number is %x\n", __func__, Wval); ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), MCS_RDREQ, MCS_RD_RTYPE, Wval, reg, buf, VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT); @@ -395,14 +359,13 @@ static int mos7840_get_uart_reg(struct usb_serial_port *port, __u16 reg, return ret; } -static void mos7840_dump_serial_port(struct moschip_port *mos7840_port) +static void mos7840_dump_serial_port(struct usb_serial_port *port, + struct moschip_port *mos7840_port) { - dbg("***************************************"); - dbg("SpRegOffset is %2x", mos7840_port->SpRegOffset); - dbg("ControlRegOffset is %2x", mos7840_port->ControlRegOffset); - dbg("DCRRegOffset is %2x", mos7840_port->DcrRegOffset); - dbg("***************************************"); + dev_dbg(&port->dev, "SpRegOffset is %2x\n", mos7840_port->SpRegOffset); + dev_dbg(&port->dev, "ControlRegOffset is %2x\n", mos7840_port->ControlRegOffset); + dev_dbg(&port->dev, "DCRRegOffset is %2x\n", mos7840_port->DcrRegOffset); } @@ -431,29 +394,22 @@ static void mos7840_handle_new_msr(struct moschip_port *port, __u8 new_msr) struct moschip_port *mos7840_port; struct async_icount *icount; mos7840_port = port; - icount = &mos7840_port->icount; if (new_msr & (MOS_MSR_DELTA_CTS | MOS_MSR_DELTA_DSR | MOS_MSR_DELTA_RI | MOS_MSR_DELTA_CD)) { - icount = &mos7840_port->icount; + icount = &mos7840_port->port->icount; /* update input line counters */ - if (new_msr & MOS_MSR_DELTA_CTS) { + if (new_msr & MOS_MSR_DELTA_CTS) icount->cts++; - smp_wmb(); - } - if (new_msr & MOS_MSR_DELTA_DSR) { + if (new_msr & MOS_MSR_DELTA_DSR) icount->dsr++; - smp_wmb(); - } - if (new_msr & MOS_MSR_DELTA_CD) { + if (new_msr & MOS_MSR_DELTA_CD) icount->dcd++; - smp_wmb(); - } - if (new_msr & MOS_MSR_DELTA_RI) { + if (new_msr & MOS_MSR_DELTA_RI) icount->rng++; - smp_wmb(); - } + + wake_up_interruptible(&port->port->port.delta_msr_wait); } } @@ -461,8 +417,6 @@ static void mos7840_handle_new_lsr(struct moschip_port *port, __u8 new_lsr) { struct async_icount *icount; - dbg("%s - %02x", __func__, new_lsr); - if (new_lsr & SERIAL_LSR_BI) { /* * Parity and Framing errors only count if they @@ -473,23 +427,15 @@ static void mos7840_handle_new_lsr(struct moschip_port *port, __u8 new_lsr) } /* update input line counters */ - icount = &port->icount; - if (new_lsr & SERIAL_LSR_BI) { + icount = &port->port->icount; + if (new_lsr & SERIAL_LSR_BI) icount->brk++; - smp_wmb(); - } - if (new_lsr & SERIAL_LSR_OE) { + if (new_lsr & SERIAL_LSR_OE) icount->overrun++; - smp_wmb(); - } - if (new_lsr & SERIAL_LSR_PE) { + if (new_lsr & SERIAL_LSR_PE) icount->parity++; - smp_wmb(); - } - if (new_lsr & SERIAL_LSR_FE) { + if (new_lsr & SERIAL_LSR_FE) icount->frame++; - smp_wmb(); - } } /************************************************************************/ @@ -503,8 +449,8 @@ static void mos7840_control_callback(struct urb *urb) { unsigned char *data; struct moschip_port *mos7840_port; + struct device *dev = &urb->dev->dev; __u8 regval = 0x0; - int result = 0; int status = urb->status; mos7840_port = urb->context; @@ -517,36 +463,25 @@ static void mos7840_control_callback(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", __func__, - status); - return; + dev_dbg(dev, "%s - urb shutting down with status: %d\n", __func__, status); + goto out; default: - dbg("%s - nonzero urb status received: %d", __func__, - status); - goto exit; + dev_dbg(dev, "%s - nonzero urb status received: %d\n", __func__, status); + goto out; } - dbg("%s urb buffer size is %d", __func__, urb->actual_length); - dbg("%s mos7840_port->MsrLsr is %d port %d", __func__, - mos7840_port->MsrLsr, mos7840_port->port_num); + dev_dbg(dev, "%s urb buffer size is %d\n", __func__, urb->actual_length); + dev_dbg(dev, "%s mos7840_port->MsrLsr is %d port %d\n", __func__, + mos7840_port->MsrLsr, mos7840_port->port_num); data = urb->transfer_buffer; regval = (__u8) data[0]; - dbg("%s data is %x", __func__, regval); + dev_dbg(dev, "%s data is %x\n", __func__, regval); if (mos7840_port->MsrLsr == 0) mos7840_handle_new_msr(mos7840_port, regval); else if (mos7840_port->MsrLsr == 1) mos7840_handle_new_lsr(mos7840_port, regval); - -exit: - spin_lock(&mos7840_port->pool_lock); - if (!mos7840_port->zombie) - result = usb_submit_urb(mos7840_port->int_urb, GFP_ATOMIC); - spin_unlock(&mos7840_port->pool_lock); - if (result) { - dev_err(&urb->dev->dev, - "%s - Error %d submitting interrupt urb\n", - __func__, result); - } +out: + clear_bit_unlock(MOS7840_FLAG_CTRL_BUSY, &mos7840_port->flags); } static int mos7840_get_reg(struct moschip_port *mcs, __u16 Wval, __u16 reg, @@ -557,6 +492,9 @@ static int mos7840_get_reg(struct moschip_port *mcs, __u16 Wval, __u16 reg, unsigned char *buffer = mcs->ctrl_buf; int ret; + if (test_and_set_bit_lock(MOS7840_FLAG_CTRL_BUSY, &mcs->flags)) + return -EBUSY; + dr->bRequestType = MCS_RD_RTYPE; dr->bRequest = MCS_RDREQ; dr->wValue = cpu_to_le16(Wval); /* 0 */ @@ -568,9 +506,87 @@ static int mos7840_get_reg(struct moschip_port *mcs, __u16 Wval, __u16 reg, mos7840_control_callback, mcs); mcs->control_urb->transfer_buffer_length = 2; ret = usb_submit_urb(mcs->control_urb, GFP_ATOMIC); + if (ret) + clear_bit_unlock(MOS7840_FLAG_CTRL_BUSY, &mcs->flags); + return ret; } +static void mos7840_set_led_callback(struct urb *urb) +{ + switch (urb->status) { + case 0: + /* Success */ + break; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + /* This urb is terminated, clean up */ + dev_dbg(&urb->dev->dev, "%s - urb shutting down: %d\n", + __func__, urb->status); + break; + default: + dev_dbg(&urb->dev->dev, "%s - nonzero urb status: %d\n", + __func__, urb->status); + } +} + +static void mos7840_set_led_async(struct moschip_port *mcs, __u16 wval, + __u16 reg) +{ + struct usb_device *dev = mcs->port->serial->dev; + struct usb_ctrlrequest *dr = mcs->led_dr; + + dr->bRequestType = MCS_WR_RTYPE; + dr->bRequest = MCS_WRREQ; + dr->wValue = cpu_to_le16(wval); + dr->wIndex = cpu_to_le16(reg); + dr->wLength = cpu_to_le16(0); + + usb_fill_control_urb(mcs->led_urb, dev, usb_sndctrlpipe(dev, 0), + (unsigned char *)dr, NULL, 0, mos7840_set_led_callback, NULL); + + usb_submit_urb(mcs->led_urb, GFP_ATOMIC); +} + +static void mos7840_set_led_sync(struct usb_serial_port *port, __u16 reg, + __u16 val) +{ + struct usb_device *dev = port->serial->dev; + + usb_control_msg(dev, usb_sndctrlpipe(dev, 0), MCS_WRREQ, MCS_WR_RTYPE, + val, reg, NULL, 0, MOS_WDR_TIMEOUT); +} + +static void mos7840_led_off(unsigned long arg) +{ + struct moschip_port *mcs = (struct moschip_port *) arg; + + /* Turn off LED */ + mos7840_set_led_async(mcs, 0x0300, MODEM_CONTROL_REGISTER); + mod_timer(&mcs->led_timer2, + jiffies + msecs_to_jiffies(LED_OFF_MS)); +} + +static void mos7840_led_flag_off(unsigned long arg) +{ + struct moschip_port *mcs = (struct moschip_port *) arg; + + clear_bit_unlock(MOS7840_FLAG_LED_BUSY, &mcs->flags); +} + +static void mos7840_led_activity(struct usb_serial_port *port) +{ + struct moschip_port *mos7840_port = usb_get_serial_port_data(port); + + if (test_and_set_bit_lock(MOS7840_FLAG_LED_BUSY, &mos7840_port->flags)) + return; + + mos7840_set_led_async(mos7840_port, 0x0301, MODEM_CONTROL_REGISTER); + mod_timer(&mos7840_port->led_timer1, + jiffies + msecs_to_jiffies(LED_ON_MS)); +} + /***************************************************************************** * mos7840_interrupt_callback * this is the callback function for when we have received data on the @@ -590,8 +606,6 @@ static void mos7840_interrupt_callback(struct urb *urb) __u16 wval, wreg = 0; int status = urb->status; - dbg("%s", " : Entering"); - switch (status) { case 0: /* success */ @@ -600,12 +614,12 @@ static void mos7840_interrupt_callback(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", __func__, - status); + dev_dbg(&urb->dev->dev, "%s - urb shutting down with status: %d\n", + __func__, status); return; default: - dbg("%s - nonzero urb status received: %d", __func__, - status); + dev_dbg(&urb->dev->dev, "%s - nonzero urb status received: %d\n", + __func__, status); goto exit; } @@ -622,7 +636,7 @@ static void mos7840_interrupt_callback(struct urb *urb) * Byte 5 FIFO status for both */ if (length && length > 5) { - dbg("%s", "Wrong data !!!"); + dev_dbg(&urb->dev->dev, "%s", "Wrong data !!!\n"); return; } @@ -634,34 +648,25 @@ static void mos7840_interrupt_callback(struct urb *urb) for (i = 0; i < serial->num_ports; i++) { mos7840_port = mos7840_get_port_private(serial->port[i]); - wval = - (((__u16) serial->port[i]->number - - (__u16) (serial->minor)) + 1) << 8; + wval = ((__u16)serial->port[i]->port_number + 1) << 8; if (mos7840_port->open) { if (sp[i] & 0x01) { - dbg("SP%d No Interrupt !!!", i); + dev_dbg(&urb->dev->dev, "SP%d No Interrupt !!!\n", i); } else { switch (sp[i] & 0x0f) { case SERIAL_IIR_RLS: - dbg("Serial Port %d: Receiver status error or ", i); - dbg("address bit detected in 9-bit mode"); + dev_dbg(&urb->dev->dev, "Serial Port %d: Receiver status error or \n", i); + dev_dbg(&urb->dev->dev, "address bit detected in 9-bit mode\n"); mos7840_port->MsrLsr = 1; wreg = LINE_STATUS_REGISTER; break; case SERIAL_IIR_MS: - dbg("Serial Port %d: Modem status change", i); + dev_dbg(&urb->dev->dev, "Serial Port %d: Modem status change\n", i); mos7840_port->MsrLsr = 0; wreg = MODEM_STATUS_REGISTER; break; } - spin_lock(&mos7840_port->pool_lock); - if (!mos7840_port->zombie) { - rv = mos7840_get_reg(mos7840_port, wval, wreg, &Data); - } else { - spin_unlock(&mos7840_port->pool_lock); - return; - } - spin_unlock(&mos7840_port->pool_lock); + rv = mos7840_get_reg(mos7840_port, wval, wreg, &Data); } } } @@ -681,11 +686,11 @@ static int mos7840_port_paranoia_check(struct usb_serial_port *port, const char *function) { if (!port) { - dbg("%s - port == NULL", function); + pr_debug("%s - port == NULL\n", function); return -1; } if (!port->serial) { - dbg("%s - port->serial == NULL", function); + pr_debug("%s - port->serial == NULL\n", function); return -1; } @@ -697,11 +702,11 @@ static int mos7840_serial_paranoia_check(struct usb_serial *serial, const char *function) { if (!serial) { - dbg("%s - serial == NULL", function); + pr_debug("%s - serial == NULL\n", function); return -1; } if (!serial->type) { - dbg("%s - serial->type == NULL!", function); + pr_debug("%s - serial->type == NULL!\n", function); return -1; } @@ -736,69 +741,55 @@ static void mos7840_bulk_in_callback(struct urb *urb) struct usb_serial *serial; struct usb_serial_port *port; struct moschip_port *mos7840_port; - struct tty_struct *tty; int status = urb->status; mos7840_port = urb->context; - if (!mos7840_port) { - dbg("%s", "NULL mos7840_port pointer"); + if (!mos7840_port) return; - } if (status) { - dbg("nonzero read bulk status received: %d", status); + dev_dbg(&urb->dev->dev, "nonzero read bulk status received: %d\n", status); mos7840_port->read_urb_busy = false; return; } - port = (struct usb_serial_port *)mos7840_port->port; + port = mos7840_port->port; if (mos7840_port_paranoia_check(port, __func__)) { - dbg("%s", "Port Paranoia failed"); mos7840_port->read_urb_busy = false; return; } serial = mos7840_get_usb_serial(port, __func__); if (!serial) { - dbg("%s", "Bad serial pointer"); mos7840_port->read_urb_busy = false; return; } - dbg("%s", "Entering... "); - data = urb->transfer_buffer; - - dbg("%s", "Entering ..........."); + usb_serial_debug_data(&port->dev, __func__, urb->actual_length, data); if (urb->actual_length) { - tty = tty_port_tty_get(&mos7840_port->port->port); - if (tty) { - tty_insert_flip_string(tty, data, urb->actual_length); - dbg(" %s ", data); - tty_flip_buffer_push(tty); - tty_kref_put(tty); - } - mos7840_port->icount.rx += urb->actual_length; - smp_wmb(); - dbg("mos7840_port->icount.rx is %d:", - mos7840_port->icount.rx); + struct tty_port *tport = &mos7840_port->port->port; + tty_insert_flip_string(tport, data, urb->actual_length); + tty_flip_buffer_push(tport); + port->icount.rx += urb->actual_length; + dev_dbg(&port->dev, "icount.rx is %d:\n", port->icount.rx); } if (!mos7840_port->read_urb) { - dbg("%s", "URB KILLED !!!"); + dev_dbg(&port->dev, "%s", "URB KILLED !!!\n"); mos7840_port->read_urb_busy = false; return; } - - mos7840_port->read_urb->dev = serial->dev; + if (mos7840_port->has_led) + mos7840_led_activity(port); mos7840_port->read_urb_busy = true; retval = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC); if (retval) { - dbg("usb_submit_urb(read bulk) failed, retval = %d", retval); + dev_dbg(&port->dev, "usb_submit_urb(read bulk) failed, retval = %d\n", retval); mos7840_port->read_urb_busy = false; } } @@ -812,11 +803,12 @@ static void mos7840_bulk_in_callback(struct urb *urb) static void mos7840_bulk_out_data_callback(struct urb *urb) { struct moschip_port *mos7840_port; - struct tty_struct *tty; + struct usb_serial_port *port; int status = urb->status; int i; mos7840_port = urb->context; + port = mos7840_port->port; spin_lock(&mos7840_port->pool_lock); for (i = 0; i < NUM_URBS; i++) { if (urb == mos7840_port->write_urb_pool[i]) { @@ -827,39 +819,21 @@ static void mos7840_bulk_out_data_callback(struct urb *urb) spin_unlock(&mos7840_port->pool_lock); if (status) { - dbg("nonzero write bulk status received:%d", status); + dev_dbg(&port->dev, "nonzero write bulk status received:%d\n", status); return; } - if (mos7840_port_paranoia_check(mos7840_port->port, __func__)) { - dbg("%s", "Port Paranoia failed"); + if (mos7840_port_paranoia_check(port, __func__)) return; - } - dbg("%s", "Entering ........."); - - tty = tty_port_tty_get(&mos7840_port->port->port); - if (tty && mos7840_port->open) - tty_wakeup(tty); - tty_kref_put(tty); + if (mos7840_port->open) + tty_port_tty_wakeup(&port->port); } /************************************************************************/ /* D R I V E R T T Y I N T E R F A C E F U N C T I O N S */ /************************************************************************/ -#ifdef MCSSerialProbe -static int mos7840_serial_probe(struct usb_serial *serial, - const struct usb_device_id *id) -{ - - /*need to implement the mode_reg reading and updating\ - structures usb_serial_ device_type\ - (i.e num_ports, num_bulkin,bulkout etc) */ - /* Also we can update the changes attach */ - return 1; -} -#endif /***************************************************************************** * mos7840_open @@ -879,19 +853,13 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port) struct moschip_port *mos7840_port; struct moschip_port *port0; - dbg ("%s enter", __func__); - - if (mos7840_port_paranoia_check(port, __func__)) { - dbg("%s", "Port Paranoia failed"); + if (mos7840_port_paranoia_check(port, __func__)) return -ENODEV; - } serial = port->serial; - if (mos7840_serial_paranoia_check(serial, __func__)) { - dbg("%s", "Serial Paranoia failed"); + if (mos7840_serial_paranoia_check(serial, __func__)) return -ENODEV; - } mos7840_port = mos7840_get_port_private(port); port0 = mos7840_get_port_private(serial->port[0]); @@ -907,20 +875,14 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port) for (j = 0; j < NUM_URBS; ++j) { urb = usb_alloc_urb(0, GFP_KERNEL); mos7840_port->write_urb_pool[j] = urb; - - if (urb == NULL) { - dev_err(&port->dev, "No more urbs???\n"); + if (!urb) continue; - } urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL); if (!urb->transfer_buffer) { usb_free_urb(urb); mos7840_port->write_urb_pool[j] = NULL; - dev_err(&port->dev, - "%s-out of memory for urb buffers.\n", - __func__); continue; } } @@ -942,21 +904,21 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port) Data = 0x0; status = mos7840_get_reg_sync(port, mos7840_port->SpRegOffset, &Data); if (status < 0) { - dbg("Reading Spreg failed"); - return -1; + dev_dbg(&port->dev, "Reading Spreg failed\n"); + goto err; } Data |= 0x80; status = mos7840_set_reg_sync(port, mos7840_port->SpRegOffset, Data); if (status < 0) { - dbg("writing Spreg failed"); - return -1; + dev_dbg(&port->dev, "writing Spreg failed\n"); + goto err; } Data &= ~0x80; status = mos7840_set_reg_sync(port, mos7840_port->SpRegOffset, Data); if (status < 0) { - dbg("writing Spreg failed"); - return -1; + dev_dbg(&port->dev, "writing Spreg failed\n"); + goto err; } /* End of block to be checked */ @@ -964,16 +926,16 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port) status = mos7840_get_reg_sync(port, mos7840_port->ControlRegOffset, &Data); if (status < 0) { - dbg("Reading Controlreg failed"); - return -1; + dev_dbg(&port->dev, "Reading Controlreg failed\n"); + goto err; } Data |= 0x08; /* Driver done bit */ Data |= 0x20; /* rx_disable */ status = mos7840_set_reg_sync(port, mos7840_port->ControlRegOffset, Data); if (status < 0) { - dbg("writing Controlreg failed"); - return -1; + dev_dbg(&port->dev, "writing Controlreg failed\n"); + goto err; } /* do register settings here */ /* Set all regs to the device default values. */ @@ -983,22 +945,22 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port) Data = 0x00; status = mos7840_set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data); if (status < 0) { - dbg("disabling interrupts failed"); - return -1; + dev_dbg(&port->dev, "disabling interrupts failed\n"); + goto err; } /* Set FIFO_CONTROL_REGISTER to the default value */ Data = 0x00; status = mos7840_set_uart_reg(port, FIFO_CONTROL_REGISTER, Data); if (status < 0) { - dbg("Writing FIFO_CONTROL_REGISTER failed"); - return -1; + dev_dbg(&port->dev, "Writing FIFO_CONTROL_REGISTER failed\n"); + goto err; } Data = 0xcf; status = mos7840_set_uart_reg(port, FIFO_CONTROL_REGISTER, Data); if (status < 0) { - dbg("Writing FIFO_CONTROL_REGISTER failed"); - return -1; + dev_dbg(&port->dev, "Writing FIFO_CONTROL_REGISTER failed\n"); + goto err; } Data = 0x03; @@ -1094,26 +1056,34 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port) * (can't set it up in mos7840_startup as the * * structures were not set up at that time.) */ - dbg("port number is %d", port->number); - dbg("serial number is %d", port->serial->minor); - dbg("Bulkin endpoint is %d", port->bulk_in_endpointAddress); - dbg("BulkOut endpoint is %d", port->bulk_out_endpointAddress); - dbg("Interrupt endpoint is %d", port->interrupt_in_endpointAddress); - dbg("port's number in the device is %d", mos7840_port->port_num); + dev_dbg(&port->dev, "port number is %d\n", port->port_number); + dev_dbg(&port->dev, "minor number is %d\n", port->minor); + dev_dbg(&port->dev, "Bulkin endpoint is %d\n", port->bulk_in_endpointAddress); + dev_dbg(&port->dev, "BulkOut endpoint is %d\n", port->bulk_out_endpointAddress); + dev_dbg(&port->dev, "Interrupt endpoint is %d\n", port->interrupt_in_endpointAddress); + dev_dbg(&port->dev, "port's number in the device is %d\n", mos7840_port->port_num); mos7840_port->read_urb = port->read_urb; /* set up our bulk in urb */ + if ((serial->num_ports == 2) && (((__u16)port->port_number % 2) != 0)) { + usb_fill_bulk_urb(mos7840_port->read_urb, + serial->dev, + usb_rcvbulkpipe(serial->dev, + (port->bulk_in_endpointAddress) + 2), + port->bulk_in_buffer, + mos7840_port->read_urb->transfer_buffer_length, + mos7840_bulk_in_callback, mos7840_port); + } else { + usb_fill_bulk_urb(mos7840_port->read_urb, + serial->dev, + usb_rcvbulkpipe(serial->dev, + port->bulk_in_endpointAddress), + port->bulk_in_buffer, + mos7840_port->read_urb->transfer_buffer_length, + mos7840_bulk_in_callback, mos7840_port); + } - usb_fill_bulk_urb(mos7840_port->read_urb, - serial->dev, - usb_rcvbulkpipe(serial->dev, - port->bulk_in_endpointAddress), - port->bulk_in_buffer, - mos7840_port->read_urb->transfer_buffer_length, - mos7840_bulk_in_callback, mos7840_port); - - dbg("mos7840_open: bulkin endpoint is %d", - port->bulk_in_endpointAddress); + dev_dbg(&port->dev, "%s: bulkin endpoint is %d\n", __func__, port->bulk_in_endpointAddress); mos7840_port->read_urb_busy = true; response = usb_submit_urb(mos7840_port->read_urb, GFP_KERNEL); if (response) { @@ -1122,29 +1092,23 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port) mos7840_port->read_urb_busy = false; } - /* initialize our wait queues */ - init_waitqueue_head(&mos7840_port->wait_chase); - init_waitqueue_head(&mos7840_port->delta_msr_wait); - - /* initialize our icount structure */ - memset(&(mos7840_port->icount), 0x00, sizeof(mos7840_port->icount)); - /* initialize our port settings */ /* Must set to enable ints! */ mos7840_port->shadowMCR = MCR_MASTER_IE; /* send a open port command */ mos7840_port->open = 1; /* mos7840_change_port_settings(mos7840_port,old_termios); */ - mos7840_port->icount.tx = 0; - mos7840_port->icount.rx = 0; - - dbg("usb_serial serial:%p mos7840_port:%p\n usb_serial_port port:%p", - serial, mos7840_port, port); - - dbg ("%s leave", __func__); return 0; - +err: + for (j = 0; j < NUM_URBS; ++j) { + urb = mos7840_port->write_urb_pool[j]; + if (!urb) + continue; + kfree(urb->transfer_buffer); + usb_free_urb(urb); + } + return status; } /***************************************************************************** @@ -1165,25 +1129,22 @@ static int mos7840_chars_in_buffer(struct tty_struct *tty) unsigned long flags; struct moschip_port *mos7840_port; - dbg("%s", " mos7840_chars_in_buffer:entering ..........."); - - if (mos7840_port_paranoia_check(port, __func__)) { - dbg("%s", "Invalid port"); + if (mos7840_port_paranoia_check(port, __func__)) return 0; - } mos7840_port = mos7840_get_port_private(port); - if (mos7840_port == NULL) { - dbg("%s", "mos7840_break:leaving ..........."); + if (mos7840_port == NULL) return 0; - } spin_lock_irqsave(&mos7840_port->pool_lock, flags); - for (i = 0; i < NUM_URBS; ++i) - if (mos7840_port->busy[i]) - chars += URB_TRANSFER_BUFFER_SIZE; + for (i = 0; i < NUM_URBS; ++i) { + if (mos7840_port->busy[i]) { + struct urb *urb = mos7840_port->write_urb_pool[i]; + chars += urb->transfer_buffer_length; + } + } spin_unlock_irqrestore(&mos7840_port->pool_lock, flags); - dbg("%s - returns %d", __func__, chars); + dev_dbg(&port->dev, "%s - returns %d\n", __func__, chars); return chars; } @@ -1201,18 +1162,12 @@ static void mos7840_close(struct usb_serial_port *port) int j; __u16 Data; - dbg("%s", "mos7840_close:entering..."); - - if (mos7840_port_paranoia_check(port, __func__)) { - dbg("%s", "Port Paranoia failed"); + if (mos7840_port_paranoia_check(port, __func__)) return; - } serial = mos7840_get_usb_serial(port, __func__); - if (!serial) { - dbg("%s", "Serial Paranoia failed"); + if (!serial) return; - } mos7840_port = mos7840_get_port_private(port); port0 = mos7840_get_port_private(serial->port[0]); @@ -1234,39 +1189,22 @@ static void mos7840_close(struct usb_serial_port *port) } } - /* While closing port, shutdown all bulk read, write * - * and interrupt read if they exists */ - if (serial->dev) { - if (mos7840_port->write_urb) { - dbg("%s", "Shutdown bulk write"); - usb_kill_urb(mos7840_port->write_urb); - } - if (mos7840_port->read_urb) { - dbg("%s", "Shutdown bulk read"); - usb_kill_urb(mos7840_port->read_urb); - mos7840_port->read_urb_busy = false; - } - if ((&mos7840_port->control_urb)) { - dbg("%s", "Shutdown control read"); - /*/ usb_kill_urb (mos7840_port->control_urb); */ - } - } -/* if(mos7840_port->ctrl_buf != NULL) */ -/* kfree(mos7840_port->ctrl_buf); */ + usb_kill_urb(mos7840_port->write_urb); + usb_kill_urb(mos7840_port->read_urb); + mos7840_port->read_urb_busy = false; + port0->open_ports--; - dbg("mos7840_num_open_ports in close%d:in port%d", - port0->open_ports, port->number); + dev_dbg(&port->dev, "%s in close%d\n", __func__, port0->open_ports); if (port0->open_ports == 0) { if (serial->port[0]->interrupt_in_urb) { - dbg("%s", "Shutdown interrupt_in_urb"); + dev_dbg(&port->dev, "Shutdown interrupt_in_urb\n"); usb_kill_urb(serial->port[0]->interrupt_in_urb); } } if (mos7840_port->write_urb) { /* if this urb had a transfer buffer already (old tx) free it */ - if (mos7840_port->write_urb->transfer_buffer != NULL) - kfree(mos7840_port->write_urb->transfer_buffer); + kfree(mos7840_port->write_urb->transfer_buffer); usb_free_urb(mos7840_port->write_urb); } @@ -1277,49 +1215,6 @@ static void mos7840_close(struct usb_serial_port *port) mos7840_set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data); mos7840_port->open = 0; - - dbg("%s", "Leaving ............"); -} - -/************************************************************************ - * - * mos7840_block_until_chase_response - * - * This function will block the close until one of the following: - * 1. Response to our Chase comes from mos7840 - * 2. A timeout of 10 seconds without activity has expired - * (1K of mos7840 data @ 2400 baud ==> 4 sec to empty) - * - ************************************************************************/ - -static void mos7840_block_until_chase_response(struct tty_struct *tty, - struct moschip_port *mos7840_port) -{ - int timeout = 1 * HZ; - int wait = 10; - int count; - - while (1) { - count = mos7840_chars_in_buffer(tty); - - /* Check for Buffer status */ - if (count <= 0) - return; - - /* Block the thread for a while */ - interruptible_sleep_on_timeout(&mos7840_port->wait_chase, - timeout); - /* No activity.. count down section */ - wait--; - if (wait == 0) { - dbg("%s - TIMEOUT", __func__); - return; - } else { - /* Reset timeout value back to seconds */ - wait = 10; - } - } - } /***************************************************************************** @@ -1333,29 +1228,18 @@ static void mos7840_break(struct tty_struct *tty, int break_state) struct usb_serial *serial; struct moschip_port *mos7840_port; - dbg("%s", "Entering ..........."); - dbg("mos7840_break: Start"); - - if (mos7840_port_paranoia_check(port, __func__)) { - dbg("%s", "Port Paranoia failed"); + if (mos7840_port_paranoia_check(port, __func__)) return; - } serial = mos7840_get_usb_serial(port, __func__); - if (!serial) { - dbg("%s", "Serial Paranoia failed"); + if (!serial) return; - } mos7840_port = mos7840_get_port_private(port); if (mos7840_port == NULL) return; - if (serial->dev) - /* flush and block until tx is empty */ - mos7840_block_until_chase_response(tty, mos7840_port); - if (break_state == -1) data = mos7840_port->shadowLCR | LCR_SET_BREAK; else @@ -1363,8 +1247,7 @@ static void mos7840_break(struct tty_struct *tty, int break_state) /* FIXME: no locking on shadowLCR anywhere in driver */ mos7840_port->shadowLCR = data; - dbg("mcs7840_break mos7840_port->shadowLCR is %x", - mos7840_port->shadowLCR); + dev_dbg(&port->dev, "%s mos7840_port->shadowLCR is %x\n", __func__, mos7840_port->shadowLCR); mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, mos7840_port->shadowLCR); } @@ -1385,19 +1268,12 @@ static int mos7840_write_room(struct tty_struct *tty) unsigned long flags; struct moschip_port *mos7840_port; - dbg("%s", " mos7840_write_room:entering ..........."); - - if (mos7840_port_paranoia_check(port, __func__)) { - dbg("%s", "Invalid port"); - dbg("%s", " mos7840_write_room:leaving ..........."); + if (mos7840_port_paranoia_check(port, __func__)) return -1; - } mos7840_port = mos7840_get_port_private(port); - if (mos7840_port == NULL) { - dbg("%s", "mos7840_break:leaving ..........."); + if (mos7840_port == NULL) return -1; - } spin_lock_irqsave(&mos7840_port->pool_lock, flags); for (i = 0; i < NUM_URBS; ++i) { @@ -1407,7 +1283,7 @@ static int mos7840_write_room(struct tty_struct *tty) spin_unlock_irqrestore(&mos7840_port->pool_lock, flags); room = (room == 0) ? 0 : room - URB_TRANSFER_BUFFER_SIZE + 1; - dbg("%s - returns %d", __func__, room); + dev_dbg(&mos7840_port->port->dev, "%s - returns %d\n", __func__, room); return room; } @@ -1435,17 +1311,13 @@ static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port, /* __u16 Data; */ const unsigned char *current_position = data; unsigned char *data1; - dbg("%s", "entering ..........."); - /* dbg("mos7840_write: mos7840_port->shadowLCR is %x", - mos7840_port->shadowLCR); */ #ifdef NOTMOS7840 Data = 0x00; status = mos7840_get_uart_reg(port, LINE_CONTROL_REGISTER, &Data); mos7840_port->shadowLCR = Data; - dbg("mos7840_write: LINE_CONTROL_REGISTER is %x", Data); - dbg("mos7840_write: mos7840_port->shadowLCR is %x", - mos7840_port->shadowLCR); + dev_dbg(&port->dev, "%s: LINE_CONTROL_REGISTER is %x\n", __func__, Data); + dev_dbg(&port->dev, "%s: mos7840_port->shadowLCR is %x\n", __func__, mos7840_port->shadowLCR); /* Data = 0x03; */ /* status = mos7840_set_uart_reg(port,LINE_CONTROL_REGISTER,Data); */ @@ -1458,34 +1330,27 @@ static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port, /* status = mos7840_set_uart_reg(port,DIVISOR_LATCH_LSB,Data); */ Data = 0x00; status = mos7840_get_uart_reg(port, DIVISOR_LATCH_LSB, &Data); - dbg("mos7840_write:DLL value is %x", Data); + dev_dbg(&port->dev, "%s: DLL value is %x\n", __func__, Data); Data = 0x0; status = mos7840_get_uart_reg(port, DIVISOR_LATCH_MSB, &Data); - dbg("mos7840_write:DLM value is %x", Data); + dev_dbg(&port->dev, "%s: DLM value is %x\n", __func__, Data); Data = Data & ~SERIAL_LCR_DLAB; - dbg("mos7840_write: mos7840_port->shadowLCR is %x", - mos7840_port->shadowLCR); + dev_dbg(&port->dev, "%s: mos7840_port->shadowLCR is %x\n", __func__, mos7840_port->shadowLCR); status = mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data); #endif - if (mos7840_port_paranoia_check(port, __func__)) { - dbg("%s", "Port Paranoia failed"); + if (mos7840_port_paranoia_check(port, __func__)) return -1; - } serial = port->serial; - if (mos7840_serial_paranoia_check(serial, __func__)) { - dbg("%s", "Serial Paranoia failed"); + if (mos7840_serial_paranoia_check(serial, __func__)) return -1; - } mos7840_port = mos7840_get_port_private(port); - if (mos7840_port == NULL) { - dbg("%s", "mos7840_port is NULL"); + if (mos7840_port == NULL) return -1; - } /* try to find a free urb in the list */ urb = NULL; @@ -1495,57 +1360,65 @@ static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port, if (!mos7840_port->busy[i]) { mos7840_port->busy[i] = 1; urb = mos7840_port->write_urb_pool[i]; - dbg("URB:%d", i); + dev_dbg(&port->dev, "URB:%d\n", i); break; } } spin_unlock_irqrestore(&mos7840_port->pool_lock, flags); if (urb == NULL) { - dbg("%s - no more free urbs", __func__); + dev_dbg(&port->dev, "%s - no more free urbs\n", __func__); goto exit; } if (urb->transfer_buffer == NULL) { urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL); - - if (urb->transfer_buffer == NULL) { - dev_err(&port->dev, "%s no more kernel memory...\n", - __func__); + if (!urb->transfer_buffer) goto exit; - } } transfer_size = min(count, URB_TRANSFER_BUFFER_SIZE); memcpy(urb->transfer_buffer, current_position, transfer_size); /* fill urb with data and submit */ - usb_fill_bulk_urb(urb, - serial->dev, - usb_sndbulkpipe(serial->dev, - port->bulk_out_endpointAddress), - urb->transfer_buffer, - transfer_size, - mos7840_bulk_out_data_callback, mos7840_port); + if ((serial->num_ports == 2) && (((__u16)port->port_number % 2) != 0)) { + usb_fill_bulk_urb(urb, + serial->dev, + usb_sndbulkpipe(serial->dev, + (port->bulk_out_endpointAddress) + 2), + urb->transfer_buffer, + transfer_size, + mos7840_bulk_out_data_callback, mos7840_port); + } else { + usb_fill_bulk_urb(urb, + serial->dev, + usb_sndbulkpipe(serial->dev, + port->bulk_out_endpointAddress), + urb->transfer_buffer, + transfer_size, + mos7840_bulk_out_data_callback, mos7840_port); + } data1 = urb->transfer_buffer; - dbg("bulkout endpoint is %d", port->bulk_out_endpointAddress); + dev_dbg(&port->dev, "bulkout endpoint is %d\n", port->bulk_out_endpointAddress); + + if (mos7840_port->has_led) + mos7840_led_activity(port); /* send it down the pipe */ status = usb_submit_urb(urb, GFP_ATOMIC); if (status) { mos7840_port->busy[i] = 0; - dev_err(&port->dev, "%s - usb_submit_urb(write bulk) failed " + dev_err_console(port, "%s - usb_submit_urb(write bulk) failed " "with status = %d\n", __func__, status); bytes_sent = status; goto exit; } bytes_sent = transfer_size; - mos7840_port->icount.tx += transfer_size; - smp_wmb(); - dbg("mos7840_port->icount.tx is %d:", mos7840_port->icount.tx); + port->icount.tx += transfer_size; + dev_dbg(&port->dev, "icount.tx is %d:\n", port->icount.tx); exit: return bytes_sent; @@ -1563,12 +1436,8 @@ static void mos7840_throttle(struct tty_struct *tty) struct moschip_port *mos7840_port; int status; - if (mos7840_port_paranoia_check(port, __func__)) { - dbg("%s", "Invalid port"); + if (mos7840_port_paranoia_check(port, __func__)) return; - } - - dbg("- port %d", port->number); mos7840_port = mos7840_get_port_private(port); @@ -1576,12 +1445,10 @@ static void mos7840_throttle(struct tty_struct *tty) return; if (!mos7840_port->open) { - dbg("%s", "port not opened"); + dev_dbg(&port->dev, "%s", "port not opened\n"); return; } - dbg("%s", "Entering .........."); - /* if we are implementing XON/XOFF, send the stop character */ if (I_IXOFF(tty)) { unsigned char stop_char = STOP_CHAR(tty); @@ -1590,7 +1457,7 @@ static void mos7840_throttle(struct tty_struct *tty) return; } /* if we are implementing RTS/CTS, toggle that line */ - if (tty->termios->c_cflag & CRTSCTS) { + if (tty->termios.c_cflag & CRTSCTS) { mos7840_port->shadowMCR &= ~MCR_RTS; status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, mos7840_port->shadowMCR); @@ -1611,21 +1478,17 @@ static void mos7840_unthrottle(struct tty_struct *tty) int status; struct moschip_port *mos7840_port = mos7840_get_port_private(port); - if (mos7840_port_paranoia_check(port, __func__)) { - dbg("%s", "Invalid port"); + if (mos7840_port_paranoia_check(port, __func__)) return; - } if (mos7840_port == NULL) return; if (!mos7840_port->open) { - dbg("%s - port not opened", __func__); + dev_dbg(&port->dev, "%s - port not opened\n", __func__); return; } - dbg("%s", "Entering .........."); - /* if we are implementing XON/XOFF, send the start character */ if (I_IXOFF(tty)) { unsigned char start_char = START_CHAR(tty); @@ -1635,7 +1498,7 @@ static void mos7840_unthrottle(struct tty_struct *tty) } /* if we are implementing RTS/CTS, toggle that line */ - if (tty->termios->c_cflag & CRTSCTS) { + if (tty->termios.c_cflag & CRTSCTS) { mos7840_port->shadowMCR |= MCR_RTS; status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, mos7840_port->shadowMCR); @@ -1644,7 +1507,7 @@ static void mos7840_unthrottle(struct tty_struct *tty) } } -static int mos7840_tiocmget(struct tty_struct *tty, struct file *file) +static int mos7840_tiocmget(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; struct moschip_port *mos7840_port; @@ -1654,13 +1517,15 @@ static int mos7840_tiocmget(struct tty_struct *tty, struct file *file) int status; mos7840_port = mos7840_get_port_private(port); - dbg("%s - port %d", __func__, port->number); - if (mos7840_port == NULL) return -ENODEV; status = mos7840_get_uart_reg(port, MODEM_STATUS_REGISTER, &msr); + if (status != 1) + return -EIO; status = mos7840_get_uart_reg(port, MODEM_CONTROL_REGISTER, &mcr); + if (status != 1) + return -EIO; result = ((mcr & MCR_DTR) ? TIOCM_DTR : 0) | ((mcr & MCR_RTS) ? TIOCM_RTS : 0) | ((mcr & MCR_LOOPBACK) ? TIOCM_LOOP : 0) @@ -1669,12 +1534,12 @@ static int mos7840_tiocmget(struct tty_struct *tty, struct file *file) | ((msr & MOS7840_MSR_RI) ? TIOCM_RI : 0) | ((msr & MOS7840_MSR_DSR) ? TIOCM_DSR : 0); - dbg("%s - 0x%04X", __func__, result); + dev_dbg(&port->dev, "%s - 0x%04X\n", __func__, result); return result; } -static int mos7840_tiocmset(struct tty_struct *tty, struct file *file, +static int mos7840_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) { struct usb_serial_port *port = tty->driver_data; @@ -1682,8 +1547,6 @@ static int mos7840_tiocmset(struct tty_struct *tty, struct file *file, unsigned int mcr; int status; - dbg("%s - port %d", __func__, port->number); - mos7840_port = mos7840_get_port_private(port); if (mos7840_port == NULL) @@ -1709,7 +1572,7 @@ static int mos7840_tiocmset(struct tty_struct *tty, struct file *file, status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, mcr); if (status < 0) { - dbg("setting MODEM_CONTROL_REGISTER Failed"); + dev_dbg(&port->dev, "setting MODEM_CONTROL_REGISTER Failed\n"); return status; } @@ -1721,11 +1584,11 @@ static int mos7840_tiocmset(struct tty_struct *tty, struct file *file, * this function calculates the proper baud rate divisor for the specified * baud rate. *****************************************************************************/ -static int mos7840_calc_baud_rate_divisor(int baudRate, int *divisor, +static int mos7840_calc_baud_rate_divisor(struct usb_serial_port *port, + int baudRate, int *divisor, __u16 *clk_sel_val) { - - dbg("%s - %d", __func__, baudRate); + dev_dbg(&port->dev, "%s - %d\n", __func__, baudRate); if (baudRate <= 115200) { *divisor = 115200 / baudRate; @@ -1778,11 +1641,11 @@ static int mos7840_calc_baud_rate_divisor(int baudRate, int *divisor, custom++; *divisor = custom; - dbg(" Baud %d = %d", baudrate, custom); + dev_dbg(&port->dev, " Baud %d = %d\n", baudrate, custom); return 0; } - dbg("%s", " Baud calculation Failed..."); + dev_dbg(&port->dev, "%s", " Baud calculation Failed...\n"); return -1; #endif } @@ -1806,23 +1669,16 @@ static int mos7840_send_cmd_write_baud_rate(struct moschip_port *mos7840_port, if (mos7840_port == NULL) return -1; - port = (struct usb_serial_port *)mos7840_port->port; - if (mos7840_port_paranoia_check(port, __func__)) { - dbg("%s", "Invalid port"); + port = mos7840_port->port; + if (mos7840_port_paranoia_check(port, __func__)) return -1; - } - if (mos7840_serial_paranoia_check(port->serial, __func__)) { - dbg("%s", "Invalid Serial"); + if (mos7840_serial_paranoia_check(port->serial, __func__)) return -1; - } - - dbg("%s", "Entering .........."); - number = mos7840_port->port->number - mos7840_port->port->serial->minor; + number = mos7840_port->port->port_number; - dbg("%s - port = %d, baud = %d", __func__, - mos7840_port->port->number, baudRate); + dev_dbg(&port->dev, "%s - baud = %d\n", __func__, baudRate); /* reset clk_uart_sel in spregOffset */ if (baudRate > 115200) { #ifdef HW_flow_control @@ -1833,20 +1689,20 @@ static int mos7840_send_cmd_write_baud_rate(struct moschip_port *mos7840_port, status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data); if (status < 0) { - dbg("Writing spreg failed in set_serial_baud"); + dev_dbg(&port->dev, "Writing spreg failed in set_serial_baud\n"); return -1; } #endif } else { #ifdef HW_flow_control - / *setting h/w flow control bit to 0 */ + /* setting h/w flow control bit to 0 */ Data = 0xb; mos7840_port->shadowMCR = Data; status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data); if (status < 0) { - dbg("Writing spreg failed in set_serial_baud"); + dev_dbg(&port->dev, "Writing spreg failed in set_serial_baud\n"); return -1; } #endif @@ -1856,19 +1712,19 @@ static int mos7840_send_cmd_write_baud_rate(struct moschip_port *mos7840_port, if (1) { /* baudRate <= 115200) */ clk_sel_val = 0x0; Data = 0x0; - status = mos7840_calc_baud_rate_divisor(baudRate, &divisor, + status = mos7840_calc_baud_rate_divisor(port, baudRate, &divisor, &clk_sel_val); status = mos7840_get_reg_sync(port, mos7840_port->SpRegOffset, &Data); if (status < 0) { - dbg("reading spreg failed in set_serial_baud"); + dev_dbg(&port->dev, "reading spreg failed in set_serial_baud\n"); return -1; } Data = (Data & 0x8f) | clk_sel_val; status = mos7840_set_reg_sync(port, mos7840_port->SpRegOffset, Data); if (status < 0) { - dbg("Writing spreg failed in set_serial_baud"); + dev_dbg(&port->dev, "Writing spreg failed in set_serial_baud\n"); return -1; } /* Calculate the Divisor */ @@ -1884,11 +1740,11 @@ static int mos7840_send_cmd_write_baud_rate(struct moschip_port *mos7840_port, /* Write the divisor */ Data = (unsigned char)(divisor & 0xff); - dbg("set_serial_baud Value to write DLL is %x", Data); + dev_dbg(&port->dev, "set_serial_baud Value to write DLL is %x\n", Data); mos7840_set_uart_reg(port, DIVISOR_LATCH_LSB, Data); Data = (unsigned char)((divisor & 0xff00) >> 8); - dbg("set_serial_baud Value to write DLM is %x", Data); + dev_dbg(&port->dev, "set_serial_baud Value to write DLM is %x\n", Data); mos7840_set_uart_reg(port, DIVISOR_LATCH_MSB, Data); /* Disable access to divisor latch */ @@ -1923,68 +1779,60 @@ static void mos7840_change_port_settings(struct tty_struct *tty, if (mos7840_port == NULL) return; - port = (struct usb_serial_port *)mos7840_port->port; + port = mos7840_port->port; - if (mos7840_port_paranoia_check(port, __func__)) { - dbg("%s", "Invalid port"); + if (mos7840_port_paranoia_check(port, __func__)) return; - } - if (mos7840_serial_paranoia_check(port->serial, __func__)) { - dbg("%s", "Invalid Serial"); + if (mos7840_serial_paranoia_check(port->serial, __func__)) return; - } serial = port->serial; - dbg("%s - port %d", __func__, mos7840_port->port->number); - if (!mos7840_port->open) { - dbg("%s - port not opened", __func__); + dev_dbg(&port->dev, "%s - port not opened\n", __func__); return; } - dbg("%s", "Entering .........."); - lData = LCR_BITS_8; lStop = LCR_STOP_1; lParity = LCR_PAR_NONE; - cflag = tty->termios->c_cflag; - iflag = tty->termios->c_iflag; + cflag = tty->termios.c_cflag; + iflag = tty->termios.c_iflag; /* Change the number of bits */ - if (cflag & CSIZE) { - switch (cflag & CSIZE) { - case CS5: - lData = LCR_BITS_5; - break; + switch (cflag & CSIZE) { + case CS5: + lData = LCR_BITS_5; + break; - case CS6: - lData = LCR_BITS_6; - break; + case CS6: + lData = LCR_BITS_6; + break; - case CS7: - lData = LCR_BITS_7; - break; - default: - case CS8: - lData = LCR_BITS_8; - break; - } + case CS7: + lData = LCR_BITS_7; + break; + + default: + case CS8: + lData = LCR_BITS_8; + break; } + /* Change the Parity bit */ if (cflag & PARENB) { if (cflag & PARODD) { lParity = LCR_PAR_ODD; - dbg("%s - parity = odd", __func__); + dev_dbg(&port->dev, "%s - parity = odd\n", __func__); } else { lParity = LCR_PAR_EVEN; - dbg("%s - parity = even", __func__); + dev_dbg(&port->dev, "%s - parity = even\n", __func__); } } else { - dbg("%s - parity = none", __func__); + dev_dbg(&port->dev, "%s - parity = none\n", __func__); } if (cflag & CMSPAR) @@ -1993,10 +1841,10 @@ static void mos7840_change_port_settings(struct tty_struct *tty, /* Change the Stop bit */ if (cflag & CSTOPB) { lStop = LCR_STOP_2; - dbg("%s - stop bits = 2", __func__); + dev_dbg(&port->dev, "%s - stop bits = 2\n", __func__); } else { lStop = LCR_STOP_1; - dbg("%s - stop bits = 1", __func__); + dev_dbg(&port->dev, "%s - stop bits = 1\n", __func__); } /* Update the LCR with the correct value */ @@ -2004,8 +1852,8 @@ static void mos7840_change_port_settings(struct tty_struct *tty, ~(LCR_BITS_MASK | LCR_STOP_MASK | LCR_PAR_MASK); mos7840_port->shadowLCR |= (lData | lParity | lStop); - dbg("mos7840_change_port_settings mos7840_port->shadowLCR is %x", - mos7840_port->shadowLCR); + dev_dbg(&port->dev, "%s - mos7840_port->shadowLCR is %x\n", __func__, + mos7840_port->shadowLCR); /* Disable Interrupts */ Data = 0x00; mos7840_set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data); @@ -2046,11 +1894,11 @@ static void mos7840_change_port_settings(struct tty_struct *tty, if (!baud) { /* pick a default, any default... */ - dbg("%s", "Picked default baud..."); + dev_dbg(&port->dev, "%s", "Picked default baud...\n"); baud = 9600; } - dbg("%s - baud rate = %d", __func__, baud); + dev_dbg(&port->dev, "%s - baud rate = %d\n", __func__, baud); status = mos7840_send_cmd_write_baud_rate(mos7840_port, baud); /* Enable Interrupts */ @@ -2058,19 +1906,16 @@ static void mos7840_change_port_settings(struct tty_struct *tty, mos7840_set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data); if (mos7840_port->read_urb_busy == false) { - mos7840_port->read_urb->dev = serial->dev; mos7840_port->read_urb_busy = true; status = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC); if (status) { - dbg("usb_submit_urb(read bulk) failed, status = %d", + dev_dbg(&port->dev, "usb_submit_urb(read bulk) failed, status = %d\n", status); mos7840_port->read_urb_busy = false; } } - wake_up(&mos7840_port->delta_msr_wait); - mos7840_port->delta_msr_cond = 1; - dbg("mos7840_change_port_settings mos7840_port->shadowLCR is End %x", - mos7840_port->shadowLCR); + dev_dbg(&port->dev, "%s - mos7840_port->shadowLCR is End %x\n", __func__, + mos7840_port->shadowLCR); } /***************************************************************************** @@ -2087,18 +1932,14 @@ static void mos7840_set_termios(struct tty_struct *tty, unsigned int cflag; struct usb_serial *serial; struct moschip_port *mos7840_port; - dbg("mos7840_set_termios: START"); - if (mos7840_port_paranoia_check(port, __func__)) { - dbg("%s", "Invalid port"); + + if (mos7840_port_paranoia_check(port, __func__)) return; - } serial = port->serial; - if (mos7840_serial_paranoia_check(serial, __func__)) { - dbg("%s", "Invalid Serial"); + if (mos7840_serial_paranoia_check(serial, __func__)) return; - } mos7840_port = mos7840_get_port_private(port); @@ -2106,35 +1947,33 @@ static void mos7840_set_termios(struct tty_struct *tty, return; if (!mos7840_port->open) { - dbg("%s - port not opened", __func__); + dev_dbg(&port->dev, "%s - port not opened\n", __func__); return; } - dbg("%s", "setting termios - "); + dev_dbg(&port->dev, "%s", "setting termios - \n"); - cflag = tty->termios->c_cflag; + cflag = tty->termios.c_cflag; - dbg("%s - clfag %08x iflag %08x", __func__, - tty->termios->c_cflag, RELEVANT_IFLAG(tty->termios->c_iflag)); - dbg("%s - old clfag %08x old iflag %08x", __func__, - old_termios->c_cflag, RELEVANT_IFLAG(old_termios->c_iflag)); - dbg("%s - port %d", __func__, port->number); + dev_dbg(&port->dev, "%s - clfag %08x iflag %08x\n", __func__, + tty->termios.c_cflag, RELEVANT_IFLAG(tty->termios.c_iflag)); + dev_dbg(&port->dev, "%s - old clfag %08x old iflag %08x\n", __func__, + old_termios->c_cflag, RELEVANT_IFLAG(old_termios->c_iflag)); /* change the port settings to the new ones specified */ mos7840_change_port_settings(tty, mos7840_port, old_termios); if (!mos7840_port->read_urb) { - dbg("%s", "URB KILLED !!!!!"); + dev_dbg(&port->dev, "%s", "URB KILLED !!!!!\n"); return; } if (mos7840_port->read_urb_busy == false) { - mos7840_port->read_urb->dev = serial->dev; mos7840_port->read_urb_busy = true; status = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC); if (status) { - dbg("usb_submit_urb(read bulk) failed, status = %d", + dev_dbg(&port->dev, "usb_submit_urb(read bulk) failed, status = %d\n", status); mos7840_port->read_urb_busy = false; } @@ -2159,10 +1998,8 @@ static int mos7840_get_lsr_info(struct tty_struct *tty, unsigned int result = 0; count = mos7840_chars_in_buffer(tty); - if (count == 0) { - dbg("%s -- Empty", __func__); + if (count == 0) result = TIOCSER_TEMT; - } if (copy_to_user(value, &result, sizeof(int))) return -EFAULT; @@ -2188,8 +2025,8 @@ static int mos7840_get_serial_info(struct moschip_port *mos7840_port, memset(&tmp, 0, sizeof(tmp)); tmp.type = PORT_16550A; - tmp.line = mos7840_port->port->serial->minor; - tmp.port = mos7840_port->port->number; + tmp.line = mos7840_port->port->minor; + tmp.port = mos7840_port->port->port_number; tmp.irq = 0; tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ; tmp.xmit_fifo_size = NUM_URBS * URB_TRANSFER_BUFFER_SIZE; @@ -2202,458 +2039,407 @@ static int mos7840_get_serial_info(struct moschip_port *mos7840_port, return 0; } -static int mos7840_get_icount(struct tty_struct *tty, - struct serial_icounter_struct *icount) -{ - struct usb_serial_port *port = tty->driver_data; - struct moschip_port *mos7840_port; - struct async_icount cnow; - - mos7840_port = mos7840_get_port_private(port); - cnow = mos7840_port->icount; - - smp_rmb(); - icount->cts = cnow.cts; - icount->dsr = cnow.dsr; - icount->rng = cnow.rng; - icount->dcd = cnow.dcd; - icount->rx = cnow.rx; - icount->tx = cnow.tx; - icount->frame = cnow.frame; - icount->overrun = cnow.overrun; - icount->parity = cnow.parity; - icount->brk = cnow.brk; - icount->buf_overrun = cnow.buf_overrun; - - dbg("%s (%d) TIOCGICOUNT RX=%d, TX=%d", __func__, - port->number, icount->rx, icount->tx); - return 0; -} - /***************************************************************************** * SerialIoctl * this function handles any ioctl calls to the driver *****************************************************************************/ -static int mos7840_ioctl(struct tty_struct *tty, struct file *file, +static int mos7840_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { struct usb_serial_port *port = tty->driver_data; void __user *argp = (void __user *)arg; struct moschip_port *mos7840_port; - struct async_icount cnow; - struct async_icount cprev; - - if (mos7840_port_paranoia_check(port, __func__)) { - dbg("%s", "Invalid port"); + if (mos7840_port_paranoia_check(port, __func__)) return -1; - } mos7840_port = mos7840_get_port_private(port); if (mos7840_port == NULL) return -1; - dbg("%s - port %d, cmd = 0x%x", __func__, port->number, cmd); - switch (cmd) { /* return number of bytes available */ case TIOCSERGETLSR: - dbg("%s (%d) TIOCSERGETLSR", __func__, port->number); + dev_dbg(&port->dev, "%s TIOCSERGETLSR\n", __func__); return mos7840_get_lsr_info(tty, argp); - return 0; case TIOCGSERIAL: - dbg("%s (%d) TIOCGSERIAL", __func__, port->number); + dev_dbg(&port->dev, "%s TIOCGSERIAL\n", __func__); return mos7840_get_serial_info(mos7840_port, argp); case TIOCSSERIAL: - dbg("%s (%d) TIOCSSERIAL", __func__, port->number); + dev_dbg(&port->dev, "%s TIOCSSERIAL\n", __func__); break; - - case TIOCMIWAIT: - dbg("%s (%d) TIOCMIWAIT", __func__, port->number); - cprev = mos7840_port->icount; - while (1) { - /* interruptible_sleep_on(&mos7840_port->delta_msr_wait); */ - mos7840_port->delta_msr_cond = 0; - wait_event_interruptible(mos7840_port->delta_msr_wait, - (mos7840_port-> - delta_msr_cond == 1)); - - /* see if a signal did it */ - if (signal_pending(current)) - return -ERESTARTSYS; - cnow = mos7840_port->icount; - smp_rmb(); - if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && - cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) - return -EIO; /* no change => error */ - if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || - ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || - ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || - ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) { - return 0; - } - cprev = cnow; - } - /* NOTREACHED */ - break; - default: break; } return -ENOIOCTLCMD; } +static int mos7810_check(struct usb_serial *serial) +{ + int i, pass_count = 0; + u8 *buf; + __u16 data = 0, mcr_data = 0; + __u16 test_pattern = 0x55AA; + int res; + + buf = kmalloc(VENDOR_READ_LENGTH, GFP_KERNEL); + if (!buf) + return 0; /* failed to identify 7810 */ + + /* Store MCR setting */ + res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), + MCS_RDREQ, MCS_RD_RTYPE, 0x0300, MODEM_CONTROL_REGISTER, + buf, VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT); + if (res == VENDOR_READ_LENGTH) + mcr_data = *buf; + + for (i = 0; i < 16; i++) { + /* Send the 1-bit test pattern out to MCS7810 test pin */ + usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + MCS_WRREQ, MCS_WR_RTYPE, + (0x0300 | (((test_pattern >> i) & 0x0001) << 1)), + MODEM_CONTROL_REGISTER, NULL, 0, MOS_WDR_TIMEOUT); + + /* Read the test pattern back */ + res = usb_control_msg(serial->dev, + usb_rcvctrlpipe(serial->dev, 0), MCS_RDREQ, + MCS_RD_RTYPE, 0, GPIO_REGISTER, buf, + VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT); + if (res == VENDOR_READ_LENGTH) + data = *buf; + + /* If this is a MCS7810 device, both test patterns must match */ + if (((test_pattern >> i) ^ (~data >> 1)) & 0x0001) + break; + + pass_count++; + } + + /* Restore MCR setting */ + usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), MCS_WRREQ, + MCS_WR_RTYPE, 0x0300 | mcr_data, MODEM_CONTROL_REGISTER, NULL, + 0, MOS_WDR_TIMEOUT); + + kfree(buf); + + if (pass_count == 16) + return 1; + + return 0; +} + +static int mos7840_probe(struct usb_serial *serial, + const struct usb_device_id *id) +{ + u16 product = le16_to_cpu(serial->dev->descriptor.idProduct); + u8 *buf; + int device_type; + + if (product == MOSCHIP_DEVICE_ID_7810 || + product == MOSCHIP_DEVICE_ID_7820) { + device_type = product; + goto out; + } + + buf = kzalloc(VENDOR_READ_LENGTH, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), + MCS_RDREQ, MCS_RD_RTYPE, 0, GPIO_REGISTER, buf, + VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT); + + /* For a MCS7840 device GPIO0 must be set to 1 */ + if (buf[0] & 0x01) + device_type = MOSCHIP_DEVICE_ID_7840; + else if (mos7810_check(serial)) + device_type = MOSCHIP_DEVICE_ID_7810; + else + device_type = MOSCHIP_DEVICE_ID_7820; + + kfree(buf); +out: + usb_set_serial_data(serial, (void *)(unsigned long)device_type); + + return 0; +} + static int mos7840_calc_num_ports(struct usb_serial *serial) { - int mos7840_num_ports = 0; - - dbg("numberofendpoints: cur %d, alt %d", - (int)serial->interface->cur_altsetting->desc.bNumEndpoints, - (int)serial->interface->altsetting->desc.bNumEndpoints); - if (serial->interface->cur_altsetting->desc.bNumEndpoints == 5) { - mos7840_num_ports = serial->num_ports = 2; - } else if (serial->interface->cur_altsetting->desc.bNumEndpoints == 9) { - serial->num_bulk_in = 4; - serial->num_bulk_out = 4; - mos7840_num_ports = serial->num_ports = 4; - } - dbg ("mos7840_num_ports = %d", mos7840_num_ports); + int device_type = (unsigned long)usb_get_serial_data(serial); + int mos7840_num_ports; + + mos7840_num_ports = (device_type >> 4) & 0x000F; + return mos7840_num_ports; } -/**************************************************************************** - * mos7840_startup - ****************************************************************************/ - -static int mos7840_startup(struct usb_serial *serial) +static int mos7840_port_probe(struct usb_serial_port *port) { + struct usb_serial *serial = port->serial; + int device_type = (unsigned long)usb_get_serial_data(serial); struct moschip_port *mos7840_port; - struct usb_device *dev; - int i, status; - + int status; + int pnum; __u16 Data; - dbg("%s", "mos7840_startup :Entering.........."); - if (!serial) { - dbg("%s", "Invalid Handler"); - return -1; - } + /* we set up the pointers to the endpoints in the mos7840_open * + * function, as the structures aren't created yet. */ - dev = serial->dev; + pnum = port->port_number; - dbg("%s", "Entering..."); - dbg ("mos7840_startup: serial = %p", serial); + dev_dbg(&port->dev, "mos7840_startup: configuring port %d\n", pnum); + mos7840_port = kzalloc(sizeof(struct moschip_port), GFP_KERNEL); + if (!mos7840_port) + return -ENOMEM; - /* we set up the pointers to the endpoints in the mos7840_open * - * function, as the structures aren't created yet. */ + /* Initialize all port interrupt end point to port 0 int + * endpoint. Our device has only one interrupt end point + * common to all port */ + + mos7840_port->port = port; + mos7840_set_port_private(port, mos7840_port); + spin_lock_init(&mos7840_port->pool_lock); + + /* minor is not initialised until later by + * usb-serial.c:get_free_serial() and cannot therefore be used + * to index device instances */ + mos7840_port->port_num = pnum + 1; + dev_dbg(&port->dev, "port->minor = %d\n", port->minor); + dev_dbg(&port->dev, "mos7840_port->port_num = %d\n", mos7840_port->port_num); + + if (mos7840_port->port_num == 1) { + mos7840_port->SpRegOffset = 0x0; + mos7840_port->ControlRegOffset = 0x1; + mos7840_port->DcrRegOffset = 0x4; + } else if ((mos7840_port->port_num == 2) && (serial->num_ports == 4)) { + mos7840_port->SpRegOffset = 0x8; + mos7840_port->ControlRegOffset = 0x9; + mos7840_port->DcrRegOffset = 0x16; + } else if ((mos7840_port->port_num == 2) && (serial->num_ports == 2)) { + mos7840_port->SpRegOffset = 0xa; + mos7840_port->ControlRegOffset = 0xb; + mos7840_port->DcrRegOffset = 0x19; + } else if ((mos7840_port->port_num == 3) && (serial->num_ports == 4)) { + mos7840_port->SpRegOffset = 0xa; + mos7840_port->ControlRegOffset = 0xb; + mos7840_port->DcrRegOffset = 0x19; + } else if ((mos7840_port->port_num == 4) && (serial->num_ports == 4)) { + mos7840_port->SpRegOffset = 0xc; + mos7840_port->ControlRegOffset = 0xd; + mos7840_port->DcrRegOffset = 0x1c; + } + mos7840_dump_serial_port(port, mos7840_port); + mos7840_set_port_private(port, mos7840_port); + + /* enable rx_disable bit in control register */ + status = mos7840_get_reg_sync(port, + mos7840_port->ControlRegOffset, &Data); + if (status < 0) { + dev_dbg(&port->dev, "Reading ControlReg failed status-0x%x\n", status); + goto out; + } else + dev_dbg(&port->dev, "ControlReg Reading success val is %x, status%d\n", Data, status); + Data |= 0x08; /* setting driver done bit */ + Data |= 0x04; /* sp1_bit to have cts change reflect in + modem status reg */ - /* set up port private structures */ - for (i = 0; i < serial->num_ports; ++i) { - dbg ("mos7840_startup: configuring port %d............", i); - mos7840_port = kzalloc(sizeof(struct moschip_port), GFP_KERNEL); - if (mos7840_port == NULL) { - dev_err(&dev->dev, "%s - Out of memory\n", __func__); - status = -ENOMEM; - i--; /* don't follow NULL pointer cleaning up */ - goto error; - } + /* Data |= 0x20; //rx_disable bit */ + status = mos7840_set_reg_sync(port, + mos7840_port->ControlRegOffset, Data); + if (status < 0) { + dev_dbg(&port->dev, "Writing ControlReg failed(rx_disable) status-0x%x\n", status); + goto out; + } else + dev_dbg(&port->dev, "ControlReg Writing success(rx_disable) status%d\n", status); - /* Initialize all port interrupt end point to port 0 int - * endpoint. Our device has only one interrupt end point - * common to all port */ - - mos7840_port->port = serial->port[i]; - mos7840_set_port_private(serial->port[i], mos7840_port); - spin_lock_init(&mos7840_port->pool_lock); - - /* minor is not initialised until later by - * usb-serial.c:get_free_serial() and cannot therefore be used - * to index device instances */ - mos7840_port->port_num = i + 1; - dbg ("serial->port[i]->number = %d", serial->port[i]->number); - dbg ("serial->port[i]->serial->minor = %d", serial->port[i]->serial->minor); - dbg ("mos7840_port->port_num = %d", mos7840_port->port_num); - dbg ("serial->minor = %d", serial->minor); - - if (mos7840_port->port_num == 1) { - mos7840_port->SpRegOffset = 0x0; - mos7840_port->ControlRegOffset = 0x1; - mos7840_port->DcrRegOffset = 0x4; - } else if ((mos7840_port->port_num == 2) - && (serial->num_ports == 4)) { - mos7840_port->SpRegOffset = 0x8; - mos7840_port->ControlRegOffset = 0x9; - mos7840_port->DcrRegOffset = 0x16; - } else if ((mos7840_port->port_num == 2) - && (serial->num_ports == 2)) { - mos7840_port->SpRegOffset = 0xa; - mos7840_port->ControlRegOffset = 0xb; - mos7840_port->DcrRegOffset = 0x19; - } else if ((mos7840_port->port_num == 3) - && (serial->num_ports == 4)) { - mos7840_port->SpRegOffset = 0xa; - mos7840_port->ControlRegOffset = 0xb; - mos7840_port->DcrRegOffset = 0x19; - } else if ((mos7840_port->port_num == 4) - && (serial->num_ports == 4)) { - mos7840_port->SpRegOffset = 0xc; - mos7840_port->ControlRegOffset = 0xd; - mos7840_port->DcrRegOffset = 0x1c; - } - mos7840_dump_serial_port(mos7840_port); - mos7840_set_port_private(serial->port[i], mos7840_port); + /* Write default values in DCR (i.e 0x01 in DCR0, 0x05 in DCR2 + and 0x24 in DCR3 */ + Data = 0x01; + status = mos7840_set_reg_sync(port, + (__u16) (mos7840_port->DcrRegOffset + 0), Data); + if (status < 0) { + dev_dbg(&port->dev, "Writing DCR0 failed status-0x%x\n", status); + goto out; + } else + dev_dbg(&port->dev, "DCR0 Writing success status%d\n", status); - /* enable rx_disable bit in control register */ - status = mos7840_get_reg_sync(serial->port[i], - mos7840_port->ControlRegOffset, &Data); - if (status < 0) { - dbg("Reading ControlReg failed status-0x%x", status); - break; - } else - dbg("ControlReg Reading success val is %x, status%d", - Data, status); - Data |= 0x08; /* setting driver done bit */ - Data |= 0x04; /* sp1_bit to have cts change reflect in - modem status reg */ - - /* Data |= 0x20; //rx_disable bit */ - status = mos7840_set_reg_sync(serial->port[i], - mos7840_port->ControlRegOffset, Data); - if (status < 0) { - dbg("Writing ControlReg failed(rx_disable) status-0x%x", status); - break; - } else - dbg("ControlReg Writing success(rx_disable) status%d", - status); + Data = 0x05; + status = mos7840_set_reg_sync(port, + (__u16) (mos7840_port->DcrRegOffset + 1), Data); + if (status < 0) { + dev_dbg(&port->dev, "Writing DCR1 failed status-0x%x\n", status); + goto out; + } else + dev_dbg(&port->dev, "DCR1 Writing success status%d\n", status); - /* Write default values in DCR (i.e 0x01 in DCR0, 0x05 in DCR2 - and 0x24 in DCR3 */ - Data = 0x01; - status = mos7840_set_reg_sync(serial->port[i], - (__u16) (mos7840_port->DcrRegOffset + 0), Data); - if (status < 0) { - dbg("Writing DCR0 failed status-0x%x", status); - break; - } else - dbg("DCR0 Writing success status%d", status); + Data = 0x24; + status = mos7840_set_reg_sync(port, + (__u16) (mos7840_port->DcrRegOffset + 2), Data); + if (status < 0) { + dev_dbg(&port->dev, "Writing DCR2 failed status-0x%x\n", status); + goto out; + } else + dev_dbg(&port->dev, "DCR2 Writing success status%d\n", status); - Data = 0x05; - status = mos7840_set_reg_sync(serial->port[i], - (__u16) (mos7840_port->DcrRegOffset + 1), Data); - if (status < 0) { - dbg("Writing DCR1 failed status-0x%x", status); - break; - } else - dbg("DCR1 Writing success status%d", status); + /* write values in clkstart0x0 and clkmulti 0x20 */ + Data = 0x0; + status = mos7840_set_reg_sync(port, CLK_START_VALUE_REGISTER, Data); + if (status < 0) { + dev_dbg(&port->dev, "Writing CLK_START_VALUE_REGISTER failed status-0x%x\n", status); + goto out; + } else + dev_dbg(&port->dev, "CLK_START_VALUE_REGISTER Writing success status%d\n", status); - Data = 0x24; - status = mos7840_set_reg_sync(serial->port[i], - (__u16) (mos7840_port->DcrRegOffset + 2), Data); - if (status < 0) { - dbg("Writing DCR2 failed status-0x%x", status); - break; - } else - dbg("DCR2 Writing success status%d", status); + Data = 0x20; + status = mos7840_set_reg_sync(port, CLK_MULTI_REGISTER, Data); + if (status < 0) { + dev_dbg(&port->dev, "Writing CLK_MULTI_REGISTER failed status-0x%x\n", status); + goto error; + } else + dev_dbg(&port->dev, "CLK_MULTI_REGISTER Writing success status%d\n", status); - /* write values in clkstart0x0 and clkmulti 0x20 */ - Data = 0x0; - status = mos7840_set_reg_sync(serial->port[i], - CLK_START_VALUE_REGISTER, Data); + /* write value 0x0 to scratchpad register */ + Data = 0x00; + status = mos7840_set_uart_reg(port, SCRATCH_PAD_REGISTER, Data); + if (status < 0) { + dev_dbg(&port->dev, "Writing SCRATCH_PAD_REGISTER failed status-0x%x\n", status); + goto out; + } else + dev_dbg(&port->dev, "SCRATCH_PAD_REGISTER Writing success status%d\n", status); + + /* Zero Length flag register */ + if ((mos7840_port->port_num != 1) && (serial->num_ports == 2)) { + Data = 0xff; + status = mos7840_set_reg_sync(port, + (__u16) (ZLP_REG1 + + ((__u16)mos7840_port->port_num)), Data); + dev_dbg(&port->dev, "ZLIP offset %x\n", + (__u16)(ZLP_REG1 + ((__u16) mos7840_port->port_num))); if (status < 0) { - dbg("Writing CLK_START_VALUE_REGISTER failed status-0x%x", status); - break; + dev_dbg(&port->dev, "Writing ZLP_REG%d failed status-0x%x\n", pnum + 2, status); + goto out; } else - dbg("CLK_START_VALUE_REGISTER Writing success status%d", status); - - Data = 0x20; - status = mos7840_set_reg_sync(serial->port[i], - CLK_MULTI_REGISTER, Data); + dev_dbg(&port->dev, "ZLP_REG%d Writing success status%d\n", pnum + 2, status); + } else { + Data = 0xff; + status = mos7840_set_reg_sync(port, + (__u16) (ZLP_REG1 + + ((__u16)mos7840_port->port_num) - 0x1), Data); + dev_dbg(&port->dev, "ZLIP offset %x\n", + (__u16)(ZLP_REG1 + ((__u16) mos7840_port->port_num) - 0x1)); if (status < 0) { - dbg("Writing CLK_MULTI_REGISTER failed status-0x%x", - status); - goto error; + dev_dbg(&port->dev, "Writing ZLP_REG%d failed status-0x%x\n", pnum + 1, status); + goto out; } else - dbg("CLK_MULTI_REGISTER Writing success status%d", - status); + dev_dbg(&port->dev, "ZLP_REG%d Writing success status%d\n", pnum + 1, status); - /* write value 0x0 to scratchpad register */ - Data = 0x00; - status = mos7840_set_uart_reg(serial->port[i], - SCRATCH_PAD_REGISTER, Data); - if (status < 0) { - dbg("Writing SCRATCH_PAD_REGISTER failed status-0x%x", - status); - break; - } else - dbg("SCRATCH_PAD_REGISTER Writing success status%d", - status); + } + mos7840_port->control_urb = usb_alloc_urb(0, GFP_KERNEL); + mos7840_port->ctrl_buf = kmalloc(16, GFP_KERNEL); + mos7840_port->dr = kmalloc(sizeof(struct usb_ctrlrequest), + GFP_KERNEL); + if (!mos7840_port->control_urb || !mos7840_port->ctrl_buf || + !mos7840_port->dr) { + status = -ENOMEM; + goto error; + } - /* Zero Length flag register */ - if ((mos7840_port->port_num != 1) - && (serial->num_ports == 2)) { - - Data = 0xff; - status = mos7840_set_reg_sync(serial->port[i], - (__u16) (ZLP_REG1 + - ((__u16)mos7840_port->port_num)), Data); - dbg("ZLIP offset %x", - (__u16) (ZLP_REG1 + - ((__u16) mos7840_port->port_num))); - if (status < 0) { - dbg("Writing ZLP_REG%d failed status-0x%x", - i + 2, status); - break; - } else - dbg("ZLP_REG%d Writing success status%d", - i + 2, status); - } else { - Data = 0xff; - status = mos7840_set_reg_sync(serial->port[i], - (__u16) (ZLP_REG1 + - ((__u16)mos7840_port->port_num) - 0x1), Data); - dbg("ZLIP offset %x", - (__u16) (ZLP_REG1 + - ((__u16) mos7840_port->port_num) - 0x1)); - if (status < 0) { - dbg("Writing ZLP_REG%d failed status-0x%x", - i + 1, status); - break; - } else - dbg("ZLP_REG%d Writing success status%d", - i + 1, status); + mos7840_port->has_led = false; - } - mos7840_port->control_urb = usb_alloc_urb(0, GFP_KERNEL); - mos7840_port->ctrl_buf = kmalloc(16, GFP_KERNEL); - mos7840_port->dr = kmalloc(sizeof(struct usb_ctrlrequest), + /* Initialize LED timers */ + if (device_type == MOSCHIP_DEVICE_ID_7810) { + mos7840_port->has_led = true; + + mos7840_port->led_urb = usb_alloc_urb(0, GFP_KERNEL); + mos7840_port->led_dr = kmalloc(sizeof(*mos7840_port->led_dr), GFP_KERNEL); - if (!mos7840_port->control_urb || !mos7840_port->ctrl_buf || - !mos7840_port->dr) { + if (!mos7840_port->led_urb || !mos7840_port->led_dr) { status = -ENOMEM; goto error; } - } - dbg ("mos7840_startup: all ports configured..........."); - /* Zero Length flag enable */ - Data = 0x0f; - status = mos7840_set_reg_sync(serial->port[0], ZLP_REG5, Data); - if (status < 0) { - dbg("Writing ZLP_REG5 failed status-0x%x", status); - goto error; - } else - dbg("ZLP_REG5 Writing success status%d", status); + init_timer(&mos7840_port->led_timer1); + mos7840_port->led_timer1.function = mos7840_led_off; + mos7840_port->led_timer1.expires = + jiffies + msecs_to_jiffies(LED_ON_MS); + mos7840_port->led_timer1.data = (unsigned long)mos7840_port; + + init_timer(&mos7840_port->led_timer2); + mos7840_port->led_timer2.function = mos7840_led_flag_off; + mos7840_port->led_timer2.expires = + jiffies + msecs_to_jiffies(LED_OFF_MS); + mos7840_port->led_timer2.data = (unsigned long)mos7840_port; + + /* Turn off LED */ + mos7840_set_led_sync(port, MODEM_CONTROL_REGISTER, 0x0300); + } +out: + if (pnum == serial->num_ports - 1) { + /* Zero Length flag enable */ + Data = 0x0f; + status = mos7840_set_reg_sync(serial->port[0], ZLP_REG5, Data); + if (status < 0) { + dev_dbg(&port->dev, "Writing ZLP_REG5 failed status-0x%x\n", status); + goto error; + } else + dev_dbg(&port->dev, "ZLP_REG5 Writing success status%d\n", status); - /* setting configuration feature to one */ - usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - (__u8) 0x03, 0x00, 0x01, 0x00, NULL, 0x00, 5 * HZ); + /* setting configuration feature to one */ + usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + 0x03, 0x00, 0x01, 0x00, NULL, 0x00, + MOS_WDR_TIMEOUT); + } return 0; error: - for (/* nothing */; i >= 0; i--) { - mos7840_port = mos7840_get_port_private(serial->port[i]); + kfree(mos7840_port->led_dr); + usb_free_urb(mos7840_port->led_urb); + kfree(mos7840_port->dr); + kfree(mos7840_port->ctrl_buf); + usb_free_urb(mos7840_port->control_urb); + kfree(mos7840_port); - kfree(mos7840_port->dr); - kfree(mos7840_port->ctrl_buf); - usb_free_urb(mos7840_port->control_urb); - kfree(mos7840_port); - serial->port[i] = NULL; - } return status; } -/**************************************************************************** - * mos7840_disconnect - * This function is called whenever the device is removed from the usb bus. - ****************************************************************************/ - -static void mos7840_disconnect(struct usb_serial *serial) +static int mos7840_port_remove(struct usb_serial_port *port) { - int i; - unsigned long flags; struct moschip_port *mos7840_port; - dbg("%s", " disconnect :entering.........."); - - if (!serial) { - dbg("%s", "Invalid Handler"); - return; - } - - /* check for the ports to be closed,close the ports and disconnect */ - - /* free private structure allocated for serial port * - * stop reads and writes on all ports */ - - for (i = 0; i < serial->num_ports; ++i) { - mos7840_port = mos7840_get_port_private(serial->port[i]); - dbg ("mos7840_port %d = %p", i, mos7840_port); - if (mos7840_port) { - spin_lock_irqsave(&mos7840_port->pool_lock, flags); - mos7840_port->zombie = 1; - spin_unlock_irqrestore(&mos7840_port->pool_lock, flags); - usb_kill_urb(mos7840_port->control_urb); - } - } - dbg("%s", "Thank u :: "); + mos7840_port = mos7840_get_port_private(port); -} + if (mos7840_port->has_led) { + /* Turn off LED */ + mos7840_set_led_sync(port, MODEM_CONTROL_REGISTER, 0x0300); -/**************************************************************************** - * mos7840_release - * This function is called when the usb_serial structure is freed. - ****************************************************************************/ + del_timer_sync(&mos7840_port->led_timer1); + del_timer_sync(&mos7840_port->led_timer2); -static void mos7840_release(struct usb_serial *serial) -{ - int i; - struct moschip_port *mos7840_port; - dbg("%s", " release :entering.........."); - - if (!serial) { - dbg("%s", "Invalid Handler"); - return; + usb_kill_urb(mos7840_port->led_urb); + usb_free_urb(mos7840_port->led_urb); + kfree(mos7840_port->led_dr); } + usb_kill_urb(mos7840_port->control_urb); + usb_free_urb(mos7840_port->control_urb); + kfree(mos7840_port->ctrl_buf); + kfree(mos7840_port->dr); + kfree(mos7840_port); - /* check for the ports to be closed,close the ports and disconnect */ - - /* free private structure allocated for serial port * - * stop reads and writes on all ports */ - - for (i = 0; i < serial->num_ports; ++i) { - mos7840_port = mos7840_get_port_private(serial->port[i]); - dbg("mos7840_port %d = %p", i, mos7840_port); - if (mos7840_port) { - kfree(mos7840_port->ctrl_buf); - kfree(mos7840_port->dr); - kfree(mos7840_port); - } - } - - dbg("%s", "Thank u :: "); - + return 0; } -static struct usb_driver io_driver = { - .name = "mos7840", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = moschip_id_table_combined, - .no_dynamic_id = 1, -}; - static struct usb_serial_driver moschip7840_4port_device = { .driver = { .owner = THIS_MODULE, .name = "mos7840", }, .description = DRIVER_DESC, - .usb_driver = &io_driver, - .id_table = moschip_port_id_table, + .id_table = id_table, .num_ports = 4, .open = mos7840_open, .close = mos7840_close, @@ -2663,75 +2449,25 @@ static struct usb_serial_driver moschip7840_4port_device = { .throttle = mos7840_throttle, .unthrottle = mos7840_unthrottle, .calc_num_ports = mos7840_calc_num_ports, -#ifdef MCSSerialProbe - .probe = mos7840_serial_probe, -#endif + .probe = mos7840_probe, .ioctl = mos7840_ioctl, .set_termios = mos7840_set_termios, .break_ctl = mos7840_break, .tiocmget = mos7840_tiocmget, .tiocmset = mos7840_tiocmset, - .get_icount = mos7840_get_icount, - .attach = mos7840_startup, - .disconnect = mos7840_disconnect, - .release = mos7840_release, + .tiocmiwait = usb_serial_generic_tiocmiwait, + .get_icount = usb_serial_generic_get_icount, + .port_probe = mos7840_port_probe, + .port_remove = mos7840_port_remove, .read_bulk_callback = mos7840_bulk_in_callback, .read_int_callback = mos7840_interrupt_callback, }; -/**************************************************************************** - * moschip7840_init - * This is called by the module subsystem, or on startup to initialize us - ****************************************************************************/ -static int __init moschip7840_init(void) -{ - int retval; - - dbg("%s", " mos7840_init :entering.........."); - - /* Register with the usb serial */ - retval = usb_serial_register(&moschip7840_4port_device); - - if (retval) - goto failed_port_device_register; - - dbg("%s", "Entering..."); - printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" - DRIVER_DESC "\n"); - - /* Register with the usb */ - retval = usb_register(&io_driver); - if (retval == 0) { - dbg("%s", "Leaving..."); - return 0; - } - usb_serial_deregister(&moschip7840_4port_device); -failed_port_device_register: - return retval; -} - -/**************************************************************************** - * moschip7840_exit - * Called when the driver is about to be unloaded. - ****************************************************************************/ -static void __exit moschip7840_exit(void) -{ - - dbg("%s", " mos7840_exit :entering.........."); - - usb_deregister(&io_driver); - - usb_serial_deregister(&moschip7840_4port_device); - - dbg("%s", "Entering..."); -} +static struct usb_serial_driver * const serial_drivers[] = { + &moschip7840_4port_device, NULL +}; -module_init(moschip7840_init); -module_exit(moschip7840_exit); +module_usb_serial_driver(serial_drivers, id_table); -/* Module information */ MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/drivers/usb/serial/moto_modem.c b/drivers/usb/serial/moto_modem.c deleted file mode 100644 index cf1718394e1..00000000000 --- a/drivers/usb/serial/moto_modem.c +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Motorola USB Phone driver - * - * Copyright (C) 2008 Greg Kroah-Hartman <greg@kroah.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * {sigh} - * Motorola should be using the CDC ACM USB spec, but instead - * they try to just "do their own thing"... This driver should handle a - * few phones in which a basic "dumb serial connection" is needed to be - * able to get a connection through to them. - */ - -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/tty.h> -#include <linux/module.h> -#include <linux/usb.h> -#include <linux/usb/serial.h> - -static const struct usb_device_id id_table[] = { - { USB_DEVICE(0x05c6, 0x3197) }, /* unknown Motorola phone */ - { USB_DEVICE(0x0c44, 0x0022) }, /* unknown Mororola phone */ - { USB_DEVICE(0x22b8, 0x2a64) }, /* Motorola KRZR K1m */ - { USB_DEVICE(0x22b8, 0x2c64) }, /* Motorola V950 phone */ - { }, -}; -MODULE_DEVICE_TABLE(usb, id_table); - -static struct usb_driver moto_driver = { - .name = "moto-modem", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, - .no_dynamic_id = 1, -}; - -static struct usb_serial_driver moto_device = { - .driver = { - .owner = THIS_MODULE, - .name = "moto-modem", - }, - .id_table = id_table, - .num_ports = 1, -}; - -static int __init moto_init(void) -{ - int retval; - - retval = usb_serial_register(&moto_device); - if (retval) - return retval; - retval = usb_register(&moto_driver); - if (retval) - usb_serial_deregister(&moto_device); - return retval; -} - -static void __exit moto_exit(void) -{ - usb_deregister(&moto_driver); - usb_serial_deregister(&moto_device); -} - -module_init(moto_init); -module_exit(moto_exit); -MODULE_LICENSE("GPL"); diff --git a/drivers/usb/serial/mxuport.c b/drivers/usb/serial/mxuport.c new file mode 100644 index 00000000000..ab1d690274a --- /dev/null +++ b/drivers/usb/serial/mxuport.c @@ -0,0 +1,1393 @@ +/* + * mxuport.c - MOXA UPort series driver + * + * Copyright (c) 2006 Moxa Technologies Co., Ltd. + * Copyright (c) 2013 Andrew Lunn <andrew@lunn.ch> + * + * 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. + * + * Supports the following Moxa USB to serial converters: + * 2 ports : UPort 1250, UPort 1250I + * 4 ports : UPort 1410, UPort 1450, UPort 1450I + * 8 ports : UPort 1610-8, UPort 1650-8 + * 16 ports : UPort 1610-16, UPort 1650-16 + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/firmware.h> +#include <linux/jiffies.h> +#include <linux/serial.h> +#include <linux/serial_reg.h> +#include <linux/slab.h> +#include <linux/tty.h> +#include <linux/tty_driver.h> +#include <linux/tty_flip.h> +#include <linux/uaccess.h> +#include <linux/usb.h> +#include <linux/usb/serial.h> +#include <asm/unaligned.h> + +/* Definitions for the vendor ID and device ID */ +#define MX_USBSERIAL_VID 0x110A +#define MX_UPORT1250_PID 0x1250 +#define MX_UPORT1251_PID 0x1251 +#define MX_UPORT1410_PID 0x1410 +#define MX_UPORT1450_PID 0x1450 +#define MX_UPORT1451_PID 0x1451 +#define MX_UPORT1618_PID 0x1618 +#define MX_UPORT1658_PID 0x1658 +#define MX_UPORT1613_PID 0x1613 +#define MX_UPORT1653_PID 0x1653 + +/* Definitions for USB info */ +#define HEADER_SIZE 4 +#define EVENT_LENGTH 8 +#define DOWN_BLOCK_SIZE 64 + +/* Definitions for firmware info */ +#define VER_ADDR_1 0x20 +#define VER_ADDR_2 0x24 +#define VER_ADDR_3 0x28 + +/* Definitions for USB vendor request */ +#define RQ_VENDOR_NONE 0x00 +#define RQ_VENDOR_SET_BAUD 0x01 /* Set baud rate */ +#define RQ_VENDOR_SET_LINE 0x02 /* Set line status */ +#define RQ_VENDOR_SET_CHARS 0x03 /* Set Xon/Xoff chars */ +#define RQ_VENDOR_SET_RTS 0x04 /* Set RTS */ +#define RQ_VENDOR_SET_DTR 0x05 /* Set DTR */ +#define RQ_VENDOR_SET_XONXOFF 0x06 /* Set auto Xon/Xoff */ +#define RQ_VENDOR_SET_RX_HOST_EN 0x07 /* Set RX host enable */ +#define RQ_VENDOR_SET_OPEN 0x08 /* Set open/close port */ +#define RQ_VENDOR_PURGE 0x09 /* Purge Rx/Tx buffer */ +#define RQ_VENDOR_SET_MCR 0x0A /* Set MCR register */ +#define RQ_VENDOR_SET_BREAK 0x0B /* Set Break signal */ + +#define RQ_VENDOR_START_FW_DOWN 0x0C /* Start firmware download */ +#define RQ_VENDOR_STOP_FW_DOWN 0x0D /* Stop firmware download */ +#define RQ_VENDOR_QUERY_FW_READY 0x0E /* Query if new firmware ready */ + +#define RQ_VENDOR_SET_FIFO_DISABLE 0x0F /* Set fifo disable */ +#define RQ_VENDOR_SET_INTERFACE 0x10 /* Set interface */ +#define RQ_VENDOR_SET_HIGH_PERFOR 0x11 /* Set hi-performance */ + +#define RQ_VENDOR_ERASE_BLOCK 0x12 /* Erase flash block */ +#define RQ_VENDOR_WRITE_PAGE 0x13 /* Write flash page */ +#define RQ_VENDOR_PREPARE_WRITE 0x14 /* Prepare write flash */ +#define RQ_VENDOR_CONFIRM_WRITE 0x15 /* Confirm write flash */ +#define RQ_VENDOR_LOCATE 0x16 /* Locate the device */ + +#define RQ_VENDOR_START_ROM_DOWN 0x17 /* Start firmware download */ +#define RQ_VENDOR_ROM_DATA 0x18 /* Rom file data */ +#define RQ_VENDOR_STOP_ROM_DOWN 0x19 /* Stop firmware download */ +#define RQ_VENDOR_FW_DATA 0x20 /* Firmware data */ + +#define RQ_VENDOR_RESET_DEVICE 0x23 /* Try to reset the device */ +#define RQ_VENDOR_QUERY_FW_CONFIG 0x24 + +#define RQ_VENDOR_GET_VERSION 0x81 /* Get firmware version */ +#define RQ_VENDOR_GET_PAGE 0x82 /* Read flash page */ +#define RQ_VENDOR_GET_ROM_PROC 0x83 /* Get ROM process state */ + +#define RQ_VENDOR_GET_INQUEUE 0x84 /* Data in input buffer */ +#define RQ_VENDOR_GET_OUTQUEUE 0x85 /* Data in output buffer */ + +#define RQ_VENDOR_GET_MSR 0x86 /* Get modem status register */ + +/* Definitions for UPort event type */ +#define UPORT_EVENT_NONE 0 /* None */ +#define UPORT_EVENT_TXBUF_THRESHOLD 1 /* Tx buffer threshold */ +#define UPORT_EVENT_SEND_NEXT 2 /* Send next */ +#define UPORT_EVENT_MSR 3 /* Modem status */ +#define UPORT_EVENT_LSR 4 /* Line status */ +#define UPORT_EVENT_MCR 5 /* Modem control */ + +/* Definitions for serial event type */ +#define SERIAL_EV_CTS 0x0008 /* CTS changed state */ +#define SERIAL_EV_DSR 0x0010 /* DSR changed state */ +#define SERIAL_EV_RLSD 0x0020 /* RLSD changed state */ + +/* Definitions for modem control event type */ +#define SERIAL_EV_XOFF 0x40 /* XOFF received */ + +/* Definitions for line control of communication */ +#define MX_WORDLENGTH_5 5 +#define MX_WORDLENGTH_6 6 +#define MX_WORDLENGTH_7 7 +#define MX_WORDLENGTH_8 8 + +#define MX_PARITY_NONE 0 +#define MX_PARITY_ODD 1 +#define MX_PARITY_EVEN 2 +#define MX_PARITY_MARK 3 +#define MX_PARITY_SPACE 4 + +#define MX_STOP_BITS_1 0 +#define MX_STOP_BITS_1_5 1 +#define MX_STOP_BITS_2 2 + +#define MX_RTS_DISABLE 0x0 +#define MX_RTS_ENABLE 0x1 +#define MX_RTS_HW 0x2 +#define MX_RTS_NO_CHANGE 0x3 /* Flag, not valid register value*/ + +#define MX_INT_RS232 0 +#define MX_INT_2W_RS485 1 +#define MX_INT_RS422 2 +#define MX_INT_4W_RS485 3 + +/* Definitions for holding reason */ +#define MX_WAIT_FOR_CTS 0x0001 +#define MX_WAIT_FOR_DSR 0x0002 +#define MX_WAIT_FOR_DCD 0x0004 +#define MX_WAIT_FOR_XON 0x0008 +#define MX_WAIT_FOR_START_TX 0x0010 +#define MX_WAIT_FOR_UNTHROTTLE 0x0020 +#define MX_WAIT_FOR_LOW_WATER 0x0040 +#define MX_WAIT_FOR_SEND_NEXT 0x0080 + +#define MX_UPORT_2_PORT BIT(0) +#define MX_UPORT_4_PORT BIT(1) +#define MX_UPORT_8_PORT BIT(2) +#define MX_UPORT_16_PORT BIT(3) + +/* This structure holds all of the local port information */ +struct mxuport_port { + u8 mcr_state; /* Last MCR state */ + u8 msr_state; /* Last MSR state */ + struct mutex mutex; /* Protects mcr_state */ + spinlock_t spinlock; /* Protects msr_state */ +}; + +/* Table of devices that work with this driver */ +static const struct usb_device_id mxuport_idtable[] = { + { USB_DEVICE(MX_USBSERIAL_VID, MX_UPORT1250_PID), + .driver_info = MX_UPORT_2_PORT }, + { USB_DEVICE(MX_USBSERIAL_VID, MX_UPORT1251_PID), + .driver_info = MX_UPORT_2_PORT }, + { USB_DEVICE(MX_USBSERIAL_VID, MX_UPORT1410_PID), + .driver_info = MX_UPORT_4_PORT }, + { USB_DEVICE(MX_USBSERIAL_VID, MX_UPORT1450_PID), + .driver_info = MX_UPORT_4_PORT }, + { USB_DEVICE(MX_USBSERIAL_VID, MX_UPORT1451_PID), + .driver_info = MX_UPORT_4_PORT }, + { USB_DEVICE(MX_USBSERIAL_VID, MX_UPORT1618_PID), + .driver_info = MX_UPORT_8_PORT }, + { USB_DEVICE(MX_USBSERIAL_VID, MX_UPORT1658_PID), + .driver_info = MX_UPORT_8_PORT }, + { USB_DEVICE(MX_USBSERIAL_VID, MX_UPORT1613_PID), + .driver_info = MX_UPORT_16_PORT }, + { USB_DEVICE(MX_USBSERIAL_VID, MX_UPORT1653_PID), + .driver_info = MX_UPORT_16_PORT }, + {} /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE(usb, mxuport_idtable); + +/* + * Add a four byte header containing the port number and the number of + * bytes of data in the message. Return the number of bytes in the + * buffer. + */ +static int mxuport_prepare_write_buffer(struct usb_serial_port *port, + void *dest, size_t size) +{ + u8 *buf = dest; + int count; + + count = kfifo_out_locked(&port->write_fifo, buf + HEADER_SIZE, + size - HEADER_SIZE, + &port->lock); + + put_unaligned_be16(port->port_number, buf); + put_unaligned_be16(count, buf + 2); + + dev_dbg(&port->dev, "%s - size %zd count %d\n", __func__, + size, count); + + return count + HEADER_SIZE; +} + +/* Read the given buffer in from the control pipe. */ +static int mxuport_recv_ctrl_urb(struct usb_serial *serial, + u8 request, u16 value, u16 index, + u8 *data, size_t size) +{ + int status; + + status = usb_control_msg(serial->dev, + usb_rcvctrlpipe(serial->dev, 0), + request, + (USB_DIR_IN | USB_TYPE_VENDOR | + USB_RECIP_DEVICE), value, index, + data, size, + USB_CTRL_GET_TIMEOUT); + if (status < 0) { + dev_err(&serial->interface->dev, + "%s - usb_control_msg failed (%d)\n", + __func__, status); + return status; + } + + if (status != size) { + dev_err(&serial->interface->dev, + "%s - short read (%d / %zd)\n", + __func__, status, size); + return -EIO; + } + + return status; +} + +/* Write the given buffer out to the control pipe. */ +static int mxuport_send_ctrl_data_urb(struct usb_serial *serial, + u8 request, + u16 value, u16 index, + u8 *data, size_t size) +{ + int status; + + status = usb_control_msg(serial->dev, + usb_sndctrlpipe(serial->dev, 0), + request, + (USB_DIR_OUT | USB_TYPE_VENDOR | + USB_RECIP_DEVICE), value, index, + data, size, + USB_CTRL_SET_TIMEOUT); + if (status < 0) { + dev_err(&serial->interface->dev, + "%s - usb_control_msg failed (%d)\n", + __func__, status); + return status; + } + + if (status != size) { + dev_err(&serial->interface->dev, + "%s - short write (%d / %zd)\n", + __func__, status, size); + return -EIO; + } + + return 0; +} + +/* Send a vendor request without any data */ +static int mxuport_send_ctrl_urb(struct usb_serial *serial, + u8 request, u16 value, u16 index) +{ + return mxuport_send_ctrl_data_urb(serial, request, value, index, + NULL, 0); +} + +/* + * mxuport_throttle - throttle function of driver + * + * This function is called by the tty driver when it wants to stop the + * data being read from the port. Since all the data comes over one + * bulk in endpoint, we cannot stop submitting urbs by setting + * port->throttle. Instead tell the device to stop sending us data for + * the port. + */ +static void mxuport_throttle(struct tty_struct *tty) +{ + struct usb_serial_port *port = tty->driver_data; + struct usb_serial *serial = port->serial; + + dev_dbg(&port->dev, "%s\n", __func__); + + mxuport_send_ctrl_urb(serial, RQ_VENDOR_SET_RX_HOST_EN, + 0, port->port_number); +} + +/* + * mxuport_unthrottle - unthrottle function of driver + * + * This function is called by the tty driver when it wants to resume + * the data being read from the port. Tell the device it can resume + * sending us received data from the port. + */ +static void mxuport_unthrottle(struct tty_struct *tty) +{ + + struct usb_serial_port *port = tty->driver_data; + struct usb_serial *serial = port->serial; + + dev_dbg(&port->dev, "%s\n", __func__); + + mxuport_send_ctrl_urb(serial, RQ_VENDOR_SET_RX_HOST_EN, + 1, port->port_number); +} + +/* + * Processes one chunk of data received for a port. Mostly a copy of + * usb_serial_generic_process_read_urb(). + */ +static void mxuport_process_read_urb_data(struct usb_serial_port *port, + char *data, int size) +{ + int i; + + if (!port->port.console || !port->sysrq) { + tty_insert_flip_string(&port->port, data, size); + } else { + for (i = 0; i < size; i++, data++) { + if (!usb_serial_handle_sysrq_char(port, *data)) + tty_insert_flip_char(&port->port, *data, + TTY_NORMAL); + } + } + tty_flip_buffer_push(&port->port); +} + +static void mxuport_msr_event(struct usb_serial_port *port, u8 buf[4]) +{ + struct mxuport_port *mxport = usb_get_serial_port_data(port); + u8 rcv_msr_hold = buf[2] & 0xF0; + u16 rcv_msr_event = get_unaligned_be16(buf); + unsigned long flags; + + if (rcv_msr_event == 0) + return; + + /* Update MSR status */ + spin_lock_irqsave(&mxport->spinlock, flags); + + dev_dbg(&port->dev, "%s - current MSR status = 0x%x\n", + __func__, mxport->msr_state); + + if (rcv_msr_hold & UART_MSR_CTS) { + mxport->msr_state |= UART_MSR_CTS; + dev_dbg(&port->dev, "%s - CTS high\n", __func__); + } else { + mxport->msr_state &= ~UART_MSR_CTS; + dev_dbg(&port->dev, "%s - CTS low\n", __func__); + } + + if (rcv_msr_hold & UART_MSR_DSR) { + mxport->msr_state |= UART_MSR_DSR; + dev_dbg(&port->dev, "%s - DSR high\n", __func__); + } else { + mxport->msr_state &= ~UART_MSR_DSR; + dev_dbg(&port->dev, "%s - DSR low\n", __func__); + } + + if (rcv_msr_hold & UART_MSR_DCD) { + mxport->msr_state |= UART_MSR_DCD; + dev_dbg(&port->dev, "%s - DCD high\n", __func__); + } else { + mxport->msr_state &= ~UART_MSR_DCD; + dev_dbg(&port->dev, "%s - DCD low\n", __func__); + } + spin_unlock_irqrestore(&mxport->spinlock, flags); + + if (rcv_msr_event & + (SERIAL_EV_CTS | SERIAL_EV_DSR | SERIAL_EV_RLSD)) { + + if (rcv_msr_event & SERIAL_EV_CTS) { + port->icount.cts++; + dev_dbg(&port->dev, "%s - CTS change\n", __func__); + } + + if (rcv_msr_event & SERIAL_EV_DSR) { + port->icount.dsr++; + dev_dbg(&port->dev, "%s - DSR change\n", __func__); + } + + if (rcv_msr_event & SERIAL_EV_RLSD) { + port->icount.dcd++; + dev_dbg(&port->dev, "%s - DCD change\n", __func__); + } + wake_up_interruptible(&port->port.delta_msr_wait); + } +} + +static void mxuport_lsr_event(struct usb_serial_port *port, u8 buf[4]) +{ + u8 lsr_event = buf[2]; + + if (lsr_event & UART_LSR_BI) { + port->icount.brk++; + dev_dbg(&port->dev, "%s - break error\n", __func__); + } + + if (lsr_event & UART_LSR_FE) { + port->icount.frame++; + dev_dbg(&port->dev, "%s - frame error\n", __func__); + } + + if (lsr_event & UART_LSR_PE) { + port->icount.parity++; + dev_dbg(&port->dev, "%s - parity error\n", __func__); + } + + if (lsr_event & UART_LSR_OE) { + port->icount.overrun++; + dev_dbg(&port->dev, "%s - overrun error\n", __func__); + } +} + +/* + * When something interesting happens, modem control lines XON/XOFF + * etc, the device sends an event. Process these events. + */ +static void mxuport_process_read_urb_event(struct usb_serial_port *port, + u8 buf[4], u32 event) +{ + dev_dbg(&port->dev, "%s - receive event : %04x\n", __func__, event); + + switch (event) { + case UPORT_EVENT_SEND_NEXT: + /* + * Sent as part of the flow control on device buffers. + * Not currently used. + */ + break; + case UPORT_EVENT_MSR: + mxuport_msr_event(port, buf); + break; + case UPORT_EVENT_LSR: + mxuport_lsr_event(port, buf); + break; + case UPORT_EVENT_MCR: + /* + * Event to indicate a change in XON/XOFF from the + * peer. Currently not used. We just continue + * sending the device data and it will buffer it if + * needed. This event could be used for flow control + * between the host and the device. + */ + break; + default: + dev_dbg(&port->dev, "Unexpected event\n"); + break; + } +} + +/* + * One URB can contain data for multiple ports. Demultiplex the data, + * checking the port exists, is opened and the message is valid. + */ +static void mxuport_process_read_urb_demux_data(struct urb *urb) +{ + struct usb_serial_port *port = urb->context; + struct usb_serial *serial = port->serial; + u8 *data = urb->transfer_buffer; + u8 *end = data + urb->actual_length; + struct usb_serial_port *demux_port; + u8 *ch; + u16 rcv_port; + u16 rcv_len; + + while (data < end) { + if (data + HEADER_SIZE > end) { + dev_warn(&port->dev, "%s - message with short header\n", + __func__); + return; + } + + rcv_port = get_unaligned_be16(data); + if (rcv_port >= serial->num_ports) { + dev_warn(&port->dev, "%s - message for invalid port\n", + __func__); + return; + } + + demux_port = serial->port[rcv_port]; + rcv_len = get_unaligned_be16(data + 2); + if (!rcv_len || data + HEADER_SIZE + rcv_len > end) { + dev_warn(&port->dev, "%s - short data\n", __func__); + return; + } + + if (test_bit(ASYNCB_INITIALIZED, &demux_port->port.flags)) { + ch = data + HEADER_SIZE; + mxuport_process_read_urb_data(demux_port, ch, rcv_len); + } else { + dev_dbg(&demux_port->dev, "%s - data for closed port\n", + __func__); + } + data += HEADER_SIZE + rcv_len; + } +} + +/* + * One URB can contain events for multiple ports. Demultiplex the event, + * checking the port exists, and is opened. + */ +static void mxuport_process_read_urb_demux_event(struct urb *urb) +{ + struct usb_serial_port *port = urb->context; + struct usb_serial *serial = port->serial; + u8 *data = urb->transfer_buffer; + u8 *end = data + urb->actual_length; + struct usb_serial_port *demux_port; + u8 *ch; + u16 rcv_port; + u16 rcv_event; + + while (data < end) { + if (data + EVENT_LENGTH > end) { + dev_warn(&port->dev, "%s - message with short event\n", + __func__); + return; + } + + rcv_port = get_unaligned_be16(data); + if (rcv_port >= serial->num_ports) { + dev_warn(&port->dev, "%s - message for invalid port\n", + __func__); + return; + } + + demux_port = serial->port[rcv_port]; + if (test_bit(ASYNCB_INITIALIZED, &demux_port->port.flags)) { + ch = data + HEADER_SIZE; + rcv_event = get_unaligned_be16(data + 2); + mxuport_process_read_urb_event(demux_port, ch, + rcv_event); + } else { + dev_dbg(&demux_port->dev, + "%s - event for closed port\n", __func__); + } + data += EVENT_LENGTH; + } +} + +/* + * This is called when we have received data on the bulk in + * endpoint. Depending on which port it was received on, it can + * contain serial data or events. + */ +static void mxuport_process_read_urb(struct urb *urb) +{ + struct usb_serial_port *port = urb->context; + struct usb_serial *serial = port->serial; + + if (port == serial->port[0]) + mxuport_process_read_urb_demux_data(urb); + + if (port == serial->port[1]) + mxuport_process_read_urb_demux_event(urb); +} + +/* + * Ask the device how many bytes it has queued to be sent out. If + * there are none, return true. + */ +static bool mxuport_tx_empty(struct usb_serial_port *port) +{ + struct usb_serial *serial = port->serial; + bool is_empty = true; + u32 txlen; + u8 *len_buf; + int err; + + len_buf = kzalloc(4, GFP_KERNEL); + if (!len_buf) + goto out; + + err = mxuport_recv_ctrl_urb(serial, RQ_VENDOR_GET_OUTQUEUE, 0, + port->port_number, len_buf, 4); + if (err < 0) + goto out; + + txlen = get_unaligned_be32(len_buf); + dev_dbg(&port->dev, "%s - tx len = %u\n", __func__, txlen); + + if (txlen != 0) + is_empty = false; + +out: + kfree(len_buf); + return is_empty; +} + +static int mxuport_set_mcr(struct usb_serial_port *port, u8 mcr_state) +{ + struct usb_serial *serial = port->serial; + int err; + + dev_dbg(&port->dev, "%s - %02x\n", __func__, mcr_state); + + err = mxuport_send_ctrl_urb(serial, RQ_VENDOR_SET_MCR, + mcr_state, port->port_number); + if (err) + dev_err(&port->dev, "%s - failed to change MCR\n", __func__); + + return err; +} + +static int mxuport_set_dtr(struct usb_serial_port *port, int on) +{ + struct mxuport_port *mxport = usb_get_serial_port_data(port); + struct usb_serial *serial = port->serial; + int err; + + mutex_lock(&mxport->mutex); + + err = mxuport_send_ctrl_urb(serial, RQ_VENDOR_SET_DTR, + !!on, port->port_number); + if (!err) { + if (on) + mxport->mcr_state |= UART_MCR_DTR; + else + mxport->mcr_state &= ~UART_MCR_DTR; + } + + mutex_unlock(&mxport->mutex); + + return err; +} + +static int mxuport_set_rts(struct usb_serial_port *port, u8 state) +{ + struct mxuport_port *mxport = usb_get_serial_port_data(port); + struct usb_serial *serial = port->serial; + int err; + u8 mcr_state; + + mutex_lock(&mxport->mutex); + mcr_state = mxport->mcr_state; + + switch (state) { + case MX_RTS_DISABLE: + mcr_state &= ~UART_MCR_RTS; + break; + case MX_RTS_ENABLE: + mcr_state |= UART_MCR_RTS; + break; + case MX_RTS_HW: + /* + * Do not update mxport->mcr_state when doing hardware + * flow control. + */ + break; + default: + /* + * Should not happen, but somebody might try passing + * MX_RTS_NO_CHANGE, which is not valid. + */ + err = -EINVAL; + goto out; + } + err = mxuport_send_ctrl_urb(serial, RQ_VENDOR_SET_RTS, + state, port->port_number); + if (!err) + mxport->mcr_state = mcr_state; + +out: + mutex_unlock(&mxport->mutex); + + return err; +} + +static void mxuport_dtr_rts(struct usb_serial_port *port, int on) +{ + struct mxuport_port *mxport = usb_get_serial_port_data(port); + u8 mcr_state; + int err; + + mutex_lock(&mxport->mutex); + mcr_state = mxport->mcr_state; + + if (on) + mcr_state |= (UART_MCR_RTS | UART_MCR_DTR); + else + mcr_state &= ~(UART_MCR_RTS | UART_MCR_DTR); + + err = mxuport_set_mcr(port, mcr_state); + if (!err) + mxport->mcr_state = mcr_state; + + mutex_unlock(&mxport->mutex); +} + +static int mxuport_tiocmset(struct tty_struct *tty, unsigned int set, + unsigned int clear) +{ + struct usb_serial_port *port = tty->driver_data; + struct mxuport_port *mxport = usb_get_serial_port_data(port); + int err; + u8 mcr_state; + + mutex_lock(&mxport->mutex); + mcr_state = mxport->mcr_state; + + if (set & TIOCM_RTS) + mcr_state |= UART_MCR_RTS; + + if (set & TIOCM_DTR) + mcr_state |= UART_MCR_DTR; + + if (clear & TIOCM_RTS) + mcr_state &= ~UART_MCR_RTS; + + if (clear & TIOCM_DTR) + mcr_state &= ~UART_MCR_DTR; + + err = mxuport_set_mcr(port, mcr_state); + if (!err) + mxport->mcr_state = mcr_state; + + mutex_unlock(&mxport->mutex); + + return err; +} + +static int mxuport_tiocmget(struct tty_struct *tty) +{ + struct mxuport_port *mxport; + struct usb_serial_port *port = tty->driver_data; + unsigned int result; + unsigned long flags; + unsigned int msr; + unsigned int mcr; + + mxport = usb_get_serial_port_data(port); + + mutex_lock(&mxport->mutex); + spin_lock_irqsave(&mxport->spinlock, flags); + + msr = mxport->msr_state; + mcr = mxport->mcr_state; + + spin_unlock_irqrestore(&mxport->spinlock, flags); + mutex_unlock(&mxport->mutex); + + result = (((mcr & UART_MCR_DTR) ? TIOCM_DTR : 0) | /* 0x002 */ + ((mcr & UART_MCR_RTS) ? TIOCM_RTS : 0) | /* 0x004 */ + ((msr & UART_MSR_CTS) ? TIOCM_CTS : 0) | /* 0x020 */ + ((msr & UART_MSR_DCD) ? TIOCM_CAR : 0) | /* 0x040 */ + ((msr & UART_MSR_RI) ? TIOCM_RI : 0) | /* 0x080 */ + ((msr & UART_MSR_DSR) ? TIOCM_DSR : 0)); /* 0x100 */ + + dev_dbg(&port->dev, "%s - 0x%04x\n", __func__, result); + + return result; +} + +static int mxuport_set_termios_flow(struct tty_struct *tty, + struct ktermios *old_termios, + struct usb_serial_port *port, + struct usb_serial *serial) +{ + u8 xon = START_CHAR(tty); + u8 xoff = STOP_CHAR(tty); + int enable; + int err; + u8 *buf; + u8 rts; + + buf = kmalloc(2, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + /* S/W flow control settings */ + if (I_IXOFF(tty) || I_IXON(tty)) { + enable = 1; + buf[0] = xon; + buf[1] = xoff; + + err = mxuport_send_ctrl_data_urb(serial, RQ_VENDOR_SET_CHARS, + 0, port->port_number, + buf, 2); + if (err) + goto out; + + dev_dbg(&port->dev, "%s - XON = 0x%02x, XOFF = 0x%02x\n", + __func__, xon, xoff); + } else { + enable = 0; + } + + err = mxuport_send_ctrl_urb(serial, RQ_VENDOR_SET_XONXOFF, + enable, port->port_number); + if (err) + goto out; + + rts = MX_RTS_NO_CHANGE; + + /* H/W flow control settings */ + if (!old_termios || + C_CRTSCTS(tty) != (old_termios->c_cflag & CRTSCTS)) { + if (C_CRTSCTS(tty)) + rts = MX_RTS_HW; + else + rts = MX_RTS_ENABLE; + } + + if (C_BAUD(tty)) { + if (old_termios && (old_termios->c_cflag & CBAUD) == B0) { + /* Raise DTR and RTS */ + if (C_CRTSCTS(tty)) + rts = MX_RTS_HW; + else + rts = MX_RTS_ENABLE; + mxuport_set_dtr(port, 1); + } + } else { + /* Drop DTR and RTS */ + rts = MX_RTS_DISABLE; + mxuport_set_dtr(port, 0); + } + + if (rts != MX_RTS_NO_CHANGE) + err = mxuport_set_rts(port, rts); + +out: + kfree(buf); + return err; +} + +static void mxuport_set_termios(struct tty_struct *tty, + struct usb_serial_port *port, + struct ktermios *old_termios) +{ + struct usb_serial *serial = port->serial; + u8 *buf; + u8 data_bits; + u8 stop_bits; + u8 parity; + int baud; + int err; + + if (old_termios && + !tty_termios_hw_change(&tty->termios, old_termios) && + tty->termios.c_iflag == old_termios->c_iflag) { + dev_dbg(&port->dev, "%s - nothing to change\n", __func__); + return; + } + + buf = kmalloc(4, GFP_KERNEL); + if (!buf) + return; + + /* Set data bit of termios */ + switch (C_CSIZE(tty)) { + case CS5: + data_bits = MX_WORDLENGTH_5; + break; + case CS6: + data_bits = MX_WORDLENGTH_6; + break; + case CS7: + data_bits = MX_WORDLENGTH_7; + break; + case CS8: + default: + data_bits = MX_WORDLENGTH_8; + break; + } + + /* Set parity of termios */ + if (C_PARENB(tty)) { + if (C_CMSPAR(tty)) { + if (C_PARODD(tty)) + parity = MX_PARITY_MARK; + else + parity = MX_PARITY_SPACE; + } else { + if (C_PARODD(tty)) + parity = MX_PARITY_ODD; + else + parity = MX_PARITY_EVEN; + } + } else { + parity = MX_PARITY_NONE; + } + + /* Set stop bit of termios */ + if (C_CSTOPB(tty)) + stop_bits = MX_STOP_BITS_2; + else + stop_bits = MX_STOP_BITS_1; + + buf[0] = data_bits; + buf[1] = parity; + buf[2] = stop_bits; + buf[3] = 0; + + err = mxuport_send_ctrl_data_urb(serial, RQ_VENDOR_SET_LINE, + 0, port->port_number, buf, 4); + if (err) + goto out; + + err = mxuport_set_termios_flow(tty, old_termios, port, serial); + if (err) + goto out; + + baud = tty_get_baud_rate(tty); + if (!baud) + baud = 9600; + + /* Note: Little Endian */ + put_unaligned_le32(baud, buf); + + err = mxuport_send_ctrl_data_urb(serial, RQ_VENDOR_SET_BAUD, + 0, port->port_number, + buf, 4); + if (err) + goto out; + + dev_dbg(&port->dev, "baud_rate : %d\n", baud); + dev_dbg(&port->dev, "data_bits : %d\n", data_bits); + dev_dbg(&port->dev, "parity : %d\n", parity); + dev_dbg(&port->dev, "stop_bits : %d\n", stop_bits); + +out: + kfree(buf); +} + +/* + * Determine how many ports this device has dynamically. It will be + * called after the probe() callback is called, but before attach(). + */ +static int mxuport_calc_num_ports(struct usb_serial *serial) +{ + unsigned long features = (unsigned long)usb_get_serial_data(serial); + + if (features & MX_UPORT_2_PORT) + return 2; + if (features & MX_UPORT_4_PORT) + return 4; + if (features & MX_UPORT_8_PORT) + return 8; + if (features & MX_UPORT_16_PORT) + return 16; + + return 0; +} + +/* Get the version of the firmware currently running. */ +static int mxuport_get_fw_version(struct usb_serial *serial, u32 *version) +{ + u8 *ver_buf; + int err; + + ver_buf = kzalloc(4, GFP_KERNEL); + if (!ver_buf) + return -ENOMEM; + + /* Get firmware version from SDRAM */ + err = mxuport_recv_ctrl_urb(serial, RQ_VENDOR_GET_VERSION, 0, 0, + ver_buf, 4); + if (err != 4) { + err = -EIO; + goto out; + } + + *version = (ver_buf[0] << 16) | (ver_buf[1] << 8) | ver_buf[2]; + err = 0; +out: + kfree(ver_buf); + return err; +} + +/* Given a firmware blob, download it to the device. */ +static int mxuport_download_fw(struct usb_serial *serial, + const struct firmware *fw_p) +{ + u8 *fw_buf; + size_t txlen; + size_t fwidx; + int err; + + fw_buf = kmalloc(DOWN_BLOCK_SIZE, GFP_KERNEL); + if (!fw_buf) + return -ENOMEM; + + dev_dbg(&serial->interface->dev, "Starting firmware download...\n"); + err = mxuport_send_ctrl_urb(serial, RQ_VENDOR_START_FW_DOWN, 0, 0); + if (err) + goto out; + + fwidx = 0; + do { + txlen = min_t(size_t, (fw_p->size - fwidx), DOWN_BLOCK_SIZE); + + memcpy(fw_buf, &fw_p->data[fwidx], txlen); + err = mxuport_send_ctrl_data_urb(serial, RQ_VENDOR_FW_DATA, + 0, 0, fw_buf, txlen); + if (err) { + mxuport_send_ctrl_urb(serial, RQ_VENDOR_STOP_FW_DOWN, + 0, 0); + goto out; + } + + fwidx += txlen; + usleep_range(1000, 2000); + + } while (fwidx < fw_p->size); + + msleep(1000); + err = mxuport_send_ctrl_urb(serial, RQ_VENDOR_STOP_FW_DOWN, 0, 0); + if (err) + goto out; + + msleep(1000); + err = mxuport_send_ctrl_urb(serial, RQ_VENDOR_QUERY_FW_READY, 0, 0); + +out: + kfree(fw_buf); + return err; +} + +static int mxuport_probe(struct usb_serial *serial, + const struct usb_device_id *id) +{ + u16 productid = le16_to_cpu(serial->dev->descriptor.idProduct); + const struct firmware *fw_p = NULL; + u32 version; + int local_ver; + char buf[32]; + int err; + + /* Load our firmware */ + err = mxuport_send_ctrl_urb(serial, RQ_VENDOR_QUERY_FW_CONFIG, 0, 0); + if (err) { + mxuport_send_ctrl_urb(serial, RQ_VENDOR_RESET_DEVICE, 0, 0); + return err; + } + + err = mxuport_get_fw_version(serial, &version); + if (err < 0) + return err; + + dev_dbg(&serial->interface->dev, "Device firmware version v%x.%x.%x\n", + (version & 0xff0000) >> 16, + (version & 0xff00) >> 8, + (version & 0xff)); + + snprintf(buf, sizeof(buf) - 1, "moxa/moxa-%04x.fw", productid); + + err = request_firmware(&fw_p, buf, &serial->interface->dev); + if (err) { + dev_warn(&serial->interface->dev, "Firmware %s not found\n", + buf); + + /* Use the firmware already in the device */ + err = 0; + } else { + local_ver = ((fw_p->data[VER_ADDR_1] << 16) | + (fw_p->data[VER_ADDR_2] << 8) | + fw_p->data[VER_ADDR_3]); + dev_dbg(&serial->interface->dev, + "Available firmware version v%x.%x.%x\n", + fw_p->data[VER_ADDR_1], fw_p->data[VER_ADDR_2], + fw_p->data[VER_ADDR_3]); + if (local_ver > version) { + err = mxuport_download_fw(serial, fw_p); + if (err) + goto out; + err = mxuport_get_fw_version(serial, &version); + if (err < 0) + goto out; + } + } + + dev_info(&serial->interface->dev, + "Using device firmware version v%x.%x.%x\n", + (version & 0xff0000) >> 16, + (version & 0xff00) >> 8, + (version & 0xff)); + + /* + * Contains the features of this hardware. Store away for + * later use, eg, number of ports. + */ + usb_set_serial_data(serial, (void *)id->driver_info); +out: + if (fw_p) + release_firmware(fw_p); + return err; +} + + +static int mxuport_port_probe(struct usb_serial_port *port) +{ + struct usb_serial *serial = port->serial; + struct mxuport_port *mxport; + int err; + + mxport = devm_kzalloc(&port->dev, sizeof(struct mxuport_port), + GFP_KERNEL); + if (!mxport) + return -ENOMEM; + + mutex_init(&mxport->mutex); + spin_lock_init(&mxport->spinlock); + + /* Set the port private data */ + usb_set_serial_port_data(port, mxport); + + /* Set FIFO (Enable) */ + err = mxuport_send_ctrl_urb(serial, RQ_VENDOR_SET_FIFO_DISABLE, + 0, port->port_number); + if (err) + return err; + + /* Set transmission mode (Hi-Performance) */ + err = mxuport_send_ctrl_urb(serial, RQ_VENDOR_SET_HIGH_PERFOR, + 0, port->port_number); + if (err) + return err; + + /* Set interface (RS-232) */ + err = mxuport_send_ctrl_urb(serial, RQ_VENDOR_SET_INTERFACE, + MX_INT_RS232, + port->port_number); + if (err) + return err; + + return 0; +} + +static int mxuport_alloc_write_urb(struct usb_serial *serial, + struct usb_serial_port *port, + struct usb_serial_port *port0, + int j) +{ + struct usb_device *dev = interface_to_usbdev(serial->interface); + + set_bit(j, &port->write_urbs_free); + port->write_urbs[j] = usb_alloc_urb(0, GFP_KERNEL); + if (!port->write_urbs[j]) + return -ENOMEM; + + port->bulk_out_buffers[j] = kmalloc(port0->bulk_out_size, GFP_KERNEL); + if (!port->bulk_out_buffers[j]) + return -ENOMEM; + + usb_fill_bulk_urb(port->write_urbs[j], dev, + usb_sndbulkpipe(dev, port->bulk_out_endpointAddress), + port->bulk_out_buffers[j], + port->bulk_out_size, + serial->type->write_bulk_callback, + port); + return 0; +} + + +static int mxuport_alloc_write_urbs(struct usb_serial *serial, + struct usb_serial_port *port, + struct usb_serial_port *port0) +{ + int j; + int ret; + + for (j = 0; j < ARRAY_SIZE(port->write_urbs); ++j) { + ret = mxuport_alloc_write_urb(serial, port, port0, j); + if (ret) + return ret; + } + return 0; +} + + +static int mxuport_attach(struct usb_serial *serial) +{ + struct usb_serial_port *port0 = serial->port[0]; + struct usb_serial_port *port1 = serial->port[1]; + struct usb_serial_port *port; + int err; + int i; + int j; + + /* + * Throw away all but the first allocated write URBs so we can + * set them up again to fit the multiplexing scheme. + */ + for (i = 1; i < serial->num_bulk_out; ++i) { + port = serial->port[i]; + for (j = 0; j < ARRAY_SIZE(port->write_urbs); ++j) { + usb_free_urb(port->write_urbs[j]); + kfree(port->bulk_out_buffers[j]); + port->write_urbs[j] = NULL; + port->bulk_out_buffers[j] = NULL; + } + port->write_urbs_free = 0; + } + + /* + * All write data is sent over the first bulk out endpoint, + * with an added header to indicate the port. Allocate URBs + * for each port to the first bulk out endpoint. + */ + for (i = 1; i < serial->num_ports; ++i) { + port = serial->port[i]; + port->bulk_out_size = port0->bulk_out_size; + port->bulk_out_endpointAddress = + port0->bulk_out_endpointAddress; + + err = mxuport_alloc_write_urbs(serial, port, port0); + if (err) + return err; + + port->write_urb = port->write_urbs[0]; + port->bulk_out_buffer = port->bulk_out_buffers[0]; + + /* + * Ensure each port has a fifo. The framework only + * allocates a fifo to ports with a bulk out endpoint, + * where as we need one for every port. + */ + if (!kfifo_initialized(&port->write_fifo)) { + err = kfifo_alloc(&port->write_fifo, PAGE_SIZE, + GFP_KERNEL); + if (err) + return err; + } + } + + /* + * All data from the ports is received on the first bulk in + * endpoint, with a multiplex header. The second bulk in is + * used for events. + * + * Start to read from the device. + */ + err = usb_serial_generic_submit_read_urbs(port0, GFP_KERNEL); + if (err) + return err; + + err = usb_serial_generic_submit_read_urbs(port1, GFP_KERNEL); + if (err) { + usb_serial_generic_close(port0); + return err; + } + + return 0; +} + +static int mxuport_open(struct tty_struct *tty, struct usb_serial_port *port) +{ + struct mxuport_port *mxport = usb_get_serial_port_data(port); + struct usb_serial *serial = port->serial; + int err; + + /* Set receive host (enable) */ + err = mxuport_send_ctrl_urb(serial, RQ_VENDOR_SET_RX_HOST_EN, + 1, port->port_number); + if (err) + return err; + + err = mxuport_send_ctrl_urb(serial, RQ_VENDOR_SET_OPEN, + 1, port->port_number); + if (err) { + mxuport_send_ctrl_urb(serial, RQ_VENDOR_SET_RX_HOST_EN, + 0, port->port_number); + return err; + } + + /* Initial port termios */ + mxuport_set_termios(tty, port, NULL); + + /* + * TODO: use RQ_VENDOR_GET_MSR, once we know what it + * returns. + */ + mxport->msr_state = 0; + + return err; +} + +static void mxuport_close(struct usb_serial_port *port) +{ + struct usb_serial *serial = port->serial; + + mxuport_send_ctrl_urb(serial, RQ_VENDOR_SET_OPEN, 0, + port->port_number); + + mxuport_send_ctrl_urb(serial, RQ_VENDOR_SET_RX_HOST_EN, 0, + port->port_number); +} + +/* Send a break to the port. */ +static void mxuport_break_ctl(struct tty_struct *tty, int break_state) +{ + struct usb_serial_port *port = tty->driver_data; + struct usb_serial *serial = port->serial; + int enable; + + if (break_state == -1) { + enable = 1; + dev_dbg(&port->dev, "%s - sending break\n", __func__); + } else { + enable = 0; + dev_dbg(&port->dev, "%s - clearing break\n", __func__); + } + + mxuport_send_ctrl_urb(serial, RQ_VENDOR_SET_BREAK, + enable, port->port_number); +} + +static int mxuport_resume(struct usb_serial *serial) +{ + struct usb_serial_port *port; + int c = 0; + int i; + int r; + + for (i = 0; i < 2; i++) { + port = serial->port[i]; + + r = usb_serial_generic_submit_read_urbs(port, GFP_NOIO); + if (r < 0) + c++; + } + + for (i = 0; i < serial->num_ports; i++) { + port = serial->port[i]; + if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags)) + continue; + + r = usb_serial_generic_write_start(port, GFP_NOIO); + if (r < 0) + c++; + } + + return c ? -EIO : 0; +} + +static struct usb_serial_driver mxuport_device = { + .driver = { + .owner = THIS_MODULE, + .name = "mxuport", + }, + .description = "MOXA UPort", + .id_table = mxuport_idtable, + .num_ports = 0, + .probe = mxuport_probe, + .port_probe = mxuport_port_probe, + .attach = mxuport_attach, + .calc_num_ports = mxuport_calc_num_ports, + .open = mxuport_open, + .close = mxuport_close, + .set_termios = mxuport_set_termios, + .break_ctl = mxuport_break_ctl, + .tx_empty = mxuport_tx_empty, + .tiocmiwait = usb_serial_generic_tiocmiwait, + .get_icount = usb_serial_generic_get_icount, + .throttle = mxuport_throttle, + .unthrottle = mxuport_unthrottle, + .tiocmget = mxuport_tiocmget, + .tiocmset = mxuport_tiocmset, + .dtr_rts = mxuport_dtr_rts, + .process_read_urb = mxuport_process_read_urb, + .prepare_write_buffer = mxuport_prepare_write_buffer, + .resume = mxuport_resume, +}; + +static struct usb_serial_driver *const serial_drivers[] = { + &mxuport_device, NULL +}; + +module_usb_serial_driver(serial_drivers, mxuport_idtable); + +MODULE_AUTHOR("Andrew Lunn <andrew@lunn.ch>"); +MODULE_AUTHOR("<support@moxa.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/serial/navman.c b/drivers/usb/serial/navman.c index 1f00f243c26..2a97cdc078d 100644 --- a/drivers/usb/serial/navman.c +++ b/drivers/usb/serial/navman.c @@ -14,15 +14,12 @@ #include <linux/gfp.h> #include <linux/kernel.h> -#include <linux/init.h> #include <linux/tty.h> #include <linux/tty_flip.h> #include <linux/module.h> #include <linux/usb.h> #include <linux/usb/serial.h> -static int debug; - static const struct usb_device_id id_table[] = { { USB_DEVICE(0x0a99, 0x0001) }, /* Talon Technology device */ { USB_DEVICE(0x0df7, 0x0900) }, /* Mobile Action i-gotU */ @@ -30,19 +27,10 @@ static const struct usb_device_id id_table[] = { }; MODULE_DEVICE_TABLE(usb, id_table); -static struct usb_driver navman_driver = { - .name = "navman", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, - .no_dynamic_id = 1, -}; - static void navman_read_int_callback(struct urb *urb) { struct usb_serial_port *port = urb->context; unsigned char *data = urb->transfer_buffer; - struct tty_struct *tty; int status = urb->status; int result; @@ -54,24 +42,21 @@ static void navman_read_int_callback(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", - __func__, status); + dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n", + __func__, status); return; default: - dbg("%s - nonzero urb status received: %d", - __func__, status); + dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n", + __func__, status); goto exit; } - usb_serial_debug_data(debug, &port->dev, __func__, - urb->actual_length, data); + usb_serial_debug_data(&port->dev, __func__, urb->actual_length, data); - tty = tty_port_tty_get(&port->port); - if (tty && urb->actual_length) { - tty_insert_flip_string(tty, data, urb->actual_length); - tty_flip_buffer_push(tty); + if (urb->actual_length) { + tty_insert_flip_string(&port->port, data, urb->actual_length); + tty_flip_buffer_push(&port->port); } - tty_kref_put(tty); exit: result = usb_submit_urb(urb, GFP_ATOMIC); @@ -85,10 +70,9 @@ static int navman_open(struct tty_struct *tty, struct usb_serial_port *port) { int result = 0; - dbg("%s - port %d", __func__, port->number); - if (port->interrupt_in_urb) { - dbg("%s - adding interrupt input for treo", __func__); + dev_dbg(&port->dev, "%s - adding interrupt input for treo\n", + __func__); result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); if (result) dev_err(&port->dev, @@ -100,16 +84,12 @@ static int navman_open(struct tty_struct *tty, struct usb_serial_port *port) static void navman_close(struct usb_serial_port *port) { - dbg("%s - port %d", __func__, port->number); - usb_kill_urb(port->interrupt_in_urb); } static int navman_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count) { - dbg("%s - port %d", __func__, port->number); - /* * This device can't write any data, only read from the device */ @@ -122,7 +102,6 @@ static struct usb_serial_driver navman_device = { .name = "navman", }, .id_table = id_table, - .usb_driver = &navman_driver, .num_ports = 1, .open = navman_open, .close = navman_close, @@ -130,28 +109,10 @@ static struct usb_serial_driver navman_device = { .read_int_callback = navman_read_int_callback, }; -static int __init navman_init(void) -{ - int retval; - - retval = usb_serial_register(&navman_device); - if (retval) - return retval; - retval = usb_register(&navman_driver); - if (retval) - usb_serial_deregister(&navman_device); - return retval; -} +static struct usb_serial_driver * const serial_drivers[] = { + &navman_device, NULL +}; -static void __exit navman_exit(void) -{ - usb_deregister(&navman_driver); - usb_serial_deregister(&navman_device); -} +module_usb_serial_driver(serial_drivers, id_table); -module_init(navman_init); -module_exit(navman_exit); MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c index 60f38d5e64f..f6c6900bccf 100644 --- a/drivers/usb/serial/omninet.c +++ b/drivers/usb/serial/omninet.c @@ -9,52 +9,19 @@ * driver * * Please report both successes and troubles to the author at omninet@kroah.com - * - * (05/30/2001) gkh - * switched from using spinlock to a semaphore, which fixes lots of - * problems. - * - * (04/08/2001) gb - * Identify version on module load. - * - * (11/01/2000) Adam J. Richter - * usb_device_id table support - * - * (10/05/2000) gkh - * Fixed bug with urb->dev not being set properly, now that the usb - * core needs it. - * - * (08/28/2000) gkh - * Added locks for SMP safeness. - * Fixed MOD_INC and MOD_DEC logic and the ability to open a port more - * than once. - * Fixed potential race in omninet_write_bulk_callback - * - * (07/19/2000) gkh - * Added module_init and module_exit functions to handle the fact that this - * driver is a loadable module now. - * */ #include <linux/kernel.h> #include <linux/errno.h> -#include <linux/init.h> #include <linux/slab.h> #include <linux/tty.h> #include <linux/tty_driver.h> #include <linux/tty_flip.h> #include <linux/module.h> -#include <linux/spinlock.h> #include <linux/uaccess.h> #include <linux/usb.h> #include <linux/usb/serial.h> -static int debug; - -/* - * Version Information - */ -#define DRIVER_VERSION "v1.1" #define DRIVER_AUTHOR "Alessandro Zummo" #define DRIVER_DESC "USB ZyXEL omni.net LCD PLUS Driver" @@ -65,77 +32,67 @@ static int debug; /* function prototypes */ static int omninet_open(struct tty_struct *tty, struct usb_serial_port *port); -static void omninet_close(struct usb_serial_port *port); -static void omninet_read_bulk_callback(struct urb *urb); +static void omninet_process_read_urb(struct urb *urb); static void omninet_write_bulk_callback(struct urb *urb); static int omninet_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count); static int omninet_write_room(struct tty_struct *tty); static void omninet_disconnect(struct usb_serial *serial); -static void omninet_release(struct usb_serial *serial); -static int omninet_attach(struct usb_serial *serial); +static int omninet_port_probe(struct usb_serial_port *port); +static int omninet_port_remove(struct usb_serial_port *port); static const struct usb_device_id id_table[] = { { USB_DEVICE(ZYXEL_VENDOR_ID, ZYXEL_OMNINET_ID) }, { USB_DEVICE(ZYXEL_VENDOR_ID, BT_IGNITIONPRO_ID) }, { } /* Terminating entry */ }; - MODULE_DEVICE_TABLE(usb, id_table); -static struct usb_driver omninet_driver = { - .name = "omninet", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, - .no_dynamic_id = 1, -}; - - static struct usb_serial_driver zyxel_omninet_device = { .driver = { .owner = THIS_MODULE, .name = "omninet", }, .description = "ZyXEL - omni.net lcd plus usb", - .usb_driver = &omninet_driver, .id_table = id_table, .num_ports = 1, - .attach = omninet_attach, + .port_probe = omninet_port_probe, + .port_remove = omninet_port_remove, .open = omninet_open, - .close = omninet_close, .write = omninet_write, .write_room = omninet_write_room, - .read_bulk_callback = omninet_read_bulk_callback, .write_bulk_callback = omninet_write_bulk_callback, + .process_read_urb = omninet_process_read_urb, .disconnect = omninet_disconnect, - .release = omninet_release, +}; + +static struct usb_serial_driver * const serial_drivers[] = { + &zyxel_omninet_device, NULL }; -/* The protocol. +/* + * The protocol. * * The omni.net always exchange 64 bytes of data with the host. The first - * four bytes are the control header, you can see it in the above structure. + * four bytes are the control header. * * oh_seq is a sequence number. Don't know if/how it's used. * oh_len is the length of the data bytes in the packet. * oh_xxx Bit-mapped, related to handshaking and status info. - * I normally set it to 0x03 in trasmitted frames. + * I normally set it to 0x03 in transmitted frames. * 7: Active when the TA is in a CONNECTed state. * 6: unknown * 5: handshaking, unknown * 4: handshaking, unknown * 3: unknown, usually 0 * 2: unknown, usually 0 - * 1: handshaking, unknown, usually set to 1 in trasmitted frames - * 0: handshaking, unknown, usually set to 1 in trasmitted frames + * 1: handshaking, unknown, usually set to 1 in transmitted frames + * 0: handshaking, unknown, usually set to 1 in transmitted frames * oh_pad Probably a pad byte. * * After the header you will find data bytes if oh_len was greater than zero. - * */ - struct omninet_header { __u8 oh_seq; __u8 oh_len; @@ -147,18 +104,26 @@ struct omninet_data { __u8 od_outseq; /* Sequence number for bulk_out URBs */ }; -static int omninet_attach(struct usb_serial *serial) +static int omninet_port_probe(struct usb_serial_port *port) { struct omninet_data *od; - struct usb_serial_port *port = serial->port[0]; - od = kmalloc(sizeof(struct omninet_data), GFP_KERNEL); - if (!od) { - dev_err(&port->dev, "%s- kmalloc(%Zd) failed.\n", - __func__, sizeof(struct omninet_data)); + od = kzalloc(sizeof(*od), GFP_KERNEL); + if (!od) return -ENOMEM; - } + usb_set_serial_port_data(port, od); + + return 0; +} + +static int omninet_port_remove(struct usb_serial_port *port) +{ + struct omninet_data *od; + + od = usb_get_serial_port_data(port); + kfree(od); + return 0; } @@ -166,86 +131,32 @@ static int omninet_open(struct tty_struct *tty, struct usb_serial_port *port) { struct usb_serial *serial = port->serial; struct usb_serial_port *wport; - int result = 0; - - dbg("%s - port %d", __func__, port->number); wport = serial->port[1]; tty_port_tty_set(&wport->port, tty); - /* Start reading from the device */ - usb_fill_bulk_urb(port->read_urb, serial->dev, - usb_rcvbulkpipe(serial->dev, - port->bulk_in_endpointAddress), - port->read_urb->transfer_buffer, - port->read_urb->transfer_buffer_length, - omninet_read_bulk_callback, port); - result = usb_submit_urb(port->read_urb, GFP_KERNEL); - if (result) - dev_err(&port->dev, - "%s - failed submitting read urb, error %d\n", - __func__, result); - return result; -} - -static void omninet_close(struct usb_serial_port *port) -{ - dbg("%s - port %d", __func__, port->number); - usb_kill_urb(port->read_urb); + return usb_serial_generic_open(tty, port); } +#define OMNINET_HEADERLEN 4 +#define OMNINET_BULKOUTSIZE 64 +#define OMNINET_PAYLOADSIZE (OMNINET_BULKOUTSIZE - OMNINET_HEADERLEN) -#define OMNINET_DATAOFFSET 0x04 -#define OMNINET_HEADERLEN sizeof(struct omninet_header) -#define OMNINET_BULKOUTSIZE (64 - OMNINET_HEADERLEN) - -static void omninet_read_bulk_callback(struct urb *urb) +static void omninet_process_read_urb(struct urb *urb) { - struct usb_serial_port *port = urb->context; - unsigned char *data = urb->transfer_buffer; - struct omninet_header *header = (struct omninet_header *) &data[0]; - int status = urb->status; - int result; - int i; + struct usb_serial_port *port = urb->context; + const struct omninet_header *hdr = urb->transfer_buffer; + const unsigned char *data; + size_t data_len; - dbg("%s - port %d", __func__, port->number); - - if (status) { - dbg("%s - nonzero read bulk status received: %d", - __func__, status); + if (urb->actual_length <= OMNINET_HEADERLEN || !hdr->oh_len) return; - } - - if (debug && header->oh_xxx != 0x30) { - if (urb->actual_length) { - printk(KERN_DEBUG "%s: omninet_read %d: ", - __FILE__, header->oh_len); - for (i = 0; i < (header->oh_len + - OMNINET_HEADERLEN); i++) - printk("%.2x ", data[i]); - printk("\n"); - } - } - - if (urb->actual_length && header->oh_len) { - struct tty_struct *tty = tty_port_tty_get(&port->port); - tty_insert_flip_string(tty, data + OMNINET_DATAOFFSET, - header->oh_len); - tty_flip_buffer_push(tty); - tty_kref_put(tty); - } - /* Continue trying to always read */ - usb_fill_bulk_urb(urb, port->serial->dev, - usb_rcvbulkpipe(port->serial->dev, - port->bulk_in_endpointAddress), - urb->transfer_buffer, urb->transfer_buffer_length, - omninet_read_bulk_callback, port); - result = usb_submit_urb(urb, GFP_ATOMIC); - if (result) - dev_err(&port->dev, - "%s - failed resubmitting read urb, error %d\n", - __func__, result); + data = (char *)urb->transfer_buffer + OMNINET_HEADERLEN; + data_len = min_t(size_t, urb->actual_length - OMNINET_HEADERLEN, + hdr->oh_len); + tty_insert_flip_string(&port->port, data, data_len); + tty_flip_buffer_push(&port->port); } static int omninet_write(struct tty_struct *tty, struct usb_serial_port *port, @@ -260,29 +171,23 @@ static int omninet_write(struct tty_struct *tty, struct usb_serial_port *port, int result; - dbg("%s - port %d", __func__, port->number); - if (count == 0) { - dbg("%s - write request of 0 bytes", __func__); + dev_dbg(&port->dev, "%s - write request of 0 bytes\n", __func__); return 0; } - spin_lock_bh(&wport->lock); - if (wport->write_urb_busy) { - spin_unlock_bh(&wport->lock); - dbg("%s - already writing", __func__); + if (!test_and_clear_bit(0, &port->write_urbs_free)) { + dev_dbg(&port->dev, "%s - already writing\n", __func__); return 0; } - wport->write_urb_busy = 1; - spin_unlock_bh(&wport->lock); - count = (count > OMNINET_BULKOUTSIZE) ? OMNINET_BULKOUTSIZE : count; + count = (count > OMNINET_PAYLOADSIZE) ? OMNINET_PAYLOADSIZE : count; - memcpy(wport->write_urb->transfer_buffer + OMNINET_DATAOFFSET, + memcpy(wport->write_urb->transfer_buffer + OMNINET_HEADERLEN, buf, count); - usb_serial_debug_data(debug, &port->dev, __func__, count, - wport->write_urb->transfer_buffer); + usb_serial_debug_data(&port->dev, __func__, count, + wport->write_urb->transfer_buffer); header->oh_seq = od->od_outseq++; header->oh_len = count; @@ -290,13 +195,12 @@ static int omninet_write(struct tty_struct *tty, struct usb_serial_port *port, header->oh_pad = 0x00; /* send the data out the bulk port, always 64 bytes */ - wport->write_urb->transfer_buffer_length = 64; + wport->write_urb->transfer_buffer_length = OMNINET_BULKOUTSIZE; - wport->write_urb->dev = serial->dev; result = usb_submit_urb(wport->write_urb, GFP_ATOMIC); if (result) { - wport->write_urb_busy = 0; - dev_err(&port->dev, + set_bit(0, &wport->write_urbs_free); + dev_err_console(port, "%s - failed submitting write urb, error %d\n", __func__, result); } else @@ -314,11 +218,10 @@ static int omninet_write_room(struct tty_struct *tty) int room = 0; /* Default: no room */ - /* FIXME: no consistent locking for write_urb_busy */ - if (wport->write_urb_busy) + if (test_bit(0, &wport->write_urbs_free)) room = wport->bulk_out_size - OMNINET_HEADERLEN; - dbg("%s - returns %d", __func__, room); + dev_dbg(&port->dev, "%s - returns %d\n", __func__, room); return room; } @@ -330,12 +233,10 @@ static void omninet_write_bulk_callback(struct urb *urb) struct usb_serial_port *port = urb->context; int status = urb->status; - dbg("%s - port %0x", __func__, port->number); - - port->write_urb_busy = 0; + set_bit(0, &port->write_urbs_free); if (status) { - dbg("%s - nonzero write bulk status received: %d", - __func__, status); + dev_dbg(&port->dev, "%s - nonzero write bulk status received: %d\n", + __func__, status); return; } @@ -347,54 +248,11 @@ static void omninet_disconnect(struct usb_serial *serial) { struct usb_serial_port *wport = serial->port[1]; - dbg("%s", __func__); - usb_kill_urb(wport->write_urb); } - -static void omninet_release(struct usb_serial *serial) -{ - struct usb_serial_port *port = serial->port[0]; - - dbg("%s", __func__); - - kfree(usb_get_serial_port_data(port)); -} - - -static int __init omninet_init(void) -{ - int retval; - retval = usb_serial_register(&zyxel_omninet_device); - if (retval) - goto failed_usb_serial_register; - retval = usb_register(&omninet_driver); - if (retval) - goto failed_usb_register; - printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" - DRIVER_DESC "\n"); - return 0; -failed_usb_register: - usb_serial_deregister(&zyxel_omninet_device); -failed_usb_serial_register: - return retval; -} - - -static void __exit omninet_exit(void) -{ - usb_deregister(&omninet_driver); - usb_serial_deregister(&zyxel_omninet_device); -} - - -module_init(omninet_init); -module_exit(omninet_exit); +module_usb_serial_driver(serial_drivers, id_table); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/drivers/usb/serial/opticon.c b/drivers/usb/serial/opticon.c index eda1f9266c4..4856fb7e637 100644 --- a/drivers/usb/serial/opticon.c +++ b/drivers/usb/serial/opticon.c @@ -1,6 +1,8 @@ /* * Opticon USB barcode to serial driver * + * Copyright (C) 2011 - 2012 Johan Hovold <jhovold@gmail.com> + * Copyright (C) 2011 Martin Jansen <martin.jansen@opticon.com> * Copyright (C) 2008 - 2009 Greg Kroah-Hartman <gregkh@suse.de> * Copyright (C) 2008 - 2009 Novell Inc. * @@ -10,7 +12,6 @@ */ #include <linux/kernel.h> -#include <linux/init.h> #include <linux/tty.h> #include <linux/tty_driver.h> #include <linux/slab.h> @@ -21,7 +22,15 @@ #include <linux/usb/serial.h> #include <linux/uaccess.h> -static int debug; +#define CONTROL_RTS 0x02 +#define RESEND_CTS_STATE 0x03 + +/* max number of write urbs in flight */ +#define URB_UPPER_LIMIT 8 + +/* This driver works for the Opticon 1D barcode reader + * an examples of 1D barcode types are EAN, UPC, Code39, IATA etc.. */ +#define DRIVER_DESC "Opticon USB barcode to serial driver (1D)" static const struct usb_device_id id_table[] = { { USB_DEVICE(0x065a, 0x0009) }, @@ -31,156 +40,122 @@ MODULE_DEVICE_TABLE(usb, id_table); /* This structure holds all of the individual device information */ struct opticon_private { - struct usb_device *udev; - struct usb_serial *serial; - struct usb_serial_port *port; - unsigned char *bulk_in_buffer; - struct urb *bulk_read_urb; - int buffer_size; - u8 bulk_address; spinlock_t lock; /* protects the following flags */ - bool throttled; - bool actually_throttled; bool rts; + bool cts; int outstanding_urbs; }; -/* max number of write urbs in flight */ -#define URB_UPPER_LIMIT 4 -static void opticon_bulk_callback(struct urb *urb) +static void opticon_process_data_packet(struct usb_serial_port *port, + const unsigned char *buf, size_t len) { - struct opticon_private *priv = urb->context; - unsigned char *data = urb->transfer_buffer; - struct usb_serial_port *port = priv->port; - int status = urb->status; - struct tty_struct *tty; - int result; - int data_length; - - dbg("%s - port %d", __func__, port->number); - - switch (status) { - case 0: - /* success */ - break; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", - __func__, status); + tty_insert_flip_string(&port->port, buf, len); + tty_flip_buffer_push(&port->port); +} + +static void opticon_process_status_packet(struct usb_serial_port *port, + const unsigned char *buf, size_t len) +{ + struct opticon_private *priv = usb_get_serial_port_data(port); + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + if (buf[0] == 0x00) + priv->cts = false; + else + priv->cts = true; + spin_unlock_irqrestore(&priv->lock, flags); +} + +static void opticon_process_read_urb(struct urb *urb) +{ + struct usb_serial_port *port = urb->context; + const unsigned char *hdr = urb->transfer_buffer; + const unsigned char *data = hdr + 2; + size_t data_len = urb->actual_length - 2; + + if (urb->actual_length <= 2) { + dev_dbg(&port->dev, "malformed packet received: %d bytes\n", + urb->actual_length); return; - default: - dbg("%s - nonzero urb status received: %d", - __func__, status); - goto exit; } - - usb_serial_debug_data(debug, &port->dev, __func__, urb->actual_length, - data); - - if (urb->actual_length > 2) { - data_length = urb->actual_length - 2; - - /* - * Data from the device comes with a 2 byte header: - * - * <0x00><0x00>data... - * This is real data to be sent to the tty layer - * <0x00><0x01)level - * This is a RTS level change, the third byte is the RTS - * value (0 for low, 1 for high). - */ - if ((data[0] == 0x00) && (data[1] == 0x00)) { - /* real data, send it to the tty layer */ - tty = tty_port_tty_get(&port->port); - if (tty) { - tty_insert_flip_string(tty, data + 2, - data_length); - tty_flip_buffer_push(tty); - tty_kref_put(tty); - } - } else { - if ((data[0] == 0x00) && (data[1] == 0x01)) { - if (data[2] == 0x00) - priv->rts = false; - else - priv->rts = true; - } else { - dev_dbg(&priv->udev->dev, - "Unknown data packet received from the device:" - " %2x %2x\n", - data[0], data[1]); - } - } + /* + * Data from the device comes with a 2 byte header: + * + * <0x00><0x00>data... + * This is real data to be sent to the tty layer + * <0x00><0x01>level + * This is a CTS level change, the third byte is the CTS + * value (0 for low, 1 for high). + */ + if ((hdr[0] == 0x00) && (hdr[1] == 0x00)) { + opticon_process_data_packet(port, data, data_len); + } else if ((hdr[0] == 0x00) && (hdr[1] == 0x01)) { + opticon_process_status_packet(port, data, data_len); } else { - dev_dbg(&priv->udev->dev, - "Improper amount of data received from the device, " - "%d bytes", urb->actual_length); + dev_dbg(&port->dev, "unknown packet received: %02x %02x\n", + hdr[0], hdr[1]); } +} + +static int send_control_msg(struct usb_serial_port *port, u8 requesttype, + u8 val) +{ + struct usb_serial *serial = port->serial; + int retval; + u8 *buffer; + + buffer = kzalloc(1, GFP_KERNEL); + if (!buffer) + return -ENOMEM; -exit: - spin_lock(&priv->lock); - - /* Continue trying to always read if we should */ - if (!priv->throttled) { - usb_fill_bulk_urb(priv->bulk_read_urb, priv->udev, - usb_rcvbulkpipe(priv->udev, - priv->bulk_address), - priv->bulk_in_buffer, priv->buffer_size, - opticon_bulk_callback, priv); - result = usb_submit_urb(priv->bulk_read_urb, GFP_ATOMIC); - if (result) - dev_err(&port->dev, - "%s - failed resubmitting read urb, error %d\n", - __func__, result); - } else - priv->actually_throttled = true; - spin_unlock(&priv->lock); + buffer[0] = val; + /* Send the message to the vendor control endpoint + * of the connected device */ + retval = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + requesttype, + USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_INTERFACE, + 0, 0, buffer, 1, 0); + kfree(buffer); + + if (retval < 0) + return retval; + + return 0; } static int opticon_open(struct tty_struct *tty, struct usb_serial_port *port) { - struct opticon_private *priv = usb_get_serial_data(port->serial); + struct opticon_private *priv = usb_get_serial_port_data(port); unsigned long flags; - int result = 0; - - dbg("%s - port %d", __func__, port->number); + int res; spin_lock_irqsave(&priv->lock, flags); - priv->throttled = false; - priv->actually_throttled = false; - priv->port = port; + priv->rts = false; spin_unlock_irqrestore(&priv->lock, flags); - /* Start reading from the device */ - usb_fill_bulk_urb(priv->bulk_read_urb, priv->udev, - usb_rcvbulkpipe(priv->udev, - priv->bulk_address), - priv->bulk_in_buffer, priv->buffer_size, - opticon_bulk_callback, priv); - result = usb_submit_urb(priv->bulk_read_urb, GFP_KERNEL); - if (result) - dev_err(&port->dev, - "%s - failed resubmitting read urb, error %d\n", - __func__, result); - return result; -} + /* Clear RTS line */ + send_control_msg(port, CONTROL_RTS, 0); -static void opticon_close(struct usb_serial_port *port) -{ - struct opticon_private *priv = usb_get_serial_data(port->serial); + /* clear the halt status of the endpoint */ + usb_clear_halt(port->serial->dev, port->read_urb->pipe); + + res = usb_serial_generic_open(tty, port); + if (!res) + return res; - dbg("%s - port %d", __func__, port->number); + /* Request CTS line state, sometimes during opening the current + * CTS state can be missed. */ + send_control_msg(port, RESEND_CTS_STATE, 1); - /* shutdown our urbs */ - usb_kill_urb(priv->bulk_read_urb); + return res; } -static void opticon_write_bulk_callback(struct urb *urb) +static void opticon_write_control_callback(struct urb *urb) { - struct opticon_private *priv = urb->context; + struct usb_serial_port *port = urb->context; + struct opticon_private *priv = usb_get_serial_port_data(port); int status = urb->status; unsigned long flags; @@ -191,32 +166,32 @@ static void opticon_write_bulk_callback(struct urb *urb) kfree(urb->setup_packet); if (status) - dbg("%s - nonzero write bulk status received: %d", - __func__, status); + dev_dbg(&port->dev, + "%s - non-zero urb status received: %d\n", + __func__, status); spin_lock_irqsave(&priv->lock, flags); --priv->outstanding_urbs; spin_unlock_irqrestore(&priv->lock, flags); - usb_serial_port_softint(priv->port); + usb_serial_port_softint(port); } static int opticon_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count) { - struct opticon_private *priv = usb_get_serial_data(port->serial); + struct opticon_private *priv = usb_get_serial_port_data(port); struct usb_serial *serial = port->serial; struct urb *urb; unsigned char *buffer; unsigned long flags; int status; - - dbg("%s - port %d", __func__, port->number); + struct usb_ctrlrequest *dr; spin_lock_irqsave(&priv->lock, flags); if (priv->outstanding_urbs > URB_UPPER_LIMIT) { spin_unlock_irqrestore(&priv->lock, flags); - dbg("%s - write limit hit", __func__); + dev_dbg(&port->dev, "%s - write limit hit\n", __func__); return 0; } priv->outstanding_urbs++; @@ -224,51 +199,44 @@ static int opticon_write(struct tty_struct *tty, struct usb_serial_port *port, buffer = kmalloc(count, GFP_ATOMIC); if (!buffer) { - dev_err(&port->dev, "out of memory\n"); count = -ENOMEM; goto error_no_buffer; } urb = usb_alloc_urb(0, GFP_ATOMIC); if (!urb) { - dev_err(&port->dev, "no more free urbs\n"); count = -ENOMEM; goto error_no_urb; } memcpy(buffer, buf, count); - usb_serial_debug_data(debug, &port->dev, __func__, count, buffer); + usb_serial_debug_data(&port->dev, __func__, count, buffer); - if (port->bulk_out_endpointAddress) { - usb_fill_bulk_urb(urb, serial->dev, - usb_sndbulkpipe(serial->dev, - port->bulk_out_endpointAddress), - buffer, count, opticon_write_bulk_callback, priv); - } else { - struct usb_ctrlrequest *dr; - - dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO); - if (!dr) - return -ENOMEM; - - dr->bRequestType = USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT; - dr->bRequest = 0x01; - dr->wValue = 0; - dr->wIndex = 0; - dr->wLength = cpu_to_le16(count); - - usb_fill_control_urb(urb, serial->dev, - usb_sndctrlpipe(serial->dev, 0), - (unsigned char *)dr, buffer, count, - opticon_write_bulk_callback, priv); + /* The connected devices do not have a bulk write endpoint, + * to transmit data to de barcode device the control endpoint is used */ + dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO); + if (!dr) { + count = -ENOMEM; + goto error_no_dr; } + dr->bRequestType = USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT; + dr->bRequest = 0x01; + dr->wValue = 0; + dr->wIndex = 0; + dr->wLength = cpu_to_le16(count); + + usb_fill_control_urb(urb, serial->dev, + usb_sndctrlpipe(serial->dev, 0), + (unsigned char *)dr, buffer, count, + opticon_write_control_callback, port); + /* send it down the pipe */ status = usb_submit_urb(urb, GFP_ATOMIC); if (status) { dev_err(&port->dev, - "%s - usb_submit_urb(write bulk) failed with status = %d\n", + "%s - usb_submit_urb(write endpoint) failed status = %d\n", __func__, status); count = status; goto error; @@ -280,6 +248,8 @@ static int opticon_write(struct tty_struct *tty, struct usb_serial_port *port, return count; error: + kfree(dr); +error_no_dr: usb_free_urb(urb); error_no_urb: kfree(buffer); @@ -293,11 +263,9 @@ error_no_buffer: static int opticon_write_room(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; - struct opticon_private *priv = usb_get_serial_data(port->serial); + struct opticon_private *priv = usb_get_serial_port_data(port); unsigned long flags; - dbg("%s - port %d", __func__, port->number); - /* * We really can take almost anything the user throws at us * but let's pick a nice big number to tell the tty @@ -306,7 +274,7 @@ static int opticon_write_room(struct tty_struct *tty) spin_lock_irqsave(&priv->lock, flags); if (priv->outstanding_urbs > URB_UPPER_LIMIT * 2 / 3) { spin_unlock_irqrestore(&priv->lock, flags); - dbg("%s - write limit hit", __func__); + dev_dbg(&port->dev, "%s - write limit hit\n", __func__); return 0; } spin_unlock_irqrestore(&priv->lock, flags); @@ -314,63 +282,56 @@ static int opticon_write_room(struct tty_struct *tty) return 2048; } -static void opticon_throttle(struct tty_struct *tty) +static int opticon_tiocmget(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; - struct opticon_private *priv = usb_get_serial_data(port->serial); + struct opticon_private *priv = usb_get_serial_port_data(port); unsigned long flags; + int result = 0; - dbg("%s - port %d", __func__, port->number); spin_lock_irqsave(&priv->lock, flags); - priv->throttled = true; + if (priv->rts) + result |= TIOCM_RTS; + if (priv->cts) + result |= TIOCM_CTS; spin_unlock_irqrestore(&priv->lock, flags); -} + dev_dbg(&port->dev, "%s - %x\n", __func__, result); + return result; +} -static void opticon_unthrottle(struct tty_struct *tty) +static int opticon_tiocmset(struct tty_struct *tty, + unsigned int set, unsigned int clear) { struct usb_serial_port *port = tty->driver_data; - struct opticon_private *priv = usb_get_serial_data(port->serial); + struct opticon_private *priv = usb_get_serial_port_data(port); unsigned long flags; - int result, was_throttled; - - dbg("%s - port %d", __func__, port->number); + bool rts; + bool changed = false; + int ret; + /* We only support RTS so we only handle that */ spin_lock_irqsave(&priv->lock, flags); - priv->throttled = false; - was_throttled = priv->actually_throttled; - priv->actually_throttled = false; - spin_unlock_irqrestore(&priv->lock, flags); - priv->bulk_read_urb->dev = port->serial->dev; - if (was_throttled) { - result = usb_submit_urb(priv->bulk_read_urb, GFP_ATOMIC); - if (result) - dev_err(&port->dev, - "%s - failed submitting read urb, error %d\n", - __func__, result); - } -} - -static int opticon_tiocmget(struct tty_struct *tty, struct file *file) -{ - struct usb_serial_port *port = tty->driver_data; - struct opticon_private *priv = usb_get_serial_data(port->serial); - unsigned long flags; - int result = 0; + rts = priv->rts; + if (set & TIOCM_RTS) + priv->rts = true; + if (clear & TIOCM_RTS) + priv->rts = false; + changed = rts ^ priv->rts; + spin_unlock_irqrestore(&priv->lock, flags); - dbg("%s - port %d", __func__, port->number); + if (!changed) + return 0; - spin_lock_irqsave(&priv->lock, flags); - if (priv->rts) - result = TIOCM_RTS; - spin_unlock_irqrestore(&priv->lock, flags); + ret = send_control_msg(port, CONTROL_RTS, !rts); + if (ret) + return usb_translate_errors(ret); - dbg("%s - %x", __func__, result); - return result; + return 0; } -static int get_serial_info(struct opticon_private *priv, +static int get_serial_info(struct usb_serial_port *port, struct serial_struct __user *serial) { struct serial_struct tmp; @@ -382,7 +343,7 @@ static int get_serial_info(struct opticon_private *priv, /* fake emulate a 16550 uart to make userspace code happy */ tmp.type = PORT_16550A; - tmp.line = priv->serial->minor; + tmp.line = port->minor; tmp.port = 0; tmp.irq = 0; tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ; @@ -396,17 +357,14 @@ static int get_serial_info(struct opticon_private *priv, return 0; } -static int opticon_ioctl(struct tty_struct *tty, struct file *file, +static int opticon_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { struct usb_serial_port *port = tty->driver_data; - struct opticon_private *priv = usb_get_serial_data(port->serial); - - dbg("%s - port %d, cmd = 0x%x", __func__, port->number, cmd); switch (cmd) { case TIOCGSERIAL: - return get_serial_info(priv, + return get_serial_info(port, (struct serial_struct __user *)arg); } @@ -415,173 +373,65 @@ static int opticon_ioctl(struct tty_struct *tty, struct file *file, static int opticon_startup(struct usb_serial *serial) { - struct opticon_private *priv; - struct usb_host_interface *intf; - int i; - int retval = -ENOMEM; - bool bulk_in_found = false; - - /* create our private serial structure */ - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (priv == NULL) { - dev_err(&serial->dev->dev, "%s - Out of memory\n", __func__); - return -ENOMEM; - } - spin_lock_init(&priv->lock); - priv->serial = serial; - priv->port = serial->port[0]; - priv->udev = serial->dev; - - /* find our bulk endpoint */ - intf = serial->interface->altsetting; - for (i = 0; i < intf->desc.bNumEndpoints; ++i) { - struct usb_endpoint_descriptor *endpoint; - - endpoint = &intf->endpoint[i].desc; - if (!usb_endpoint_is_bulk_in(endpoint)) - continue; - - priv->bulk_read_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!priv->bulk_read_urb) { - dev_err(&priv->udev->dev, "out of memory\n"); - goto error; - } - - priv->buffer_size = le16_to_cpu(endpoint->wMaxPacketSize) * 2; - priv->bulk_in_buffer = kmalloc(priv->buffer_size, GFP_KERNEL); - if (!priv->bulk_in_buffer) { - dev_err(&priv->udev->dev, "out of memory\n"); - goto error; - } - - priv->bulk_address = endpoint->bEndpointAddress; - - /* set up our bulk urb */ - usb_fill_bulk_urb(priv->bulk_read_urb, priv->udev, - usb_rcvbulkpipe(priv->udev, - endpoint->bEndpointAddress), - priv->bulk_in_buffer, priv->buffer_size, - opticon_bulk_callback, priv); - - bulk_in_found = true; - break; - } - - if (!bulk_in_found) { - dev_err(&priv->udev->dev, - "Error - the proper endpoints were not found!\n"); - goto error; + if (!serial->num_bulk_in) { + dev_err(&serial->dev->dev, "no bulk in endpoint\n"); + return -ENODEV; } - usb_set_serial_data(serial, priv); return 0; - -error: - usb_free_urb(priv->bulk_read_urb); - kfree(priv->bulk_in_buffer); - kfree(priv); - return retval; } -static void opticon_disconnect(struct usb_serial *serial) +static int opticon_port_probe(struct usb_serial_port *port) { - struct opticon_private *priv = usb_get_serial_data(serial); - - dbg("%s", __func__); + struct opticon_private *priv; - usb_kill_urb(priv->bulk_read_urb); - usb_free_urb(priv->bulk_read_urb); -} + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; -static void opticon_release(struct usb_serial *serial) -{ - struct opticon_private *priv = usb_get_serial_data(serial); + spin_lock_init(&priv->lock); - dbg("%s", __func__); + usb_set_serial_port_data(port, priv); - kfree(priv->bulk_in_buffer); - kfree(priv); + return 0; } -static int opticon_suspend(struct usb_interface *intf, pm_message_t message) +static int opticon_port_remove(struct usb_serial_port *port) { - struct usb_serial *serial = usb_get_intfdata(intf); - struct opticon_private *priv = usb_get_serial_data(serial); + struct opticon_private *priv = usb_get_serial_port_data(port); - usb_kill_urb(priv->bulk_read_urb); - return 0; -} + kfree(priv); -static int opticon_resume(struct usb_interface *intf) -{ - struct usb_serial *serial = usb_get_intfdata(intf); - struct opticon_private *priv = usb_get_serial_data(serial); - struct usb_serial_port *port = serial->port[0]; - int result; - - mutex_lock(&port->port.mutex); - /* This is protected by the port mutex against close/open */ - if (test_bit(ASYNCB_INITIALIZED, &port->port.flags)) - result = usb_submit_urb(priv->bulk_read_urb, GFP_NOIO); - else - result = 0; - mutex_unlock(&port->port.mutex); - return result; + return 0; } -static struct usb_driver opticon_driver = { - .name = "opticon", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .suspend = opticon_suspend, - .resume = opticon_resume, - .id_table = id_table, - .no_dynamic_id = 1, -}; - static struct usb_serial_driver opticon_device = { .driver = { .owner = THIS_MODULE, .name = "opticon", }, .id_table = id_table, - .usb_driver = &opticon_driver, .num_ports = 1, + .bulk_in_size = 256, .attach = opticon_startup, + .port_probe = opticon_port_probe, + .port_remove = opticon_port_remove, .open = opticon_open, - .close = opticon_close, .write = opticon_write, .write_room = opticon_write_room, - .disconnect = opticon_disconnect, - .release = opticon_release, - .throttle = opticon_throttle, - .unthrottle = opticon_unthrottle, + .throttle = usb_serial_generic_throttle, + .unthrottle = usb_serial_generic_unthrottle, .ioctl = opticon_ioctl, .tiocmget = opticon_tiocmget, + .tiocmset = opticon_tiocmset, + .process_read_urb = opticon_process_read_urb, }; -static int __init opticon_init(void) -{ - int retval; - - retval = usb_serial_register(&opticon_device); - if (retval) - return retval; - retval = usb_register(&opticon_driver); - if (retval) - usb_serial_deregister(&opticon_device); - return retval; -} +static struct usb_serial_driver * const serial_drivers[] = { + &opticon_device, NULL +}; -static void __exit opticon_exit(void) -{ - usb_deregister(&opticon_driver); - usb_serial_deregister(&opticon_device); -} +module_usb_serial_driver(serial_drivers, id_table); -module_init(opticon_init); -module_exit(opticon_exit); +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index ef2977d3a61..a9688940543 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -28,7 +28,6 @@ device features. */ -#define DRIVER_VERSION "v0.7.2" #define DRIVER_AUTHOR "Matthias Urlichs <smurf@smurf.noris.de>" #define DRIVER_DESC "USB Driver for GSM modems" @@ -47,6 +46,8 @@ /* Function prototypes */ static int option_probe(struct usb_serial *serial, const struct usb_device_id *id); +static int option_attach(struct usb_serial *serial); +static void option_release(struct usb_serial *serial); static int option_send_setup(struct usb_serial_port *port); static void option_instat_callback(struct urb *urb); @@ -79,76 +80,12 @@ static void option_instat_callback(struct urb *urb); #define OPTION_PRODUCT_GTM380_MODEM 0x7201 #define HUAWEI_VENDOR_ID 0x12D1 -#define HUAWEI_PRODUCT_E600 0x1001 -#define HUAWEI_PRODUCT_E220 0x1003 -#define HUAWEI_PRODUCT_E220BIS 0x1004 -#define HUAWEI_PRODUCT_E1401 0x1401 -#define HUAWEI_PRODUCT_E1402 0x1402 -#define HUAWEI_PRODUCT_E1403 0x1403 -#define HUAWEI_PRODUCT_E1404 0x1404 -#define HUAWEI_PRODUCT_E1405 0x1405 -#define HUAWEI_PRODUCT_E1406 0x1406 -#define HUAWEI_PRODUCT_E1407 0x1407 -#define HUAWEI_PRODUCT_E1408 0x1408 -#define HUAWEI_PRODUCT_E1409 0x1409 -#define HUAWEI_PRODUCT_E140A 0x140A -#define HUAWEI_PRODUCT_E140B 0x140B -#define HUAWEI_PRODUCT_E140C 0x140C -#define HUAWEI_PRODUCT_E140D 0x140D -#define HUAWEI_PRODUCT_E140E 0x140E -#define HUAWEI_PRODUCT_E140F 0x140F -#define HUAWEI_PRODUCT_E1410 0x1410 -#define HUAWEI_PRODUCT_E1411 0x1411 -#define HUAWEI_PRODUCT_E1412 0x1412 -#define HUAWEI_PRODUCT_E1413 0x1413 -#define HUAWEI_PRODUCT_E1414 0x1414 -#define HUAWEI_PRODUCT_E1415 0x1415 -#define HUAWEI_PRODUCT_E1416 0x1416 -#define HUAWEI_PRODUCT_E1417 0x1417 -#define HUAWEI_PRODUCT_E1418 0x1418 -#define HUAWEI_PRODUCT_E1419 0x1419 -#define HUAWEI_PRODUCT_E141A 0x141A -#define HUAWEI_PRODUCT_E141B 0x141B -#define HUAWEI_PRODUCT_E141C 0x141C -#define HUAWEI_PRODUCT_E141D 0x141D -#define HUAWEI_PRODUCT_E141E 0x141E -#define HUAWEI_PRODUCT_E141F 0x141F -#define HUAWEI_PRODUCT_E1420 0x1420 -#define HUAWEI_PRODUCT_E1421 0x1421 -#define HUAWEI_PRODUCT_E1422 0x1422 -#define HUAWEI_PRODUCT_E1423 0x1423 -#define HUAWEI_PRODUCT_E1424 0x1424 -#define HUAWEI_PRODUCT_E1425 0x1425 -#define HUAWEI_PRODUCT_E1426 0x1426 -#define HUAWEI_PRODUCT_E1427 0x1427 -#define HUAWEI_PRODUCT_E1428 0x1428 -#define HUAWEI_PRODUCT_E1429 0x1429 -#define HUAWEI_PRODUCT_E142A 0x142A -#define HUAWEI_PRODUCT_E142B 0x142B -#define HUAWEI_PRODUCT_E142C 0x142C -#define HUAWEI_PRODUCT_E142D 0x142D -#define HUAWEI_PRODUCT_E142E 0x142E -#define HUAWEI_PRODUCT_E142F 0x142F -#define HUAWEI_PRODUCT_E1430 0x1430 -#define HUAWEI_PRODUCT_E1431 0x1431 -#define HUAWEI_PRODUCT_E1432 0x1432 -#define HUAWEI_PRODUCT_E1433 0x1433 -#define HUAWEI_PRODUCT_E1434 0x1434 -#define HUAWEI_PRODUCT_E1435 0x1435 -#define HUAWEI_PRODUCT_E1436 0x1436 -#define HUAWEI_PRODUCT_E1437 0x1437 -#define HUAWEI_PRODUCT_E1438 0x1438 -#define HUAWEI_PRODUCT_E1439 0x1439 -#define HUAWEI_PRODUCT_E143A 0x143A -#define HUAWEI_PRODUCT_E143B 0x143B -#define HUAWEI_PRODUCT_E143C 0x143C -#define HUAWEI_PRODUCT_E143D 0x143D -#define HUAWEI_PRODUCT_E143E 0x143E -#define HUAWEI_PRODUCT_E143F 0x143F +#define HUAWEI_PRODUCT_E173 0x140C +#define HUAWEI_PRODUCT_E1750 0x1406 #define HUAWEI_PRODUCT_K4505 0x1464 #define HUAWEI_PRODUCT_K3765 0x1465 -#define HUAWEI_PRODUCT_E14AC 0x14AC -#define HUAWEI_PRODUCT_ETS1220 0x1803 +#define HUAWEI_PRODUCT_K4605 0x14C6 +#define HUAWEI_PRODUCT_E173S6 0x1C07 #define QUANTA_VENDOR_ID 0x0408 #define QUANTA_PRODUCT_Q101 0xEA02 @@ -223,9 +160,10 @@ static void option_instat_callback(struct urb *urb); #define NOVATELWIRELESS_PRODUCT_EVDO_EMBEDDED_HIGHSPEED 0x8001 #define NOVATELWIRELESS_PRODUCT_HSPA_EMBEDDED_FULLSPEED 0x9000 #define NOVATELWIRELESS_PRODUCT_HSPA_EMBEDDED_HIGHSPEED 0x9001 -#define NOVATELWIRELESS_PRODUCT_G1 0xA001 -#define NOVATELWIRELESS_PRODUCT_G1_M 0xA002 +#define NOVATELWIRELESS_PRODUCT_E362 0x9010 +#define NOVATELWIRELESS_PRODUCT_E371 0x9011 #define NOVATELWIRELESS_PRODUCT_G2 0xA010 +#define NOVATELWIRELESS_PRODUCT_MC551 0xB001 /* AMOI PRODUCTS */ #define AMOI_VENDOR_ID 0x1614 @@ -257,6 +195,10 @@ static void option_instat_callback(struct urb *urb); #define DELL_PRODUCT_5730_MINICARD_TELUS 0x8181 #define DELL_PRODUCT_5730_MINICARD_VZW 0x8182 +#define DELL_PRODUCT_5800_MINICARD_VZW 0x8195 /* Novatel E362 */ +#define DELL_PRODUCT_5800_V2_MINICARD_VZW 0x8196 /* Novatel E362 */ +#define DELL_PRODUCT_5804_MINICARD_ATT 0x819b /* Novatel E371 */ + #define KYOCERA_VENDOR_ID 0x0c88 #define KYOCERA_PRODUCT_KPC650 0x17da #define KYOCERA_PRODUCT_KPC680 0x180a @@ -293,26 +235,48 @@ static void option_instat_callback(struct urb *urb); #define QUALCOMM_VENDOR_ID 0x05C6 #define CMOTECH_VENDOR_ID 0x16d8 -#define CMOTECH_PRODUCT_6008 0x6008 -#define CMOTECH_PRODUCT_6280 0x6280 +#define CMOTECH_PRODUCT_6001 0x6001 +#define CMOTECH_PRODUCT_CMU_300 0x6002 +#define CMOTECH_PRODUCT_6003 0x6003 +#define CMOTECH_PRODUCT_6004 0x6004 +#define CMOTECH_PRODUCT_6005 0x6005 +#define CMOTECH_PRODUCT_CGU_628A 0x6006 +#define CMOTECH_PRODUCT_CHE_628S 0x6007 +#define CMOTECH_PRODUCT_CMU_301 0x6008 +#define CMOTECH_PRODUCT_CHU_628 0x6280 +#define CMOTECH_PRODUCT_CHU_628S 0x6281 +#define CMOTECH_PRODUCT_CDU_680 0x6803 +#define CMOTECH_PRODUCT_CDU_685A 0x6804 +#define CMOTECH_PRODUCT_CHU_720S 0x7001 +#define CMOTECH_PRODUCT_7002 0x7002 +#define CMOTECH_PRODUCT_CHU_629K 0x7003 +#define CMOTECH_PRODUCT_7004 0x7004 +#define CMOTECH_PRODUCT_7005 0x7005 +#define CMOTECH_PRODUCT_CGU_629 0x7006 +#define CMOTECH_PRODUCT_CHU_629S 0x700a +#define CMOTECH_PRODUCT_CHU_720I 0x7211 +#define CMOTECH_PRODUCT_7212 0x7212 +#define CMOTECH_PRODUCT_7213 0x7213 +#define CMOTECH_PRODUCT_7251 0x7251 +#define CMOTECH_PRODUCT_7252 0x7252 +#define CMOTECH_PRODUCT_7253 0x7253 #define TELIT_VENDOR_ID 0x1bc7 #define TELIT_PRODUCT_UC864E 0x1003 #define TELIT_PRODUCT_UC864G 0x1004 +#define TELIT_PRODUCT_CC864_DUAL 0x1005 +#define TELIT_PRODUCT_CC864_SINGLE 0x1006 +#define TELIT_PRODUCT_DE910_DUAL 0x1010 +#define TELIT_PRODUCT_UE910_V2 0x1012 +#define TELIT_PRODUCT_LE920 0x1200 /* ZTE PRODUCTS */ #define ZTE_VENDOR_ID 0x19d2 #define ZTE_PRODUCT_MF622 0x0001 #define ZTE_PRODUCT_MF628 0x0015 #define ZTE_PRODUCT_MF626 0x0031 -#define ZTE_PRODUCT_CDMA_TECH 0xfffe -#define ZTE_PRODUCT_AC8710 0xfff1 -#define ZTE_PRODUCT_AC2726 0xfff5 -#define ZTE_PRODUCT_AC8710T 0xffff - -/* ZTE PRODUCTS -- alternate vendor ID */ -#define ZTE_VENDOR_ID2 0x1d6b -#define ZTE_PRODUCT_MF_330 0x0002 +#define ZTE_PRODUCT_MC2718 0xffe8 +#define ZTE_PRODUCT_AC2726 0xfff1 #define BENQ_VENDOR_ID 0x04a5 #define BENQ_PRODUCT_H10 0x4068 @@ -339,11 +303,15 @@ static void option_instat_callback(struct urb *urb); #define TOSHIBA_PRODUCT_G450 0x0d45 #define ALINK_VENDOR_ID 0x1e0e +#define ALINK_PRODUCT_PH300 0x9100 #define ALINK_PRODUCT_3GU 0x9200 /* ALCATEL PRODUCTS */ #define ALCATEL_VENDOR_ID 0x1bbb -#define ALCATEL_PRODUCT_X060S 0x0000 +#define ALCATEL_PRODUCT_X060S_X200 0x0000 +#define ALCATEL_PRODUCT_X220_X500D 0x0017 +#define ALCATEL_PRODUCT_L100V 0x011e +#define ALCATEL_PRODUCT_L800MA 0x0203 #define PIRELLI_VENDOR_ID 0x1266 #define PIRELLI_PRODUCT_C100_1 0x1002 @@ -378,25 +346,153 @@ static void option_instat_callback(struct urb *urb); * It seems to contain a Qualcomm QSC6240/6290 chipset */ #define FOUR_G_SYSTEMS_PRODUCT_W14 0x9603 +/* iBall 3.5G connect wireless modem */ +#define IBALL_3_5G_CONNECT 0x9605 + +/* Zoom */ +#define ZOOM_PRODUCT_4597 0x9607 + +/* SpeedUp SU9800 usb 3g modem */ +#define SPEEDUP_PRODUCT_SU9800 0x9800 + /* Haier products */ #define HAIER_VENDOR_ID 0x201e #define HAIER_PRODUCT_CE100 0x2009 -#define CINTERION_VENDOR_ID 0x0681 +/* Cinterion (formerly Siemens) products */ +#define SIEMENS_VENDOR_ID 0x0681 +#define CINTERION_VENDOR_ID 0x1e2d +#define CINTERION_PRODUCT_HC25_MDM 0x0047 +#define CINTERION_PRODUCT_HC25_MDMNET 0x0040 +#define CINTERION_PRODUCT_HC28_MDM 0x004C +#define CINTERION_PRODUCT_HC28_MDMNET 0x004A /* same for HC28J */ +#define CINTERION_PRODUCT_EU3_E 0x0051 +#define CINTERION_PRODUCT_EU3_P 0x0052 +#define CINTERION_PRODUCT_PH8 0x0053 +#define CINTERION_PRODUCT_AHXX 0x0055 +#define CINTERION_PRODUCT_PLXX 0x0060 /* Olivetti products */ #define OLIVETTI_VENDOR_ID 0x0b3c #define OLIVETTI_PRODUCT_OLICARD100 0xc000 +#define OLIVETTI_PRODUCT_OLICARD120 0xc001 +#define OLIVETTI_PRODUCT_OLICARD140 0xc002 +#define OLIVETTI_PRODUCT_OLICARD145 0xc003 +#define OLIVETTI_PRODUCT_OLICARD155 0xc004 +#define OLIVETTI_PRODUCT_OLICARD200 0xc005 +#define OLIVETTI_PRODUCT_OLICARD160 0xc00a +#define OLIVETTI_PRODUCT_OLICARD500 0xc00b /* Celot products */ #define CELOT_VENDOR_ID 0x211f #define CELOT_PRODUCT_CT680M 0x6801 -/* ONDA Communication vendor id */ -#define ONDA_VENDOR_ID 0x1ee8 - -/* ONDA MT825UP HSDPA 14.2 modem */ -#define ONDA_MT825UP 0x000b +/* Samsung products */ +#define SAMSUNG_VENDOR_ID 0x04e8 +#define SAMSUNG_PRODUCT_GT_B3730 0x6889 + +/* YUGA products www.yuga-info.com gavin.kx@qq.com */ +#define YUGA_VENDOR_ID 0x257A +#define YUGA_PRODUCT_CEM600 0x1601 +#define YUGA_PRODUCT_CEM610 0x1602 +#define YUGA_PRODUCT_CEM500 0x1603 +#define YUGA_PRODUCT_CEM510 0x1604 +#define YUGA_PRODUCT_CEM800 0x1605 +#define YUGA_PRODUCT_CEM900 0x1606 + +#define YUGA_PRODUCT_CEU818 0x1607 +#define YUGA_PRODUCT_CEU816 0x1608 +#define YUGA_PRODUCT_CEU828 0x1609 +#define YUGA_PRODUCT_CEU826 0x160A +#define YUGA_PRODUCT_CEU518 0x160B +#define YUGA_PRODUCT_CEU516 0x160C +#define YUGA_PRODUCT_CEU528 0x160D +#define YUGA_PRODUCT_CEU526 0x160F +#define YUGA_PRODUCT_CEU881 0x161F +#define YUGA_PRODUCT_CEU882 0x162F + +#define YUGA_PRODUCT_CWM600 0x2601 +#define YUGA_PRODUCT_CWM610 0x2602 +#define YUGA_PRODUCT_CWM500 0x2603 +#define YUGA_PRODUCT_CWM510 0x2604 +#define YUGA_PRODUCT_CWM800 0x2605 +#define YUGA_PRODUCT_CWM900 0x2606 + +#define YUGA_PRODUCT_CWU718 0x2607 +#define YUGA_PRODUCT_CWU716 0x2608 +#define YUGA_PRODUCT_CWU728 0x2609 +#define YUGA_PRODUCT_CWU726 0x260A +#define YUGA_PRODUCT_CWU518 0x260B +#define YUGA_PRODUCT_CWU516 0x260C +#define YUGA_PRODUCT_CWU528 0x260D +#define YUGA_PRODUCT_CWU581 0x260E +#define YUGA_PRODUCT_CWU526 0x260F +#define YUGA_PRODUCT_CWU582 0x261F +#define YUGA_PRODUCT_CWU583 0x262F + +#define YUGA_PRODUCT_CLM600 0x3601 +#define YUGA_PRODUCT_CLM610 0x3602 +#define YUGA_PRODUCT_CLM500 0x3603 +#define YUGA_PRODUCT_CLM510 0x3604 +#define YUGA_PRODUCT_CLM800 0x3605 +#define YUGA_PRODUCT_CLM900 0x3606 + +#define YUGA_PRODUCT_CLU718 0x3607 +#define YUGA_PRODUCT_CLU716 0x3608 +#define YUGA_PRODUCT_CLU728 0x3609 +#define YUGA_PRODUCT_CLU726 0x360A +#define YUGA_PRODUCT_CLU518 0x360B +#define YUGA_PRODUCT_CLU516 0x360C +#define YUGA_PRODUCT_CLU528 0x360D +#define YUGA_PRODUCT_CLU526 0x360F + +/* Viettel products */ +#define VIETTEL_VENDOR_ID 0x2262 +#define VIETTEL_PRODUCT_VT1000 0x0002 + +/* ZD Incorporated */ +#define ZD_VENDOR_ID 0x0685 +#define ZD_PRODUCT_7000 0x7000 + +/* LG products */ +#define LG_VENDOR_ID 0x1004 +#define LG_PRODUCT_L02C 0x618f + +/* MediaTek products */ +#define MEDIATEK_VENDOR_ID 0x0e8d +#define MEDIATEK_PRODUCT_DC_1COM 0x00a0 +#define MEDIATEK_PRODUCT_DC_4COM 0x00a5 +#define MEDIATEK_PRODUCT_DC_4COM2 0x00a7 +#define MEDIATEK_PRODUCT_DC_5COM 0x00a4 +#define MEDIATEK_PRODUCT_7208_1COM 0x7101 +#define MEDIATEK_PRODUCT_7208_2COM 0x7102 +#define MEDIATEK_PRODUCT_7103_2COM 0x7103 +#define MEDIATEK_PRODUCT_7106_2COM 0x7106 +#define MEDIATEK_PRODUCT_FP_1COM 0x0003 +#define MEDIATEK_PRODUCT_FP_2COM 0x0023 +#define MEDIATEK_PRODUCT_FPDC_1COM 0x0043 +#define MEDIATEK_PRODUCT_FPDC_2COM 0x0033 + +/* Cellient products */ +#define CELLIENT_VENDOR_ID 0x2692 +#define CELLIENT_PRODUCT_MEN200 0x9005 + +/* Hyundai Petatel Inc. products */ +#define PETATEL_VENDOR_ID 0x1ff4 +#define PETATEL_PRODUCT_NP10T_600A 0x600a +#define PETATEL_PRODUCT_NP10T_600E 0x600e + +/* TP-LINK Incorporated products */ +#define TPLINK_VENDOR_ID 0x2357 +#define TPLINK_PRODUCT_MA180 0x0201 + +/* Changhong products */ +#define CHANGHONG_VENDOR_ID 0x2077 +#define CHANGHONG_PRODUCT_CH690 0x7001 + +/* Inovia */ +#define INOVIA_VENDOR_ID 0x20a6 +#define INOVIA_SEW858 0x1105 /* some devices interfaces need special handling due to a number of reasons */ enum option_blacklist_reason { @@ -405,17 +501,80 @@ enum option_blacklist_reason { OPTION_BLACKLIST_RESERVED_IF = 2 }; +#define MAX_BL_NUM 8 struct option_blacklist_info { - const u32 infolen; /* number of interface numbers on blacklist */ - const u8 *ifaceinfo; /* pointer to the array holding the numbers */ - enum option_blacklist_reason reason; + /* bitfield of interface numbers for OPTION_BLACKLIST_SENDSETUP */ + const unsigned long sendsetup; + /* bitfield of interface numbers for OPTION_BLACKLIST_RESERVED_IF */ + const unsigned long reserved; }; -static const u8 four_g_w14_no_sendsetup[] = { 0, 1 }; static const struct option_blacklist_info four_g_w14_blacklist = { - .infolen = ARRAY_SIZE(four_g_w14_no_sendsetup), - .ifaceinfo = four_g_w14_no_sendsetup, - .reason = OPTION_BLACKLIST_SENDSETUP + .sendsetup = BIT(0) | BIT(1), +}; + +static const struct option_blacklist_info alcatel_x200_blacklist = { + .sendsetup = BIT(0) | BIT(1), + .reserved = BIT(4), +}; + +static const struct option_blacklist_info zte_0037_blacklist = { + .sendsetup = BIT(0) | BIT(1), +}; + +static const struct option_blacklist_info zte_k3765_z_blacklist = { + .sendsetup = BIT(0) | BIT(1) | BIT(2), + .reserved = BIT(4), +}; + +static const struct option_blacklist_info zte_mc2718_z_blacklist = { + .sendsetup = BIT(1) | BIT(2) | BIT(3) | BIT(4), +}; + +static const struct option_blacklist_info huawei_cdc12_blacklist = { + .reserved = BIT(1) | BIT(2), +}; + +static const struct option_blacklist_info net_intf0_blacklist = { + .reserved = BIT(0), +}; + +static const struct option_blacklist_info net_intf1_blacklist = { + .reserved = BIT(1), +}; + +static const struct option_blacklist_info net_intf2_blacklist = { + .reserved = BIT(2), +}; + +static const struct option_blacklist_info net_intf3_blacklist = { + .reserved = BIT(3), +}; + +static const struct option_blacklist_info net_intf4_blacklist = { + .reserved = BIT(4), +}; + +static const struct option_blacklist_info net_intf5_blacklist = { + .reserved = BIT(5), +}; + +static const struct option_blacklist_info net_intf6_blacklist = { + .reserved = BIT(6), +}; + +static const struct option_blacklist_info zte_mf626_blacklist = { + .sendsetup = BIT(0) | BIT(1), + .reserved = BIT(4), +}; + +static const struct option_blacklist_info zte_1255_blacklist = { + .reserved = BIT(3) | BIT(4), +}; + +static const struct option_blacklist_info telit_le920_blacklist = { + .sendsetup = BIT(0), + .reserved = BIT(1) | BIT(5), }; static const struct usb_device_id option_ids[] = { @@ -449,76 +608,378 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(QUANTA_VENDOR_ID, QUANTA_PRODUCT_GLX) }, { USB_DEVICE(QUANTA_VENDOR_ID, QUANTA_PRODUCT_GKE) }, { USB_DEVICE(QUANTA_VENDOR_ID, QUANTA_PRODUCT_GLE) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220BIS, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1401, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1402, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1403, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1404, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1405, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1406, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1407, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1408, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1409, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E140A, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E140B, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E140C, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E140D, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E140E, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E140F, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1410, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1411, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1412, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1413, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1414, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1415, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1416, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1417, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1418, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1419, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E141A, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E141B, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E141C, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E141D, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E141E, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E141F, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1420, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1421, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1422, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1423, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1424, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1425, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1426, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1427, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1428, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1429, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E142A, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E142B, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E142C, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E142D, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E142E, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E142F, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1430, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1431, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1432, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1433, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1434, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1435, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1436, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1437, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1438, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1439, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143A, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143B, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143C, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143D, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143E, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143F, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4505, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3765, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_ETS1220, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E14AC, 0xff, 0xff, 0xff) }, + { USB_DEVICE(QUANTA_VENDOR_ID, 0xea42), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1c05, USB_CLASS_COMM, 0x02, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1c1f, USB_CLASS_COMM, 0x02, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1c23, USB_CLASS_COMM, 0x02, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E173, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t) &net_intf1_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E173S6, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t) &net_intf1_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1750, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t) &net_intf2_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1441, USB_CLASS_COMM, 0x02, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1442, USB_CLASS_COMM, 0x02, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4505, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t) &huawei_cdc12_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3765, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t) &huawei_cdc12_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x14ac, 0xff, 0xff, 0xff), /* Huawei E1820 */ + .driver_info = (kernel_ulong_t) &net_intf1_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4605, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t) &huawei_cdc12_blacklist }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0xff, 0xff) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x01) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x02) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x03) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x04) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x05) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x06) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x0A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x0B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x0D) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x0E) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x0F) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x10) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x12) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x13) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x14) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x15) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x17) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x18) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x19) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x1A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x1B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x1C) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x31) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x32) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x33) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x34) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x35) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x36) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x3A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x3B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x3D) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x3E) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x3F) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x48) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x49) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x4A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x4B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x4C) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x61) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x62) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x63) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x64) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x65) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x66) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x6A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x6B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x6D) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x6E) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x6F) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x72) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x73) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x74) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x75) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x78) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x79) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x7A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x7B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x7C) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x01) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x02) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x03) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x04) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x05) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x06) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x0A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x0B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x0D) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x0E) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x0F) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x10) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x12) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x13) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x14) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x15) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x17) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x18) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x19) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x1A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x1B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x1C) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x31) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x32) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x33) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x34) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x35) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x36) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x3A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x3B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x3D) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x3E) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x3F) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x48) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x49) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x4A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x4B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x4C) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x61) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x62) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x63) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x64) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x65) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x66) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x6A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x6B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x6D) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x6E) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x6F) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x72) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x73) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x74) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x75) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x78) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x79) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x7A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x7B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x7C) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x01) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x02) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x03) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x04) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x05) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x06) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x0A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x0B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x0D) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x0E) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x0F) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x10) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x12) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x13) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x14) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x15) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x17) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x18) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x19) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x1A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x1B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x1C) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x31) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x32) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x33) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x34) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x35) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x36) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x3A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x3B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x3D) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x3E) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x3F) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x48) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x49) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x4A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x4B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x4C) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x61) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x62) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x63) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x64) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x65) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x66) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x6A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x6B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x6D) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x6E) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x6F) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x72) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x73) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x74) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x75) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x78) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x79) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x7A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x7B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x7C) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x01) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x02) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x03) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x04) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x05) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x06) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x0A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x0B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x0D) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x0E) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x0F) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x10) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x12) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x13) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x14) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x15) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x17) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x18) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x19) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x1A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x1B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x1C) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x31) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x32) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x33) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x34) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x35) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x36) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x3A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x3B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x3D) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x3E) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x3F) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x48) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x49) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x4A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x4B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x4C) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x61) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x62) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x63) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x64) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x65) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x66) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x6A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x6B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x6D) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x6E) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x6F) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x72) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x73) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x74) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x75) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x78) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x79) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x7A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x7B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x7C) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x01) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x02) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x03) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x04) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x05) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x06) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x0A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x0B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x0D) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x0E) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x0F) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x10) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x12) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x13) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x14) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x15) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x17) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x18) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x19) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x1A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x1B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x1C) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x31) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x32) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x33) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x34) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x35) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x36) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x3A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x3B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x3D) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x3E) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x3F) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x48) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x49) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x4A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x4B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x4C) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x61) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x62) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x63) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x64) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x65) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x66) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x6A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x6B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x6D) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x6E) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x6F) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x72) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x73) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x74) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x75) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x78) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x79) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x7A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x7B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x7C) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x01) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x02) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x03) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x04) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x05) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x06) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x0A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x0B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x0D) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x0E) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x0F) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x10) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x12) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x13) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x14) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x15) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x17) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x18) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x19) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x1A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x1B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x1C) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x31) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x32) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x33) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x34) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x35) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x36) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x3A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x3B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x3D) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x3E) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x3F) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x48) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x49) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x4A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x4B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x4C) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x61) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x62) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x63) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x64) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x65) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x66) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x6A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x6B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x6D) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x6E) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x6F) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x72) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x73) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x74) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x75) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x78) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x79) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x7A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x7B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x7C) }, + + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V640) }, { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V620) }, { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V740) }, @@ -544,6 +1005,7 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EVDO_EMBEDDED_FULLSPEED) }, { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_EMBEDDED_FULLSPEED) }, { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EVDO_HIGHSPEED) }, + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED) }, { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED3) }, { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED4) }, { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED5) }, @@ -554,9 +1016,11 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC547) }, { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EVDO_EMBEDDED_HIGHSPEED) }, { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_EMBEDDED_HIGHSPEED) }, - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_G1) }, - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_G1_M) }, { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_G2) }, + /* Novatel Ovation MC551 a.k.a. Verizon USB551L */ + { USB_DEVICE_AND_INTERFACE_INFO(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC551, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_E362, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_E371, 0xff, 0xff, 0xff) }, { USB_DEVICE(AMOI_VENDOR_ID, AMOI_PRODUCT_H01) }, { USB_DEVICE(AMOI_VENDOR_ID, AMOI_PRODUCT_H01A) }, @@ -579,43 +1043,92 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(DELL_VENDOR_ID, DELL_PRODUCT_5730_MINICARD_SPRINT) }, /* Dell Wireless 5730 Mobile Broadband EVDO/HSPA Mini-Card */ { USB_DEVICE(DELL_VENDOR_ID, DELL_PRODUCT_5730_MINICARD_TELUS) }, /* Dell Wireless 5730 Mobile Broadband EVDO/HSPA Mini-Card */ { USB_DEVICE(DELL_VENDOR_ID, DELL_PRODUCT_5730_MINICARD_VZW) }, /* Dell Wireless 5730 Mobile Broadband EVDO/HSPA Mini-Card */ + { USB_DEVICE_AND_INTERFACE_INFO(DELL_VENDOR_ID, DELL_PRODUCT_5800_MINICARD_VZW, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(DELL_VENDOR_ID, DELL_PRODUCT_5800_V2_MINICARD_VZW, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(DELL_VENDOR_ID, DELL_PRODUCT_5804_MINICARD_ATT, 0xff, 0xff, 0xff) }, { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_E100A) }, /* ADU-E100, ADU-310 */ { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_500A) }, { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_620UW) }, { USB_DEVICE(AXESSTEL_VENDOR_ID, AXESSTEL_PRODUCT_MV110H) }, { USB_DEVICE(YISO_VENDOR_ID, YISO_PRODUCT_U893) }, - { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_C100_1) }, - { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_C100_2) }, - { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_1004) }, - { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_1005) }, - { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_1006) }, - { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_1007) }, - { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_1008) }, - { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_1009) }, - { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_100A) }, - { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_100B) }, - { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_100C) }, - { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_100D) }, - { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_100E) }, - { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_100F) }, - { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_1010) }, - { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_1011) }, - { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_1012) }, + { USB_DEVICE_INTERFACE_CLASS(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_C100_1, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_C100_2, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_1004, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_1005, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_1006, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_1007, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_1008, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_1009, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_100A, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_100B, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_100C, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_100D, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_100E, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_100F, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_1010, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_1011, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_1012, 0xff) }, { USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_PRODUCT_KPC650) }, { USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_PRODUCT_KPC680) }, - { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6000)}, /* ZTE AC8700 */ { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6613)}, /* Onda H600/ZTE MF330 */ - { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6280) }, /* BP3-USB & BP3-EXT HSDPA */ - { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6008) }, + { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x0023)}, /* ONYX 3G device */ + { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x9000)}, /* SIMCom SIM5218 */ + { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6001) }, + { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CMU_300) }, + { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6003), + .driver_info = (kernel_ulong_t)&net_intf0_blacklist }, + { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6004) }, + { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6005) }, + { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CGU_628A) }, + { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CHE_628S), + .driver_info = (kernel_ulong_t)&net_intf0_blacklist }, + { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CMU_301), + .driver_info = (kernel_ulong_t)&net_intf0_blacklist }, + { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CHU_628), + .driver_info = (kernel_ulong_t)&net_intf0_blacklist }, + { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CHU_628S) }, + { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CDU_680) }, + { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CDU_685A) }, + { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CHU_720S), + .driver_info = (kernel_ulong_t)&net_intf0_blacklist }, + { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_7002), + .driver_info = (kernel_ulong_t)&net_intf0_blacklist }, + { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CHU_629K), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_7004), + .driver_info = (kernel_ulong_t)&net_intf3_blacklist }, + { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_7005) }, + { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CGU_629), + .driver_info = (kernel_ulong_t)&net_intf5_blacklist }, + { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CHU_629S), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CHU_720I), + .driver_info = (kernel_ulong_t)&net_intf0_blacklist }, + { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_7212), + .driver_info = (kernel_ulong_t)&net_intf0_blacklist }, + { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_7213), + .driver_info = (kernel_ulong_t)&net_intf0_blacklist }, + { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_7251), + .driver_info = (kernel_ulong_t)&net_intf1_blacklist }, + { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_7252), + .driver_info = (kernel_ulong_t)&net_intf1_blacklist }, + { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_7253), + .driver_info = (kernel_ulong_t)&net_intf1_blacklist }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UC864E) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UC864G) }, + { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_CC864_DUAL) }, + { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_CC864_SINGLE) }, + { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_DE910_DUAL) }, + { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UE910_V2) }, + { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE920), + .driver_info = (kernel_ulong_t)&telit_le920_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF622, 0xff, 0xff, 0xff) }, /* ZTE WCDMA products */ - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0002, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0002, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf1_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0003, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0004, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0005, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0006, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0007, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0008, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0009, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x000a, 0xff, 0xff, 0xff) }, @@ -626,56 +1139,64 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x000f, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0010, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0011, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0012, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0012, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf1_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0013, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0014, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF628, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0016, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0017, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0017, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf3_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0018, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0019, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0019, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf3_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0020, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0021, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0021, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0022, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0023, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0024, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0025, 0xff, 0xff, 0xff) }, - /* { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0026, 0xff, 0xff, 0xff) }, */ + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0025, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf1_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0028, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0029, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0030, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF626, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF626, 0xff, + 0xff, 0xff), .driver_info = (kernel_ulong_t)&zte_mf626_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0032, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0033, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0034, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0037, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0037, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&zte_0037_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0038, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0039, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0040, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0042, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0042, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0043, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0044, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0048, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0049, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0049, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf5_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0050, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0051, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0052, 0xff, 0xff, 0xff) }, - /* { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0053, 0xff, 0xff, 0xff) }, */ + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0052, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0054, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0055, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0055, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf1_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0056, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0057, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0058, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0059, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0058, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0061, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0062, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0063, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0063, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0064, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0065, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0066, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0067, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0069, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0070, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0076, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0077, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0078, 0xff, 0xff, 0xff) }, @@ -684,44 +1205,96 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0083, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0086, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0087, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0104, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0088, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0089, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0090, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0091, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0092, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0093, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0094, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0095, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0096, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0097, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0104, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0105, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0106, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0108, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0113, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0113, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf5_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0117, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0118, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0121, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0118, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf5_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0121, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf5_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0122, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0123, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0124, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0125, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0126, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0123, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0124, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf5_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0125, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf6_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0126, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf5_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0128, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0135, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0136, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0137, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0139, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0142, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0143, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0144, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0145, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0146, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0147, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0148, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0149, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0150, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0151, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0152, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0153, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0154, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0155, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0156, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0157, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0158, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0157, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf5_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0158, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf3_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0159, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0160, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0161, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0162, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1008, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1010, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1012, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0164, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0165, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0167, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0189, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0191, 0xff, 0xff, 0xff), /* ZTE EuFi890 */ + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0196, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0197, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0199, 0xff, 0xff, 0xff), /* ZTE MF820S */ + .driver_info = (kernel_ulong_t)&net_intf1_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0200, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0201, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0254, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0257, 0xff, 0xff, 0xff), /* ZTE MF821 */ + .driver_info = (kernel_ulong_t)&net_intf3_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0265, 0xff, 0xff, 0xff), /* ONDA MT8205 */ + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0284, 0xff, 0xff, 0xff), /* ZTE MF880 */ + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0317, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0326, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0330, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0395, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0412, 0xff, 0xff, 0xff), /* Telewell TW-LTE 4G */ + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0414, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0417, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1008, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1010, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1012, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1018, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1021, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf2_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1057, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1058, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1059, 0xff, 0xff, 0xff) }, @@ -837,18 +1410,24 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1169, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1170, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1244, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1245, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1245, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1246, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1247, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1247, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1248, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1249, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1250, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1251, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1252, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1252, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1253, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1254, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1255, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1256, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1254, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1255, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&zte_1255_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1256, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1257, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1258, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1259, 0xff, 0xff, 0xff) }, @@ -862,7 +1441,8 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1267, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1268, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1269, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1270, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1270, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf5_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1271, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1272, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1273, 0xff, 0xff, 0xff) }, @@ -893,21 +1473,85 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1298, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1299, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1300, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1301, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1302, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1303, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1333, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1401, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf2_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1402, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf2_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1424, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf2_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1425, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf2_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1426, 0xff, 0xff, 0xff), /* ZTE MF91 */ + .driver_info = (kernel_ulong_t)&net_intf2_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1428, 0xff, 0xff, 0xff), /* Telewell TW-LTE 4G v2 */ + .driver_info = (kernel_ulong_t)&net_intf2_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1533, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1534, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1535, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1545, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1546, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1547, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1565, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1566, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1567, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1589, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1590, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1591, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1592, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1594, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1596, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1598, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1600, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2002, 0xff, + 0xff, 0xff), .driver_info = (kernel_ulong_t)&zte_k3765_z_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2003, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0014, 0xff, 0xff, 0xff) }, /* ZTE CDMA products */ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0027, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0059, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0060, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0070, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0073, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0130, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0141, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2002, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2003, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_CDMA_TECH, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC8710, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0094, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0130, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf1_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0133, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf3_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0141, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf5_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0147, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0152, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0168, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0170, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0176, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf3_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0178, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf3_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffe9, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff8b, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff8c, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff8d, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff8e, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff8f, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff90, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff91, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff92, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff93, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff94, 0xff, 0xff, 0xff) }, + + /* NOTE: most ZTE CDMA devices should be driven by zte_ev, not option */ + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MC2718, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&zte_mc2718_z_blacklist }, + { USB_VENDOR_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff, 0x02, 0x01) }, + { USB_VENDOR_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff, 0x02, 0x05) }, + { USB_VENDOR_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff, 0x86, 0x10) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC2726, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC8710T, 0xff, 0xff, 0xff) }, - { USB_DEVICE(ZTE_VENDOR_ID2, ZTE_PRODUCT_MF_330) }, + { USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_H10) }, { USB_DEVICE(DLINK_VENDOR_ID, DLINK_PRODUCT_DWM_652) }, { USB_DEVICE(ALINK_VENDOR_ID, DLINK_PRODUCT_DWM_652_U5) }, /* Yes, ALINK_VENDOR_ID */ @@ -920,52 +1564,170 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(TOSHIBA_VENDOR_ID, TOSHIBA_PRODUCT_G450) }, { USB_DEVICE(TOSHIBA_VENDOR_ID, TOSHIBA_PRODUCT_HSDPA_MINICARD ) }, /* Toshiba 3G HSDPA == Novatel Expedite EU870D MiniCard */ { USB_DEVICE(ALINK_VENDOR_ID, 0x9000) }, + { USB_DEVICE(ALINK_VENDOR_ID, ALINK_PRODUCT_PH300) }, { USB_DEVICE_AND_INTERFACE_INFO(ALINK_VENDOR_ID, ALINK_PRODUCT_3GU, 0xff, 0xff, 0xff) }, - { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_X060S) }, + { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_X060S_X200), + .driver_info = (kernel_ulong_t)&alcatel_x200_blacklist + }, + { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_X220_X500D), + .driver_info = (kernel_ulong_t)&net_intf6_blacklist }, + { USB_DEVICE(ALCATEL_VENDOR_ID, 0x0052), + .driver_info = (kernel_ulong_t)&net_intf6_blacklist }, + { USB_DEVICE(ALCATEL_VENDOR_ID, 0x00b6), + .driver_info = (kernel_ulong_t)&net_intf3_blacklist }, + { USB_DEVICE(ALCATEL_VENDOR_ID, 0x00b7), + .driver_info = (kernel_ulong_t)&net_intf5_blacklist }, + { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_L100V), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_L800MA), + .driver_info = (kernel_ulong_t)&net_intf2_blacklist }, { USB_DEVICE(AIRPLUS_VENDOR_ID, AIRPLUS_PRODUCT_MCD650) }, { USB_DEVICE(TLAYTECH_VENDOR_ID, TLAYTECH_PRODUCT_TEU800) }, { USB_DEVICE(LONGCHEER_VENDOR_ID, FOUR_G_SYSTEMS_PRODUCT_W14), .driver_info = (kernel_ulong_t)&four_g_w14_blacklist }, + { USB_DEVICE_INTERFACE_CLASS(LONGCHEER_VENDOR_ID, SPEEDUP_PRODUCT_SU9800, 0xff) }, + { USB_DEVICE(LONGCHEER_VENDOR_ID, ZOOM_PRODUCT_4597) }, + { USB_DEVICE(LONGCHEER_VENDOR_ID, IBALL_3_5G_CONNECT) }, { USB_DEVICE(HAIER_VENDOR_ID, HAIER_PRODUCT_CE100) }, /* Pirelli */ - { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_C100_1)}, - { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_C100_2)}, - { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_1004)}, - { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_1005)}, - { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_1006)}, - { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_1007)}, - { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_1008)}, - { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_1009)}, - { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_100A)}, - { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_100B) }, - { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_100C) }, - { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_100D) }, - { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_100E) }, - { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_100F) }, - { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_1011)}, - { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_1012)}, - { USB_DEVICE(CINTERION_VENDOR_ID, 0x0047) }, - { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD100) }, + { USB_DEVICE_INTERFACE_CLASS(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_C100_1, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_C100_2, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_1004, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_1005, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_1006, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_1007, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_1008, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_1009, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_100A, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_100B, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_100C, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_100D, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_100E, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_100F, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_1011, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_1012, 0xff) }, + /* Cinterion */ + { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_EU3_E) }, + { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_EU3_P) }, + { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PH8), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_AHXX) }, + { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PLXX), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_HC28_MDM) }, + { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_HC28_MDMNET) }, + { USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC25_MDM) }, + { USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC25_MDMNET) }, + { USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC28_MDM) }, /* HC28 enumerates with Siemens or Cinterion VID depending on FW revision */ + { USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC28_MDMNET) }, + { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD100), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD120), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD140), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD145) }, + { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD155), + .driver_info = (kernel_ulong_t)&net_intf6_blacklist }, + { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD200), + .driver_info = (kernel_ulong_t)&net_intf6_blacklist }, + { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD160), + .driver_info = (kernel_ulong_t)&net_intf6_blacklist }, + { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD500), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, { USB_DEVICE(CELOT_VENDOR_ID, CELOT_PRODUCT_CT680M) }, /* CT-650 CDMA 450 1xEVDO modem */ - { USB_DEVICE(ONDA_VENDOR_ID, ONDA_MT825UP) }, /* ONDA MT825UP modem */ + { USB_DEVICE_AND_INTERFACE_INFO(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_GT_B3730, USB_CLASS_CDC_DATA, 0x00, 0x00) }, /* Samsung GT-B3730 LTE USB modem.*/ + { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEM600) }, + { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEM610) }, + { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEM500) }, + { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEM510) }, + { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEM800) }, + { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEM900) }, + { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEU818) }, + { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEU816) }, + { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEU828) }, + { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEU826) }, + { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEU518) }, + { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEU516) }, + { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEU528) }, + { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEU526) }, + { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWM600) }, + { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWM610) }, + { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWM500) }, + { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWM510) }, + { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWM800) }, + { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWM900) }, + { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWU718) }, + { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWU716) }, + { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWU728) }, + { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWU726) }, + { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWU518) }, + { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWU516) }, + { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWU528) }, + { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWU526) }, + { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLM600) }, + { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLM610) }, + { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLM500) }, + { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLM510) }, + { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLM800) }, + { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLM900) }, + { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLU718) }, + { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLU716) }, + { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLU728) }, + { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLU726) }, + { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLU518) }, + { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLU516) }, + { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLU528) }, + { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLU526) }, + { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEU881) }, + { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEU882) }, + { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWU581) }, + { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWU582) }, + { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWU583) }, + { USB_DEVICE_AND_INTERFACE_INFO(VIETTEL_VENDOR_ID, VIETTEL_PRODUCT_VT1000, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZD_VENDOR_ID, ZD_PRODUCT_7000, 0xff, 0xff, 0xff) }, + { USB_DEVICE(LG_VENDOR_ID, LG_PRODUCT_L02C) }, /* docomo L-02C modem */ + { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, 0x00a1, 0xff, 0x00, 0x00) }, + { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, 0x00a1, 0xff, 0x02, 0x01) }, + { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, 0x00a2, 0xff, 0x00, 0x00) }, + { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, 0x00a2, 0xff, 0x02, 0x01) }, /* MediaTek MT6276M modem & app port */ + { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_1COM, 0x0a, 0x00, 0x00) }, + { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_5COM, 0xff, 0x02, 0x01) }, + { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_5COM, 0xff, 0x00, 0x00) }, + { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_4COM, 0xff, 0x02, 0x01) }, + { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_4COM, 0xff, 0x00, 0x00) }, + { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_7208_1COM, 0x02, 0x00, 0x00) }, + { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_7208_2COM, 0x02, 0x02, 0x01) }, + { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FP_1COM, 0x0a, 0x00, 0x00) }, + { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FP_2COM, 0x0a, 0x00, 0x00) }, + { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FPDC_1COM, 0x0a, 0x00, 0x00) }, + { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FPDC_2COM, 0x0a, 0x00, 0x00) }, + { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_7103_2COM, 0xff, 0x00, 0x00) }, + { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_7106_2COM, 0x02, 0x02, 0x01) }, + { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_4COM2, 0xff, 0x02, 0x01) }, + { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_4COM2, 0xff, 0x00, 0x00) }, + { USB_DEVICE(CELLIENT_VENDOR_ID, CELLIENT_PRODUCT_MEN200) }, + { USB_DEVICE(PETATEL_VENDOR_ID, PETATEL_PRODUCT_NP10T_600A) }, + { USB_DEVICE(PETATEL_VENDOR_ID, PETATEL_PRODUCT_NP10T_600E) }, + { USB_DEVICE(TPLINK_VENDOR_ID, TPLINK_PRODUCT_MA180), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + { USB_DEVICE(TPLINK_VENDOR_ID, 0x9000), /* TP-Link MA260 */ + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + { USB_DEVICE(CHANGHONG_VENDOR_ID, CHANGHONG_PRODUCT_CH690) }, + { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d01, 0xff, 0x02, 0x01) }, /* D-Link DWM-156 (variant) */ + { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d01, 0xff, 0x00, 0x00) }, /* D-Link DWM-156 (variant) */ + { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d02, 0xff, 0x02, 0x01) }, + { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d02, 0xff, 0x00, 0x00) }, + { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d03, 0xff, 0x02, 0x01) }, + { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d03, 0xff, 0x00, 0x00) }, + { USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x3e01, 0xff, 0xff, 0xff) }, /* D-Link DWM-152/C1 */ + { USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x3e02, 0xff, 0xff, 0xff) }, /* D-Link DWM-156/C1 */ + { USB_DEVICE(INOVIA_VENDOR_ID, INOVIA_SEW858) }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, option_ids); -static struct usb_driver option_driver = { - .name = "option", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, -#ifdef CONFIG_PM - .suspend = usb_serial_suspend, - .resume = usb_serial_resume, - .supports_autosuspend = 1, -#endif - .id_table = option_ids, - .no_dynamic_id = 1, -}; - /* The card has three separate interfaces, which the serial driver * recognizes separately, thus num_port=1. */ @@ -976,7 +1738,6 @@ static struct usb_serial_driver option_1port_device = { .name = "option1", }, .description = "GSM modem (1-port)", - .usb_driver = &option_driver, .id_table = option_ids, .num_ports = 1, .probe = option_probe, @@ -986,12 +1747,13 @@ static struct usb_serial_driver option_1port_device = { .write = usb_wwan_write, .write_room = usb_wwan_write_room, .chars_in_buffer = usb_wwan_chars_in_buffer, - .set_termios = usb_wwan_set_termios, .tiocmget = usb_wwan_tiocmget, .tiocmset = usb_wwan_tiocmset, - .attach = usb_wwan_startup, - .disconnect = usb_wwan_disconnect, - .release = usb_wwan_release, + .ioctl = usb_wwan_ioctl, + .attach = option_attach, + .release = option_release, + .port_probe = usb_wwan_port_probe, + .port_remove = usb_wwan_port_remove, .read_int_callback = option_instat_callback, #ifdef CONFIG_PM .suspend = usb_wwan_suspend, @@ -999,134 +1761,138 @@ static struct usb_serial_driver option_1port_device = { #endif }; -static int debug; - -/* per port private data */ - -#define N_IN_URB 4 -#define N_OUT_URB 4 -#define IN_BUFLEN 4096 -#define OUT_BUFLEN 4096 - -struct option_port_private { - /* Input endpoints and buffer for this port */ - struct urb *in_urbs[N_IN_URB]; - u8 *in_buffer[N_IN_URB]; - /* Output endpoints and buffer for this port */ - struct urb *out_urbs[N_OUT_URB]; - u8 *out_buffer[N_OUT_URB]; - unsigned long out_busy; /* Bit vector of URBs in use */ - int opened; - struct usb_anchor delayed; - - /* Settings for the port */ - int rts_state; /* Handshaking pins (outputs) */ - int dtr_state; - int cts_state; /* Handshaking pins (inputs) */ - int dsr_state; - int dcd_state; - int ri_state; - - unsigned long tx_start_time[N_OUT_URB]; +static struct usb_serial_driver * const serial_drivers[] = { + &option_1port_device, NULL }; -/* Functions used by new usb-serial code. */ -static int __init option_init(void) -{ - int retval; - retval = usb_serial_register(&option_1port_device); - if (retval) - goto failed_1port_device_register; - retval = usb_register(&option_driver); - if (retval) - goto failed_driver_register; +struct option_private { + u8 bInterfaceNumber; +}; - printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" - DRIVER_DESC "\n"); +module_usb_serial_driver(serial_drivers, option_ids); - return 0; +static bool is_blacklisted(const u8 ifnum, enum option_blacklist_reason reason, + const struct option_blacklist_info *blacklist) +{ + unsigned long num; + const unsigned long *intf_list; -failed_driver_register: - usb_serial_deregister(&option_1port_device); -failed_1port_device_register: - return retval; -} + if (blacklist) { + if (reason == OPTION_BLACKLIST_SENDSETUP) + intf_list = &blacklist->sendsetup; + else if (reason == OPTION_BLACKLIST_RESERVED_IF) + intf_list = &blacklist->reserved; + else { + BUG_ON(reason); + return false; + } -static void __exit option_exit(void) -{ - usb_deregister(&option_driver); - usb_serial_deregister(&option_1port_device); + for_each_set_bit(num, intf_list, MAX_BL_NUM + 1) { + if (num == ifnum) + return true; + } + } + return false; } -module_init(option_init); -module_exit(option_exit); - static int option_probe(struct usb_serial *serial, const struct usb_device_id *id) { - struct usb_wwan_intf_private *data; - /* D-Link DWM 652 still exposes CD-Rom emulation interface in modem mode */ - if (serial->dev->descriptor.idVendor == DLINK_VENDOR_ID && - serial->dev->descriptor.idProduct == DLINK_PRODUCT_DWM_652 && - serial->interface->cur_altsetting->desc.bInterfaceClass == 0x8) - return -ENODEV; + struct usb_interface_descriptor *iface_desc = + &serial->interface->cur_altsetting->desc; + struct usb_device_descriptor *dev_desc = &serial->dev->descriptor; - /* Bandrich modem and AT command interface is 0xff */ - if ((serial->dev->descriptor.idVendor == BANDRICH_VENDOR_ID || - serial->dev->descriptor.idVendor == PIRELLI_VENDOR_ID) && - serial->interface->cur_altsetting->desc.bInterfaceClass != 0xff) + /* Never bind to the CD-Rom emulation interface */ + if (iface_desc->bInterfaceClass == 0x08) return -ENODEV; - /* Don't bind network interfaces on Huawei K3765 & K4505 */ - if (serial->dev->descriptor.idVendor == HUAWEI_VENDOR_ID && - (serial->dev->descriptor.idProduct == HUAWEI_PRODUCT_K3765 || - serial->dev->descriptor.idProduct == HUAWEI_PRODUCT_K4505) && - serial->interface->cur_altsetting->desc.bInterfaceNumber == 1) + /* + * Don't bind reserved interfaces (like network ones) which often have + * the same class/subclass/protocol as the serial interfaces. Look at + * the Windows driver .INF files for reserved interface numbers. + */ + if (is_blacklisted( + iface_desc->bInterfaceNumber, + OPTION_BLACKLIST_RESERVED_IF, + (const struct option_blacklist_info *) id->driver_info)) + return -ENODEV; + /* + * Don't bind network interface on Samsung GT-B3730, it is handled by + * a separate module. + */ + if (dev_desc->idVendor == cpu_to_le16(SAMSUNG_VENDOR_ID) && + dev_desc->idProduct == cpu_to_le16(SAMSUNG_PRODUCT_GT_B3730) && + iface_desc->bInterfaceClass != USB_CLASS_CDC_DATA) return -ENODEV; - data = serial->private = kzalloc(sizeof(struct usb_wwan_intf_private), GFP_KERNEL); + /* Store device id so we can use it during attach. */ + usb_set_serial_data(serial, (void *)id); + + return 0; +} + +static int option_attach(struct usb_serial *serial) +{ + struct usb_interface_descriptor *iface_desc; + const struct usb_device_id *id; + struct usb_wwan_intf_private *data; + struct option_private *priv; + data = kzalloc(sizeof(struct usb_wwan_intf_private), GFP_KERNEL); if (!data) return -ENOMEM; - data->send_setup = option_send_setup; + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) { + kfree(data); + return -ENOMEM; + } + + /* Retrieve device id stored at probe. */ + id = usb_get_serial_data(serial); + iface_desc = &serial->interface->cur_altsetting->desc; + + priv->bInterfaceNumber = iface_desc->bInterfaceNumber; + data->private = priv; + + if (!is_blacklisted(iface_desc->bInterfaceNumber, + OPTION_BLACKLIST_SENDSETUP, + (struct option_blacklist_info *)id->driver_info)) { + data->send_setup = option_send_setup; + } spin_lock_init(&data->susp_lock); - data->private = (void *)id->driver_info; + + usb_set_serial_data(serial, data); + return 0; } -static enum option_blacklist_reason is_blacklisted(const u8 ifnum, - const struct option_blacklist_info *blacklist) +static void option_release(struct usb_serial *serial) { - const u8 *info; - int i; - - if (blacklist) { - info = blacklist->ifaceinfo; + struct usb_wwan_intf_private *intfdata = usb_get_serial_data(serial); + struct option_private *priv = intfdata->private; - for (i = 0; i < blacklist->infolen; i++) { - if (info[i] == ifnum) - return blacklist->reason; - } - } - return OPTION_BLACKLIST_NONE; + kfree(priv); + kfree(intfdata); } static void option_instat_callback(struct urb *urb) { int err; int status = urb->status; - struct usb_serial_port *port = urb->context; - struct option_port_private *portdata = usb_get_serial_port_data(port); + struct usb_serial_port *port = urb->context; + struct device *dev = &port->dev; + struct usb_wwan_port_private *portdata = + usb_get_serial_port_data(port); - dbg("%s", __func__); - dbg("%s: urb %p port %p has data %p", __func__, urb, port, portdata); + dev_dbg(dev, "%s: urb %p port %p has data %p\n", __func__, urb, port, portdata); if (status == 0) { struct usb_ctrlrequest *req_pkt = (struct usb_ctrlrequest *)urb->transfer_buffer; if (!req_pkt) { - dbg("%s: NULL req_pkt", __func__); + dev_dbg(dev, "%s: NULL req_pkt\n", __func__); return; } if ((req_pkt->bRequestType == 0xA1) && @@ -1136,7 +1902,7 @@ static void option_instat_callback(struct urb *urb) urb->transfer_buffer + sizeof(struct usb_ctrlrequest)); - dbg("%s: signal x%x", __func__, signals); + dev_dbg(dev, "%s: signal x%x\n", __func__, signals); old_dcd_state = portdata->dcd_state; portdata->cts_state = 1; @@ -1144,25 +1910,21 @@ static void option_instat_callback(struct urb *urb) portdata->dsr_state = ((signals & 0x02) ? 1 : 0); portdata->ri_state = ((signals & 0x08) ? 1 : 0); - if (old_dcd_state && !portdata->dcd_state) { - struct tty_struct *tty = - tty_port_tty_get(&port->port); - if (tty && !C_CLOCAL(tty)) - tty_hangup(tty); - tty_kref_put(tty); - } + if (old_dcd_state && !portdata->dcd_state) + tty_port_tty_hangup(&port->port, true); } else { - dbg("%s: type %x req %x", __func__, + dev_dbg(dev, "%s: type %x req %x\n", __func__, req_pkt->bRequestType, req_pkt->bRequest); } } else - err("%s: error %d", __func__, status); + dev_err(dev, "%s: error %d\n", __func__, status); /* Resubmit urb so we continue receiving IRQ data */ if (status != -ESHUTDOWN && status != -ENOENT) { + usb_mark_last_busy(port->serial->dev); err = usb_submit_urb(urb, GFP_ATOMIC); if (err) - dbg("%s: resubmit intr urb failed. (%d)", + dev_dbg(dev, "%s: resubmit intr urb failed. (%d)\n", __func__, err); } } @@ -1175,19 +1937,11 @@ static void option_instat_callback(struct urb *urb) static int option_send_setup(struct usb_serial_port *port) { struct usb_serial *serial = port->serial; - struct usb_wwan_intf_private *intfdata = - (struct usb_wwan_intf_private *) serial->private; - struct option_port_private *portdata; - int ifNum = serial->interface->cur_altsetting->desc.bInterfaceNumber; + struct usb_wwan_intf_private *intfdata = usb_get_serial_data(serial); + struct option_private *priv = intfdata->private; + struct usb_wwan_port_private *portdata; int val = 0; - dbg("%s", __func__); - - if (is_blacklisted(ifNum, - (struct option_blacklist_info *) intfdata->private) - == OPTION_BLACKLIST_SENDSETUP) { - dbg("No send_setup on blacklisted interface #%d\n", ifNum); - return -EIO; - } + int res; portdata = usb_get_serial_port_data(port); @@ -1196,15 +1950,19 @@ static int option_send_setup(struct usb_serial_port *port) if (portdata->rts_state) val |= 0x02; - return usb_control_msg(serial->dev, - usb_rcvctrlpipe(serial->dev, 0), - 0x22, 0x21, val, ifNum, NULL, 0, USB_CTRL_SET_TIMEOUT); + res = usb_autopm_get_interface(serial->interface); + if (res) + return res; + + res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + 0x22, 0x21, val, priv->bInterfaceNumber, NULL, + 0, USB_CTRL_SET_TIMEOUT); + + usb_autopm_put_interface(serial->interface); + + return res; } MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_VERSION(DRIVER_VERSION); MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug messages"); diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c index e199b0f4f99..a4b88bc038b 100644 --- a/drivers/usb/serial/oti6858.c +++ b/drivers/usb/serial/oti6858.c @@ -39,7 +39,6 @@ #include <linux/kernel.h> #include <linux/errno.h> -#include <linux/init.h> #include <linux/slab.h> #include <linux/tty.h> #include <linux/tty_driver.h> @@ -57,7 +56,6 @@ #define OTI6858_DESCRIPTION \ "Ours Technology Inc. OTi-6858 USB to serial adapter driver" #define OTI6858_AUTHOR "Tomasz Michal Lukaszewski <FIXME@FIXME>" -#define OTI6858_VERSION "0.2" static const struct usb_device_id id_table[] = { { USB_DEVICE(OTI6858_VENDOR_ID, OTI6858_PRODUCT_ID) }, @@ -66,16 +64,6 @@ static const struct usb_device_id id_table[] = { MODULE_DEVICE_TABLE(usb, id_table); -static struct usb_driver oti6858_driver = { - .name = "oti6858", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, - .no_dynamic_id = 1, -}; - -static int debug; - /* requests */ #define OTI6858_REQ_GET_STATUS (USB_DIR_IN | USB_TYPE_VENDOR | 0x00) #define OTI6858_REQ_T_GET_STATUS 0x01 @@ -114,6 +102,7 @@ struct oti6858_control_pkt { #define TX_BUFFER_EMPTIED 0x09 u8 pin_state; #define PIN_MASK 0x3f +#define PIN_MSR_MASK 0x1b #define PIN_RTS 0x20 /* output pin */ #define PIN_CTS 0x10 /* input pin, active low */ #define PIN_DSR 0x08 /* input pin, active low */ @@ -135,8 +124,6 @@ static void oti6858_close(struct usb_serial_port *port); static void oti6858_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old); static void oti6858_init_termios(struct tty_struct *tty); -static int oti6858_ioctl(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg); static void oti6858_read_int_callback(struct urb *urb); static void oti6858_read_bulk_callback(struct urb *urb); static void oti6858_write_bulk_callback(struct urb *urb); @@ -144,11 +131,11 @@ static int oti6858_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count); static int oti6858_write_room(struct tty_struct *tty); static int oti6858_chars_in_buffer(struct tty_struct *tty); -static int oti6858_tiocmget(struct tty_struct *tty, struct file *file); -static int oti6858_tiocmset(struct tty_struct *tty, struct file *file, +static int oti6858_tiocmget(struct tty_struct *tty); +static int oti6858_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear); -static int oti6858_startup(struct usb_serial *serial); -static void oti6858_release(struct usb_serial *serial); +static int oti6858_port_probe(struct usb_serial_port *port); +static int oti6858_port_remove(struct usb_serial_port *port); /* device info */ static struct usb_serial_driver oti6858_device = { @@ -161,18 +148,22 @@ static struct usb_serial_driver oti6858_device = { .open = oti6858_open, .close = oti6858_close, .write = oti6858_write, - .ioctl = oti6858_ioctl, .set_termios = oti6858_set_termios, .init_termios = oti6858_init_termios, .tiocmget = oti6858_tiocmget, .tiocmset = oti6858_tiocmset, + .tiocmiwait = usb_serial_generic_tiocmiwait, .read_bulk_callback = oti6858_read_bulk_callback, .read_int_callback = oti6858_read_int_callback, .write_bulk_callback = oti6858_write_bulk_callback, .write_room = oti6858_write_room, .chars_in_buffer = oti6858_chars_in_buffer, - .attach = oti6858_startup, - .release = oti6858_release, + .port_probe = oti6858_port_probe, + .port_remove = oti6858_port_remove, +}; + +static struct usb_serial_driver * const serial_drivers[] = { + &oti6858_device, NULL }; struct oti6858_private { @@ -195,7 +186,6 @@ struct oti6858_private { u8 setup_done; struct delayed_work delayed_setup_work; - wait_queue_head_t intr_wait; struct usb_serial_port *port; /* USB port with which associated */ }; @@ -208,11 +198,8 @@ static void setup_line(struct work_struct *work) unsigned long flags; int result; - dbg("%s(port = %d)", __func__, port->number); - new_setup = kmalloc(OTI6858_CTRL_PKT_SIZE, GFP_KERNEL); - if (new_setup == NULL) { - dev_err(&port->dev, "%s(): out of memory!\n", __func__); + if (!new_setup) { /* we will try again */ schedule_delayed_work(&priv->delayed_setup_work, msecs_to_jiffies(2)); @@ -262,12 +249,11 @@ static void setup_line(struct work_struct *work) priv->setup_done = 1; spin_unlock_irqrestore(&priv->lock, flags); - dbg("%s(): submitting interrupt urb", __func__); - port->interrupt_in_urb->dev = port->serial->dev; + dev_dbg(&port->dev, "%s(): submitting interrupt urb\n", __func__); result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); if (result != 0) { - dev_err(&port->dev, "%s(): usb_submit_urb() failed" - " with error %d\n", __func__, result); + dev_err(&port->dev, "%s(): usb_submit_urb() failed with error %d\n", + __func__, result); } } @@ -280,8 +266,6 @@ static void send_data(struct work_struct *work) unsigned long flags; u8 *allow; - dbg("%s(port = %d)", __func__, port->number); - spin_lock_irqsave(&priv->lock, flags); if (priv->flags.write_urb_in_use) { spin_unlock_irqrestore(&priv->lock, flags); @@ -301,11 +285,9 @@ static void send_data(struct work_struct *work) if (count != 0) { allow = kmalloc(1, GFP_KERNEL); - if (!allow) { - dev_err(&port->dev, "%s(): kmalloc failed\n", - __func__); + if (!allow) return; - } + result = usb_control_msg(port->serial->dev, usb_rcvctrlpipe(port->serial->dev, 0), OTI6858_REQ_T_CHECK_TXBUFF, @@ -319,12 +301,11 @@ static void send_data(struct work_struct *work) if (count == 0) { priv->flags.write_urb_in_use = 0; - dbg("%s(): submitting interrupt urb", __func__); - port->interrupt_in_urb->dev = port->serial->dev; + dev_dbg(&port->dev, "%s(): submitting interrupt urb\n", __func__); result = usb_submit_urb(port->interrupt_in_urb, GFP_NOIO); if (result != 0) { - dev_err(&port->dev, "%s(): usb_submit_urb() failed" - " with error %d\n", __func__, result); + dev_err(&port->dev, "%s(): usb_submit_urb() failed with error %d\n", + __func__, result); } return; } @@ -333,54 +314,49 @@ static void send_data(struct work_struct *work) port->write_urb->transfer_buffer, count, &port->lock); port->write_urb->transfer_buffer_length = count; - port->write_urb->dev = port->serial->dev; result = usb_submit_urb(port->write_urb, GFP_NOIO); if (result != 0) { - dev_err(&port->dev, "%s(): usb_submit_urb() failed" - " with error %d\n", __func__, result); + dev_err_console(port, "%s(): usb_submit_urb() failed with error %d\n", + __func__, result); priv->flags.write_urb_in_use = 0; } usb_serial_port_softint(port); } -static int oti6858_startup(struct usb_serial *serial) +static int oti6858_port_probe(struct usb_serial_port *port) { - struct usb_serial_port *port = serial->port[0]; struct oti6858_private *priv; - int i; - - for (i = 0; i < serial->num_ports; ++i) { - priv = kzalloc(sizeof(struct oti6858_private), GFP_KERNEL); - if (!priv) - break; - - spin_lock_init(&priv->lock); - init_waitqueue_head(&priv->intr_wait); -/* INIT_WORK(&priv->setup_work, setup_line, serial->port[i]); */ -/* INIT_WORK(&priv->write_work, send_data, serial->port[i]); */ - priv->port = port; - INIT_DELAYED_WORK(&priv->delayed_setup_work, setup_line); - INIT_DELAYED_WORK(&priv->delayed_write_work, send_data); - - usb_set_serial_port_data(serial->port[i], priv); - } - if (i == serial->num_ports) - return 0; - for (--i; i >= 0; --i) { - priv = usb_get_serial_port_data(serial->port[i]); - kfree(priv); - usb_set_serial_port_data(serial->port[i], NULL); - } - return -ENOMEM; + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + spin_lock_init(&priv->lock); + priv->port = port; + INIT_DELAYED_WORK(&priv->delayed_setup_work, setup_line); + INIT_DELAYED_WORK(&priv->delayed_write_work, send_data); + + usb_set_serial_port_data(port, priv); + + port->port.drain_delay = 256; /* FIXME: check the FIFO length */ + + return 0; +} + +static int oti6858_port_remove(struct usb_serial_port *port) +{ + struct oti6858_private *priv; + + priv = usb_get_serial_port_data(port); + kfree(priv); + + return 0; } static int oti6858_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count) { - dbg("%s(port = %d, count = %d)", __func__, port->number, count); - if (!count) return count; @@ -395,8 +371,6 @@ static int oti6858_write_room(struct tty_struct *tty) int room = 0; unsigned long flags; - dbg("%s(port = %d)", __func__, port->number); - spin_lock_irqsave(&port->lock, flags); room = kfifo_avail(&port->write_fifo); spin_unlock_irqrestore(&port->lock, flags); @@ -410,8 +384,6 @@ static int oti6858_chars_in_buffer(struct tty_struct *tty) int chars = 0; unsigned long flags; - dbg("%s(port = %d)", __func__, port->number); - spin_lock_irqsave(&port->lock, flags); chars = kfifo_len(&port->write_fifo); spin_unlock_irqrestore(&port->lock, flags); @@ -421,10 +393,10 @@ static int oti6858_chars_in_buffer(struct tty_struct *tty) static void oti6858_init_termios(struct tty_struct *tty) { - *(tty->termios) = tty_std_termios; - tty->termios->c_cflag = B38400 | CS8 | CREAD | HUPCL | CLOCAL; - tty->termios->c_ispeed = 38400; - tty->termios->c_ospeed = 38400; + tty->termios = tty_std_termios; + tty->termios.c_cflag = B38400 | CS8 | CREAD | HUPCL | CLOCAL; + tty->termios.c_ispeed = 38400; + tty->termios.c_ospeed = 38400; } static void oti6858_set_termios(struct tty_struct *tty, @@ -437,14 +409,7 @@ static void oti6858_set_termios(struct tty_struct *tty, __le16 divisor; int br; - dbg("%s(port = %d)", __func__, port->number); - - if (!tty) { - dbg("%s(): no tty structures", __func__); - return; - } - - cflag = tty->termios->c_cflag; + cflag = tty->termios.c_cflag; spin_lock_irqsave(&priv->lock, flags); divisor = priv->pending_setup.divisor; @@ -539,22 +504,17 @@ static void oti6858_set_termios(struct tty_struct *tty, static int oti6858_open(struct tty_struct *tty, struct usb_serial_port *port) { struct oti6858_private *priv = usb_get_serial_port_data(port); - struct ktermios tmp_termios; struct usb_serial *serial = port->serial; struct oti6858_control_pkt *buf; unsigned long flags; int result; - dbg("%s(port = %d)", __func__, port->number); - usb_clear_halt(serial->dev, port->write_urb->pipe); usb_clear_halt(serial->dev, port->read_urb->pipe); buf = kmalloc(OTI6858_CTRL_PKT_SIZE, GFP_KERNEL); - if (buf == NULL) { - dev_err(&port->dev, "%s(): out of memory!\n", __func__); + if (!buf) return -ENOMEM; - } result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), OTI6858_REQ_T_GET_STATUS, @@ -581,20 +541,19 @@ static int oti6858_open(struct tty_struct *tty, struct usb_serial_port *port) spin_unlock_irqrestore(&priv->lock, flags); kfree(buf); - dbg("%s(): submitting interrupt urb", __func__); - port->interrupt_in_urb->dev = serial->dev; + dev_dbg(&port->dev, "%s(): submitting interrupt urb\n", __func__); result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); if (result != 0) { - dev_err(&port->dev, "%s(): usb_submit_urb() failed" - " with error %d\n", __func__, result); + dev_err(&port->dev, "%s(): usb_submit_urb() failed with error %d\n", + __func__, result); oti6858_close(port); - return -EPROTO; + return result; } /* setup termios */ if (tty) - oti6858_set_termios(tty, port, &tmp_termios); - port->port.drain_delay = 256; /* FIXME: check the FIFO length */ + oti6858_set_termios(tty, port, NULL); + return 0; } @@ -603,28 +562,25 @@ static void oti6858_close(struct usb_serial_port *port) struct oti6858_private *priv = usb_get_serial_port_data(port); unsigned long flags; - dbg("%s(port = %d)", __func__, port->number); - spin_lock_irqsave(&port->lock, flags); /* clear out any remaining data in the buffer */ kfifo_reset_out(&port->write_fifo); spin_unlock_irqrestore(&port->lock, flags); - dbg("%s(): after buf_clear()", __func__); + dev_dbg(&port->dev, "%s(): after buf_clear()\n", __func__); /* cancel scheduled setup */ - cancel_delayed_work(&priv->delayed_setup_work); - cancel_delayed_work(&priv->delayed_write_work); - flush_scheduled_work(); + cancel_delayed_work_sync(&priv->delayed_setup_work); + cancel_delayed_work_sync(&priv->delayed_write_work); /* shutdown our urbs */ - dbg("%s(): shutting down urbs", __func__); + dev_dbg(&port->dev, "%s(): shutting down urbs\n", __func__); usb_kill_urb(port->write_urb); usb_kill_urb(port->read_urb); usb_kill_urb(port->interrupt_in_urb); } -static int oti6858_tiocmset(struct tty_struct *tty, struct file *file, +static int oti6858_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) { struct usb_serial_port *port = tty->driver_data; @@ -632,11 +588,8 @@ static int oti6858_tiocmset(struct tty_struct *tty, struct file *file, unsigned long flags; u8 control; - dbg("%s(port = %d, set = 0x%08x, clear = 0x%08x)", - __func__, port->number, set, clear); - - if (!usb_get_intfdata(port->serial->interface)) - return -ENODEV; + dev_dbg(&port->dev, "%s(set = 0x%08x, clear = 0x%08x)\n", + __func__, set, clear); /* FIXME: check if this is correct (active high/low) */ spin_lock_irqsave(&priv->lock, flags); @@ -657,7 +610,7 @@ static int oti6858_tiocmset(struct tty_struct *tty, struct file *file, return 0; } -static int oti6858_tiocmget(struct tty_struct *tty, struct file *file) +static int oti6858_tiocmget(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; struct oti6858_private *priv = usb_get_serial_port_data(port); @@ -665,11 +618,6 @@ static int oti6858_tiocmget(struct tty_struct *tty, struct file *file) unsigned pin_state; unsigned result = 0; - dbg("%s(port = %d)", __func__, port->number); - - if (!usb_get_intfdata(port->serial->interface)) - return -ENODEV; - spin_lock_irqsave(&priv->lock, flags); pin_state = priv->status.pin_state & PIN_MASK; spin_unlock_irqrestore(&priv->lock, flags); @@ -688,76 +636,11 @@ static int oti6858_tiocmget(struct tty_struct *tty, struct file *file) if ((pin_state & PIN_DCD) != 0) result |= TIOCM_CD; - dbg("%s() = 0x%08x", __func__, result); + dev_dbg(&port->dev, "%s() = 0x%08x\n", __func__, result); return result; } -static int wait_modem_info(struct usb_serial_port *port, unsigned int arg) -{ - struct oti6858_private *priv = usb_get_serial_port_data(port); - unsigned long flags; - unsigned int prev, status; - unsigned int changed; - - spin_lock_irqsave(&priv->lock, flags); - prev = priv->status.pin_state; - spin_unlock_irqrestore(&priv->lock, flags); - - while (1) { - wait_event_interruptible(priv->intr_wait, - priv->status.pin_state != prev); - if (signal_pending(current)) - return -ERESTARTSYS; - - spin_lock_irqsave(&priv->lock, flags); - status = priv->status.pin_state & PIN_MASK; - spin_unlock_irqrestore(&priv->lock, flags); - - changed = prev ^ status; - /* FIXME: check if this is correct (active high/low) */ - if (((arg & TIOCM_RNG) && (changed & PIN_RI)) || - ((arg & TIOCM_DSR) && (changed & PIN_DSR)) || - ((arg & TIOCM_CD) && (changed & PIN_DCD)) || - ((arg & TIOCM_CTS) && (changed & PIN_CTS))) - return 0; - prev = status; - } - - /* NOTREACHED */ - return 0; -} - -static int oti6858_ioctl(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct usb_serial_port *port = tty->driver_data; - - dbg("%s(port = %d, cmd = 0x%04x, arg = 0x%08lx)", - __func__, port->number, cmd, arg); - - switch (cmd) { - case TIOCMIWAIT: - dbg("%s(): TIOCMIWAIT", __func__); - return wait_modem_info(port, arg); - default: - dbg("%s(): 0x%04x not supported", __func__, cmd); - break; - } - return -ENOIOCTLCMD; -} - - -static void oti6858_release(struct usb_serial *serial) -{ - int i; - - dbg("%s()", __func__); - - for (i = 0; i < serial->num_ports; ++i) - kfree(usb_get_serial_port_data(serial->port[i])); -} - static void oti6858_read_int_callback(struct urb *urb) { struct usb_serial_port *port = urb->context; @@ -765,9 +648,6 @@ static void oti6858_read_int_callback(struct urb *urb) int transient = 0, can_recv = 0, resubmit = 1; int status = urb->status; - dbg("%s(port = %d, status = %d)", - __func__, port->number, status); - switch (status) { case 0: /* success */ @@ -776,12 +656,12 @@ static void oti6858_read_int_callback(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s(): urb shutting down with status: %d", - __func__, status); + dev_dbg(&urb->dev->dev, "%s(): urb shutting down with status: %d\n", + __func__, status); return; default: - dbg("%s(): nonzero urb status received: %d", - __func__, status); + dev_dbg(&urb->dev->dev, "%s(): nonzero urb status received: %d\n", + __func__, status); break; } @@ -797,8 +677,7 @@ static void oti6858_read_int_callback(struct urb *urb) priv->transient = 4; priv->setup_done = 0; resubmit = 0; - dbg("%s(): scheduling setup_line()", - __func__); + dev_dbg(&port->dev, "%s(): scheduling setup_line()\n", __func__); schedule_delayed_work(&priv->delayed_setup_work, 0); } } @@ -812,16 +691,28 @@ static void oti6858_read_int_callback(struct urb *urb) priv->transient = 4; priv->setup_done = 0; resubmit = 0; - dbg("%s(): scheduling setup_line()", - __func__); + dev_dbg(&port->dev, "%s(): scheduling setup_line()\n", __func__); schedule_delayed_work(&priv->delayed_setup_work, 0); } } } if (!priv->transient) { - if (xs->pin_state != priv->status.pin_state) - wake_up_interruptible(&priv->intr_wait); + u8 delta = xs->pin_state ^ priv->status.pin_state; + + if (delta & PIN_MSR_MASK) { + if (delta & PIN_CTS) + port->icount.cts++; + if (delta & PIN_DSR) + port->icount.dsr++; + if (delta & PIN_RI) + port->icount.rng++; + if (delta & PIN_DCD) + port->icount.dcd++; + + wake_up_interruptible(&port->port.delta_msr_wait); + } + memcpy(&priv->status, xs, OTI6858_CTRL_PKT_SIZE); } @@ -837,7 +728,6 @@ static void oti6858_read_int_callback(struct urb *urb) if (can_recv) { int result; - port->read_urb->dev = port->serial->dev; result = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (result != 0) { priv->flags.read_urb_in_use = 0; @@ -865,8 +755,7 @@ static void oti6858_read_int_callback(struct urb *urb) if (resubmit) { int result; -/* dbg("%s(): submitting interrupt urb", __func__); */ - urb->dev = port->serial->dev; +/* dev_dbg(&urb->dev->dev, "%s(): submitting interrupt urb\n", __func__); */ result = usb_submit_urb(urb, GFP_ATOMIC); if (result != 0) { dev_err(&urb->dev->dev, @@ -880,45 +769,26 @@ static void oti6858_read_bulk_callback(struct urb *urb) { struct usb_serial_port *port = urb->context; struct oti6858_private *priv = usb_get_serial_port_data(port); - struct tty_struct *tty; unsigned char *data = urb->transfer_buffer; unsigned long flags; int status = urb->status; int result; - dbg("%s(port = %d, status = %d)", - __func__, port->number, status); - spin_lock_irqsave(&priv->lock, flags); priv->flags.read_urb_in_use = 0; spin_unlock_irqrestore(&priv->lock, flags); if (status != 0) { - /* - if (status == -EPROTO) { - * PL2303 mysteriously fails with -EPROTO reschedule - the read * - dbg("%s - caught -EPROTO, resubmitting the urb", - __func__); - result = usb_submit_urb(urb, GFP_ATOMIC); - if (result) - dev_err(&urb->dev->dev, "%s - failed resubmitting read urb, error %d\n", __func__, result); - return; - } - */ - dbg("%s(): unable to handle the error, exiting", __func__); + dev_dbg(&urb->dev->dev, "%s(): unable to handle the error, exiting\n", __func__); return; } - tty = tty_port_tty_get(&port->port); - if (tty != NULL && urb->actual_length > 0) { - tty_insert_flip_string(tty, data, urb->actual_length); - tty_flip_buffer_push(tty); + if (urb->actual_length > 0) { + tty_insert_flip_string(&port->port, data, urb->actual_length); + tty_flip_buffer_push(&port->port); } - tty_kref_put(tty); /* schedule the interrupt urb */ - port->interrupt_in_urb->dev = port->serial->dev; result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC); if (result != 0 && result != -EPERM) { dev_err(&port->dev, "%s(): usb_submit_urb() failed," @@ -933,9 +803,6 @@ static void oti6858_write_bulk_callback(struct urb *urb) int status = urb->status; int result; - dbg("%s(port = %d, status = %d)", - __func__, port->number, status); - switch (status) { case 0: /* success */ @@ -944,21 +811,18 @@ static void oti6858_write_bulk_callback(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s(): urb shutting down with status: %d", - __func__, status); + dev_dbg(&urb->dev->dev, "%s(): urb shutting down with status: %d\n", __func__, status); priv->flags.write_urb_in_use = 0; return; default: /* error in the urb, so we have to resubmit it */ - dbg("%s(): nonzero write bulk status received: %d", - __func__, status); - dbg("%s(): overflow in write", __func__); + dev_dbg(&urb->dev->dev, "%s(): nonzero write bulk status received: %d\n", __func__, status); + dev_dbg(&urb->dev->dev, "%s(): overflow in write\n", __func__); port->write_urb->transfer_buffer_length = 1; - port->write_urb->dev = port->serial->dev; result = usb_submit_urb(port->write_urb, GFP_ATOMIC); if (result) { - dev_err(&port->dev, "%s(): usb_submit_urb() failed," + dev_err_console(port, "%s(): usb_submit_urb() failed," " error %d\n", __func__, result); } else { return; @@ -968,8 +832,7 @@ static void oti6858_write_bulk_callback(struct urb *urb) priv->flags.write_urb_in_use = 0; /* schedule the interrupt urb if we are still open */ - port->interrupt_in_urb->dev = port->serial->dev; - dbg("%s(): submitting interrupt urb", __func__); + dev_dbg(&port->dev, "%s(): submitting interrupt urb\n", __func__); result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC); if (result != 0) { dev_err(&port->dev, "%s(): failed submitting int urb," @@ -977,35 +840,8 @@ static void oti6858_write_bulk_callback(struct urb *urb) } } -/* module description and (de)initialization */ - -static int __init oti6858_init(void) -{ - int retval; - - retval = usb_serial_register(&oti6858_device); - if (retval == 0) { - retval = usb_register(&oti6858_driver); - if (retval) - usb_serial_deregister(&oti6858_device); - } - return retval; -} - -static void __exit oti6858_exit(void) -{ - usb_deregister(&oti6858_driver); - usb_serial_deregister(&oti6858_device); -} - -module_init(oti6858_init); -module_exit(oti6858_exit); +module_usb_serial_driver(serial_drivers, id_table); MODULE_DESCRIPTION(OTI6858_DESCRIPTION); MODULE_AUTHOR(OTI6858_AUTHOR); -MODULE_VERSION(OTI6858_VERSION); MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "enable debug output"); - diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 8ae4c6cbc38..b3d5a35c0d4 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -12,12 +12,10 @@ * * See Documentation/usb/usb-serial.txt for more information on using this * driver - * */ #include <linux/kernel.h> #include <linux/errno.h> -#include <linux/init.h> #include <linux/slab.h> #include <linux/tty.h> #include <linux/tty_driver.h> @@ -29,16 +27,12 @@ #include <linux/uaccess.h> #include <linux/usb.h> #include <linux/usb/serial.h> +#include <asm/unaligned.h> #include "pl2303.h" -/* - * Version Information - */ -#define DRIVER_DESC "Prolific PL2303 USB to serial adaptor driver" - -static int debug; -#define PL2303_CLOSING_WAIT (30*HZ) +#define PL2303_QUIRK_UART_STATE_IDX0 BIT(0) +#define PL2303_QUIRK_LEGACY BIT(1) static const struct usb_device_id id_table[] = { { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) }, @@ -50,6 +44,7 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MMX) }, { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GPRS) }, { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_HCR331) }, + { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MOTOROLA) }, { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) }, { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) }, { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) }, @@ -66,9 +61,12 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(SITECOM_VENDOR_ID, SITECOM_PRODUCT_ID) }, { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_ID) }, { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_ID) }, - { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_SX1) }, - { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65) }, - { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X75) }, + { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_SX1), + .driver_info = PL2303_QUIRK_UART_STATE_IDX0 }, + { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65), + .driver_info = PL2303_QUIRK_UART_STATE_IDX0 }, + { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X75), + .driver_info = PL2303_QUIRK_UART_STATE_IDX0 }, { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_EF81) }, { USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_ID_S81) }, /* Benq/Siemens S81 */ { USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) }, @@ -85,27 +83,20 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(YCCABLE_VENDOR_ID, YCCABLE_PRODUCT_ID) }, { USB_DEVICE(SUPERIAL_VENDOR_ID, SUPERIAL_PRODUCT_ID) }, { USB_DEVICE(HP_VENDOR_ID, HP_LD220_PRODUCT_ID) }, + { USB_DEVICE(HP_VENDOR_ID, HP_LD960_PRODUCT_ID) }, + { USB_DEVICE(HP_VENDOR_ID, HP_LCM220_PRODUCT_ID) }, + { USB_DEVICE(HP_VENDOR_ID, HP_LCM960_PRODUCT_ID) }, { USB_DEVICE(CRESSI_VENDOR_ID, CRESSI_EDY_PRODUCT_ID) }, { USB_DEVICE(ZEAGLE_VENDOR_ID, ZEAGLE_N2ITION3_PRODUCT_ID) }, { USB_DEVICE(SONY_VENDOR_ID, SONY_QN3USB_PRODUCT_ID) }, { USB_DEVICE(SANWA_VENDOR_ID, SANWA_PRODUCT_ID) }, { USB_DEVICE(ADLINK_VENDOR_ID, ADLINK_ND6530_PRODUCT_ID) }, + { USB_DEVICE(SMART_VENDOR_ID, SMART_PRODUCT_ID) }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, id_table); -static struct usb_driver pl2303_driver = { - .name = "pl2303", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, - .suspend = usb_serial_suspend, - .resume = usb_serial_resume, - .no_dynamic_id = 1, - .supports_autosuspend = 1, -}; - #define SET_LINE_REQUEST_TYPE 0x21 #define SET_LINE_REQUEST 0x20 @@ -128,7 +119,8 @@ static struct usb_driver pl2303_driver = { #define VENDOR_READ_REQUEST_TYPE 0xc0 #define VENDOR_READ_REQUEST 0x01 -#define UART_STATE 0x08 +#define UART_STATE_INDEX 8 +#define UART_STATE_MSR_MASK 0x8b #define UART_STATE_TRANSIENT_MASK 0x74 #define UART_DCD 0x01 #define UART_DSR 0x02 @@ -141,300 +133,462 @@ static struct usb_driver pl2303_driver = { enum pl2303_type { - type_0, /* don't know the difference between type 0 and */ - type_1, /* type 1, until someone from prolific tells us... */ - HX, /* HX version of the pl2303 chip */ + TYPE_01, /* Type 0 and 1 (difference unknown) */ + TYPE_HX, /* HX version of the pl2303 chip */ + TYPE_COUNT +}; + +struct pl2303_type_data { + speed_t max_baud_rate; + unsigned long quirks; +}; + +struct pl2303_serial_private { + const struct pl2303_type_data *type; + unsigned long quirks; }; struct pl2303_private { spinlock_t lock; - wait_queue_head_t delta_msr_wait; u8 line_control; u8 line_status; - enum pl2303_type type; + + u8 line_settings[7]; }; -static int pl2303_vendor_read(__u16 value, __u16 index, - struct usb_serial *serial, unsigned char *buf) +static const struct pl2303_type_data pl2303_type_data[TYPE_COUNT] = { + [TYPE_01] = { + .max_baud_rate = 1228800, + .quirks = PL2303_QUIRK_LEGACY, + }, +}; + +static int pl2303_vendor_read(struct usb_serial *serial, u16 value, + unsigned char buf[1]) { - int res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), + struct device *dev = &serial->interface->dev; + int res; + + res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), VENDOR_READ_REQUEST, VENDOR_READ_REQUEST_TYPE, - value, index, buf, 1, 100); - dbg("0x%x:0x%x:0x%x:0x%x %d - %x", VENDOR_READ_REQUEST_TYPE, - VENDOR_READ_REQUEST, value, index, res, buf[0]); - return res; + value, 0, buf, 1, 100); + if (res != 1) { + dev_err(dev, "%s - failed to read [%04x]: %d\n", __func__, + value, res); + if (res >= 0) + res = -EIO; + + return res; + } + + dev_dbg(dev, "%s - [%04x] = %02x\n", __func__, value, buf[0]); + + return 0; } -static int pl2303_vendor_write(__u16 value, __u16 index, - struct usb_serial *serial) +static int pl2303_vendor_write(struct usb_serial *serial, u16 value, u16 index) { - int res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + struct device *dev = &serial->interface->dev; + int res; + + dev_dbg(dev, "%s - [%04x] = %02x\n", __func__, value, index); + + res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE, value, index, NULL, 0, 100); - dbg("0x%x:0x%x:0x%x:0x%x %d", VENDOR_WRITE_REQUEST_TYPE, - VENDOR_WRITE_REQUEST, value, index, res); - return res; + if (res) { + dev_err(dev, "%s - failed to write [%04x]: %d\n", __func__, + value, res); + return res; + } + + return 0; +} + +static int pl2303_probe(struct usb_serial *serial, + const struct usb_device_id *id) +{ + usb_set_serial_data(serial, (void *)id->driver_info); + + return 0; } static int pl2303_startup(struct usb_serial *serial) { - struct pl2303_private *priv; - enum pl2303_type type = type_0; + struct pl2303_serial_private *spriv; + enum pl2303_type type = TYPE_01; unsigned char *buf; - int i; - buf = kmalloc(10, GFP_KERNEL); - if (buf == NULL) + spriv = kzalloc(sizeof(*spriv), GFP_KERNEL); + if (!spriv) + return -ENOMEM; + + buf = kmalloc(1, GFP_KERNEL); + if (!buf) { + kfree(spriv); return -ENOMEM; + } if (serial->dev->descriptor.bDeviceClass == 0x02) - type = type_0; + type = TYPE_01; /* type 0 */ else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40) - type = HX; + type = TYPE_HX; else if (serial->dev->descriptor.bDeviceClass == 0x00) - type = type_1; + type = TYPE_01; /* type 1 */ else if (serial->dev->descriptor.bDeviceClass == 0xFF) - type = type_1; - dbg("device type: %d", type); - - for (i = 0; i < serial->num_ports; ++i) { - priv = kzalloc(sizeof(struct pl2303_private), GFP_KERNEL); - if (!priv) - goto cleanup; - spin_lock_init(&priv->lock); - init_waitqueue_head(&priv->delta_msr_wait); - priv->type = type; - usb_set_serial_port_data(serial->port[i], priv); - } - - pl2303_vendor_read(0x8484, 0, serial, buf); - pl2303_vendor_write(0x0404, 0, serial); - pl2303_vendor_read(0x8484, 0, serial, buf); - pl2303_vendor_read(0x8383, 0, serial, buf); - pl2303_vendor_read(0x8484, 0, serial, buf); - pl2303_vendor_write(0x0404, 1, serial); - pl2303_vendor_read(0x8484, 0, serial, buf); - pl2303_vendor_read(0x8383, 0, serial, buf); - pl2303_vendor_write(0, 1, serial); - pl2303_vendor_write(1, 0, serial); - if (type == HX) - pl2303_vendor_write(2, 0x44, serial); + type = TYPE_01; /* type 1 */ + dev_dbg(&serial->interface->dev, "device type: %d\n", type); + + spriv->type = &pl2303_type_data[type]; + spriv->quirks = (unsigned long)usb_get_serial_data(serial); + spriv->quirks |= spriv->type->quirks; + + usb_set_serial_data(serial, spriv); + + pl2303_vendor_read(serial, 0x8484, buf); + pl2303_vendor_write(serial, 0x0404, 0); + pl2303_vendor_read(serial, 0x8484, buf); + pl2303_vendor_read(serial, 0x8383, buf); + pl2303_vendor_read(serial, 0x8484, buf); + pl2303_vendor_write(serial, 0x0404, 1); + pl2303_vendor_read(serial, 0x8484, buf); + pl2303_vendor_read(serial, 0x8383, buf); + pl2303_vendor_write(serial, 0, 1); + pl2303_vendor_write(serial, 1, 0); + if (spriv->quirks & PL2303_QUIRK_LEGACY) + pl2303_vendor_write(serial, 2, 0x24); else - pl2303_vendor_write(2, 0x24, serial); + pl2303_vendor_write(serial, 2, 0x44); kfree(buf); + return 0; +} -cleanup: - kfree(buf); - for (--i; i >= 0; --i) { - priv = usb_get_serial_port_data(serial->port[i]); - kfree(priv); - usb_set_serial_port_data(serial->port[i], NULL); - } - return -ENOMEM; +static void pl2303_release(struct usb_serial *serial) +{ + struct pl2303_serial_private *spriv = usb_get_serial_data(serial); + + kfree(spriv); } -static int set_control_lines(struct usb_device *dev, u8 value) +static int pl2303_port_probe(struct usb_serial_port *port) { + struct pl2303_private *priv; + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + spin_lock_init(&priv->lock); + + usb_set_serial_port_data(port, priv); + + port->port.drain_delay = 256; + + return 0; +} + +static int pl2303_port_remove(struct usb_serial_port *port) +{ + struct pl2303_private *priv = usb_get_serial_port_data(port); + + kfree(priv); + + return 0; +} + +static int pl2303_set_control_lines(struct usb_serial_port *port, u8 value) +{ + struct usb_device *dev = port->serial->dev; int retval; + dev_dbg(&port->dev, "%s - %02x\n", __func__, value); + retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE, value, 0, NULL, 0, 100); - dbg("%s - value = %d, retval = %d", __func__, value, retval); + if (retval) + dev_err(&port->dev, "%s - failed: %d\n", __func__, retval); + return retval; } +/* + * Returns the nearest supported baud rate that can be set directly without + * using divisors. + */ +static speed_t pl2303_get_supported_baud_rate(speed_t baud) +{ + static const speed_t baud_sup[] = { + 75, 150, 300, 600, 1200, 1800, 2400, 3600, 4800, 7200, 9600, + 14400, 19200, 28800, 38400, 57600, 115200, 230400, 460800, + 614400, 921600, 1228800, 2457600, 3000000, 6000000 + }; + + unsigned i; + + for (i = 0; i < ARRAY_SIZE(baud_sup); ++i) { + if (baud_sup[i] > baud) + break; + } + + if (i == ARRAY_SIZE(baud_sup)) + baud = baud_sup[i - 1]; + else if (i > 0 && (baud_sup[i] - baud) > (baud - baud_sup[i - 1])) + baud = baud_sup[i - 1]; + else + baud = baud_sup[i]; + + return baud; +} + +/* + * NOTE: If unsupported baud rates are set directly, the PL2303 seems to + * use 9600 baud. + */ +static speed_t pl2303_encode_baud_rate_direct(unsigned char buf[4], + speed_t baud) +{ + put_unaligned_le32(baud, buf); + + return baud; +} + +static speed_t pl2303_encode_baud_rate_divisor(unsigned char buf[4], + speed_t baud) +{ + unsigned int tmp; + + /* + * Apparently the formula is: + * baudrate = 12M * 32 / (2^buf[1]) / buf[0] + */ + tmp = 12000000 * 32 / baud; + buf[3] = 0x80; + buf[2] = 0; + buf[1] = (tmp >= 256); + while (tmp >= 256) { + tmp >>= 2; + buf[1] <<= 1; + } + buf[0] = tmp; + + return baud; +} + +static void pl2303_encode_baud_rate(struct tty_struct *tty, + struct usb_serial_port *port, + u8 buf[4]) +{ + struct usb_serial *serial = port->serial; + struct pl2303_serial_private *spriv = usb_get_serial_data(serial); + speed_t baud_sup; + speed_t baud; + + baud = tty_get_baud_rate(tty); + dev_dbg(&port->dev, "baud requested = %u\n", baud); + if (!baud) + return; + + if (spriv->type->max_baud_rate) + baud = min_t(speed_t, baud, spriv->type->max_baud_rate); + /* + * Set baud rate to nearest supported value. + * + * NOTE: Baud rate 500k can only be set using divisors. + */ + baud_sup = pl2303_get_supported_baud_rate(baud); + + if (baud == 500000) + baud = pl2303_encode_baud_rate_divisor(buf, baud); + else + baud = pl2303_encode_baud_rate_direct(buf, baud_sup); + + /* Save resulting baud rate */ + tty_encode_baud_rate(tty, baud, baud); + dev_dbg(&port->dev, "baud set = %u\n", baud); +} + +static int pl2303_get_line_request(struct usb_serial_port *port, + unsigned char buf[7]) +{ + struct usb_device *udev = port->serial->dev; + int ret; + + ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE, + 0, 0, buf, 7, 100); + if (ret != 7) { + dev_err(&port->dev, "%s - failed: %d\n", __func__, ret); + + if (ret > 0) + ret = -EIO; + + return ret; + } + + dev_dbg(&port->dev, "%s - %7ph\n", __func__, buf); + + return 0; +} + +static int pl2303_set_line_request(struct usb_serial_port *port, + unsigned char buf[7]) +{ + struct usb_device *udev = port->serial->dev; + int ret; + + ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE, + 0, 0, buf, 7, 100); + if (ret != 7) { + dev_err(&port->dev, "%s - failed: %d\n", __func__, ret); + + if (ret > 0) + ret = -EIO; + + return ret; + } + + dev_dbg(&port->dev, "%s - %7ph\n", __func__, buf); + + return 0; +} + static void pl2303_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios) { struct usb_serial *serial = port->serial; + struct pl2303_serial_private *spriv = usb_get_serial_data(serial); struct pl2303_private *priv = usb_get_serial_port_data(port); unsigned long flags; - unsigned int cflag; unsigned char *buf; - int baud; - int i; + int ret; u8 control; - const int baud_sup[] = { 75, 150, 300, 600, 1200, 1800, 2400, 3600, - 4800, 7200, 9600, 14400, 19200, 28800, 38400, - 57600, 115200, 230400, 460800, 614400, - 921600, 1228800, 2457600, 3000000, 6000000 }; - int baud_floor, baud_ceil; - int k; - - dbg("%s - port %d", __func__, port->number); - - /* The PL2303 is reported to lose bytes if you change - serial settings even to the same values as before. Thus - we actually need to filter in this specific case */ - if (!tty_termios_hw_change(tty->termios, old_termios)) + if (old_termios && !tty_termios_hw_change(&tty->termios, old_termios)) return; - cflag = tty->termios->c_cflag; - buf = kzalloc(7, GFP_KERNEL); if (!buf) { - dev_err(&port->dev, "%s - out of memory.\n", __func__); /* Report back no change occurred */ - *tty->termios = *old_termios; + if (old_termios) + tty->termios = *old_termios; return; } - i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), - GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE, - 0, 0, buf, 7, 100); - dbg("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i, - buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]); + pl2303_get_line_request(port, buf); - if (cflag & CSIZE) { - switch (cflag & CSIZE) { - case CS5: - buf[6] = 5; - break; - case CS6: - buf[6] = 6; - break; - case CS7: - buf[6] = 7; - break; - default: - case CS8: - buf[6] = 8; - break; - } - dbg("%s - data bits = %d", __func__, buf[6]); + switch (C_CSIZE(tty)) { + case CS5: + buf[6] = 5; + break; + case CS6: + buf[6] = 6; + break; + case CS7: + buf[6] = 7; + break; + default: + case CS8: + buf[6] = 8; } + dev_dbg(&port->dev, "data bits = %d\n", buf[6]); /* For reference buf[0]:buf[3] baud rate value */ - /* NOTE: Only the values defined in baud_sup are supported ! - * => if unsupported values are set, the PL2303 seems to use - * 9600 baud (at least my PL2303X always does) - */ - baud = tty_get_baud_rate(tty); - dbg("%s - baud requested = %d", __func__, baud); - if (baud) { - /* Set baudrate to nearest supported value */ - for (k=0; k<ARRAY_SIZE(baud_sup); k++) { - if (baud_sup[k] / baud) { - baud_ceil = baud_sup[k]; - if (k==0) { - baud = baud_ceil; - } else { - baud_floor = baud_sup[k-1]; - if ((baud_ceil % baud) - > (baud % baud_floor)) - baud = baud_floor; - else - baud = baud_ceil; - } - break; - } - } - if (baud > 1228800) { - /* type_0, type_1 only support up to 1228800 baud */ - if (priv->type != HX) - baud = 1228800; - else if (baud > 6000000) - baud = 6000000; - } - dbg("%s - baud set = %d", __func__, baud); - buf[0] = baud & 0xff; - buf[1] = (baud >> 8) & 0xff; - buf[2] = (baud >> 16) & 0xff; - buf[3] = (baud >> 24) & 0xff; - } + pl2303_encode_baud_rate(tty, port, &buf[0]); /* For reference buf[4]=0 is 1 stop bits */ /* For reference buf[4]=1 is 1.5 stop bits */ /* For reference buf[4]=2 is 2 stop bits */ - if (cflag & CSTOPB) { - /* NOTE: Comply with "real" UARTs / RS232: + if (C_CSTOPB(tty)) { + /* + * NOTE: Comply with "real" UARTs / RS232: * use 1.5 instead of 2 stop bits with 5 data bits */ - if ((cflag & CSIZE) == CS5) { + if (C_CSIZE(tty) == CS5) { buf[4] = 1; - dbg("%s - stop bits = 1.5", __func__); + dev_dbg(&port->dev, "stop bits = 1.5\n"); } else { buf[4] = 2; - dbg("%s - stop bits = 2", __func__); + dev_dbg(&port->dev, "stop bits = 2\n"); } } else { buf[4] = 0; - dbg("%s - stop bits = 1", __func__); + dev_dbg(&port->dev, "stop bits = 1\n"); } - if (cflag & PARENB) { + if (C_PARENB(tty)) { /* For reference buf[5]=0 is none parity */ /* For reference buf[5]=1 is odd parity */ /* For reference buf[5]=2 is even parity */ /* For reference buf[5]=3 is mark parity */ /* For reference buf[5]=4 is space parity */ - if (cflag & PARODD) { - if (cflag & CMSPAR) { + if (C_PARODD(tty)) { + if (C_CMSPAR(tty)) { buf[5] = 3; - dbg("%s - parity = mark", __func__); + dev_dbg(&port->dev, "parity = mark\n"); } else { buf[5] = 1; - dbg("%s - parity = odd", __func__); + dev_dbg(&port->dev, "parity = odd\n"); } } else { - if (cflag & CMSPAR) { + if (C_CMSPAR(tty)) { buf[5] = 4; - dbg("%s - parity = space", __func__); + dev_dbg(&port->dev, "parity = space\n"); } else { buf[5] = 2; - dbg("%s - parity = even", __func__); + dev_dbg(&port->dev, "parity = even\n"); } } } else { buf[5] = 0; - dbg("%s - parity = none", __func__); + dev_dbg(&port->dev, "parity = none\n"); } - i = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE, - 0, 0, buf, 7, 100); - dbg("0x21:0x20:0:0 %d", i); + /* + * Some PL2303 are known to lose bytes if you change serial settings + * even to the same values as before. Thus we actually need to filter + * in this specific case. + * + * Note that the tty_termios_hw_change check above is not sufficient + * as a previously requested baud rate may differ from the one + * actually used (and stored in old_termios). + * + * NOTE: No additional locking needed for line_settings as it is + * only used in set_termios, which is serialised against itself. + */ + if (!old_termios || memcmp(buf, priv->line_settings, 7)) { + ret = pl2303_set_line_request(port, buf); + if (!ret) + memcpy(priv->line_settings, buf, 7); + } /* change control lines if we are switching to or from B0 */ spin_lock_irqsave(&priv->lock, flags); control = priv->line_control; - if ((cflag & CBAUD) == B0) + if (C_BAUD(tty) == B0) priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS); - else + else if (old_termios && (old_termios->c_cflag & CBAUD) == B0) priv->line_control |= (CONTROL_DTR | CONTROL_RTS); if (control != priv->line_control) { control = priv->line_control; spin_unlock_irqrestore(&priv->lock, flags); - set_control_lines(serial->dev, control); + pl2303_set_control_lines(port, control); } else { spin_unlock_irqrestore(&priv->lock, flags); } - buf[0] = buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = buf[6] = 0; - - i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), - GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE, - 0, 0, buf, 7, 100); - dbg("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i, - buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]); - - if (cflag & CRTSCTS) { - if (priv->type == HX) - pl2303_vendor_write(0x0, 0x61, serial); + if (C_CRTSCTS(tty)) { + if (spriv->quirks & PL2303_QUIRK_LEGACY) + pl2303_vendor_write(serial, 0x0, 0x41); else - pl2303_vendor_write(0x0, 0x41, serial); + pl2303_vendor_write(serial, 0x0, 0x61); } else { - pl2303_vendor_write(0x0, 0x0, serial); + pl2303_vendor_write(serial, 0x0, 0x0); } - /* Save resulting baud rate */ - if (baud) - tty_encode_baud_rate(tty, baud, baud); - kfree(buf); } @@ -445,75 +599,65 @@ static void pl2303_dtr_rts(struct usb_serial_port *port, int on) u8 control; spin_lock_irqsave(&priv->lock, flags); - /* Change DTR and RTS */ if (on) priv->line_control |= (CONTROL_DTR | CONTROL_RTS); else priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS); control = priv->line_control; spin_unlock_irqrestore(&priv->lock, flags); - set_control_lines(port->serial->dev, control); + + pl2303_set_control_lines(port, control); } static void pl2303_close(struct usb_serial_port *port) { - dbg("%s - port %d", __func__, port->number); - usb_serial_generic_close(port); usb_kill_urb(port->interrupt_in_urb); } static int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port) { - struct ktermios tmp_termios; struct usb_serial *serial = port->serial; - struct pl2303_private *priv = usb_get_serial_port_data(port); + struct pl2303_serial_private *spriv = usb_get_serial_data(serial); int result; - dbg("%s - port %d", __func__, port->number); - - if (priv->type != HX) { + if (spriv->quirks & PL2303_QUIRK_LEGACY) { usb_clear_halt(serial->dev, port->write_urb->pipe); usb_clear_halt(serial->dev, port->read_urb->pipe); } else { /* reset upstream data pipes */ - pl2303_vendor_write(8, 0, serial); - pl2303_vendor_write(9, 0, serial); + pl2303_vendor_write(serial, 8, 0); + pl2303_vendor_write(serial, 9, 0); } /* Setup termios */ if (tty) - pl2303_set_termios(tty, port, &tmp_termios); + pl2303_set_termios(tty, port, NULL); - dbg("%s - submitting read urb", __func__); - result = usb_serial_generic_submit_read_urb(port, GFP_KERNEL); + result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); if (result) { - pl2303_close(port); - return -EPROTO; + dev_err(&port->dev, "failed to submit interrupt urb: %d\n", + result); + return result; } - dbg("%s - submitting interrupt urb", __func__); - result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); + result = usb_serial_generic_open(tty, port); if (result) { - dev_err(&port->dev, "%s - failed submitting interrupt urb," - " error %d\n", __func__, result); - pl2303_close(port); - return -EPROTO; + usb_kill_urb(port->interrupt_in_urb); + return result; } - port->port.drain_delay = 256; + return 0; } -static int pl2303_tiocmset(struct tty_struct *tty, struct file *file, +static int pl2303_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) { struct usb_serial_port *port = tty->driver_data; struct pl2303_private *priv = usb_get_serial_port_data(port); unsigned long flags; u8 control; - - if (!usb_get_intfdata(port->serial->interface)) - return -ENODEV; + int ret; spin_lock_irqsave(&priv->lock, flags); if (set & TIOCM_RTS) @@ -527,10 +671,14 @@ static int pl2303_tiocmset(struct tty_struct *tty, struct file *file, control = priv->line_control; spin_unlock_irqrestore(&priv->lock, flags); - return set_control_lines(port->serial->dev, control); + ret = pl2303_set_control_lines(port, control); + if (ret) + return usb_translate_errors(ret); + + return 0; } -static int pl2303_tiocmget(struct tty_struct *tty, struct file *file) +static int pl2303_tiocmget(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; struct pl2303_private *priv = usb_get_serial_port_data(port); @@ -539,11 +687,6 @@ static int pl2303_tiocmget(struct tty_struct *tty, struct file *file) unsigned int status; unsigned int result; - dbg("%s (%d)", __func__, port->number); - - if (!usb_get_intfdata(port->serial->interface)) - return -ENODEV; - spin_lock_irqsave(&priv->lock, flags); mcr = priv->line_control; status = priv->line_status; @@ -556,7 +699,7 @@ static int pl2303_tiocmget(struct tty_struct *tty, struct file *file) | ((status & UART_RING) ? TIOCM_RI : 0) | ((status & UART_DCD) ? TIOCM_CD : 0); - dbg("%s - result = %x", __func__, result); + dev_dbg(&port->dev, "%s - result = %x\n", __func__, result); return result; } @@ -564,74 +707,35 @@ static int pl2303_tiocmget(struct tty_struct *tty, struct file *file) static int pl2303_carrier_raised(struct usb_serial_port *port) { struct pl2303_private *priv = usb_get_serial_port_data(port); + if (priv->line_status & UART_DCD) return 1; - return 0; -} - -static int wait_modem_info(struct usb_serial_port *port, unsigned int arg) -{ - struct pl2303_private *priv = usb_get_serial_port_data(port); - unsigned long flags; - unsigned int prevstatus; - unsigned int status; - unsigned int changed; - - spin_lock_irqsave(&priv->lock, flags); - prevstatus = priv->line_status; - spin_unlock_irqrestore(&priv->lock, flags); - - while (1) { - interruptible_sleep_on(&priv->delta_msr_wait); - /* see if a signal did it */ - if (signal_pending(current)) - return -ERESTARTSYS; - - spin_lock_irqsave(&priv->lock, flags); - status = priv->line_status; - spin_unlock_irqrestore(&priv->lock, flags); - - changed = prevstatus ^ status; - if (((arg & TIOCM_RNG) && (changed & UART_RING)) || - ((arg & TIOCM_DSR) && (changed & UART_DSR)) || - ((arg & TIOCM_CD) && (changed & UART_DCD)) || - ((arg & TIOCM_CTS) && (changed & UART_CTS))) { - return 0; - } - prevstatus = status; - } - /* NOTREACHED */ return 0; } -static int pl2303_ioctl(struct tty_struct *tty, struct file *file, +static int pl2303_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { struct serial_struct ser; struct usb_serial_port *port = tty->driver_data; - dbg("%s (%d) cmd = 0x%04x", __func__, port->number, cmd); switch (cmd) { case TIOCGSERIAL: memset(&ser, 0, sizeof ser); ser.type = PORT_16654; - ser.line = port->serial->minor; - ser.port = port->number; + ser.line = port->minor; + ser.port = port->port_number; ser.baud_base = 460800; if (copy_to_user((void __user *)arg, &ser, sizeof ser)) return -EFAULT; return 0; - - case TIOCMIWAIT: - dbg("%s (%d) TIOCMIWAIT", __func__, port->number); - return wait_modem_info(port, arg); default: - dbg("%s not supported = 0x%04x", __func__, cmd); break; } + return -ENOIOCTLCMD; } @@ -642,70 +746,70 @@ static void pl2303_break_ctl(struct tty_struct *tty, int break_state) u16 state; int result; - dbg("%s - port %d", __func__, port->number); - if (break_state == 0) state = BREAK_OFF; else state = BREAK_ON; - dbg("%s - turning break %s", __func__, + + dev_dbg(&port->dev, "%s - turning break %s\n", __func__, state == BREAK_OFF ? "off" : "on"); result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), BREAK_REQUEST, BREAK_REQUEST_TYPE, state, 0, NULL, 0, 100); if (result) - dbg("%s - error sending break = %d", __func__, result); -} - -static void pl2303_release(struct usb_serial *serial) -{ - int i; - struct pl2303_private *priv; - - dbg("%s", __func__); - - for (i = 0; i < serial->num_ports; ++i) { - priv = usb_get_serial_port_data(serial->port[i]); - kfree(priv); - } + dev_err(&port->dev, "error sending break = %d\n", result); } static void pl2303_update_line_status(struct usb_serial_port *port, unsigned char *data, unsigned int actual_length) { - + struct usb_serial *serial = port->serial; + struct pl2303_serial_private *spriv = usb_get_serial_data(serial); struct pl2303_private *priv = usb_get_serial_port_data(port); + struct tty_struct *tty; unsigned long flags; - u8 status_idx = UART_STATE; - u8 length = UART_STATE + 1; - u16 idv, idp; - - idv = le16_to_cpu(port->serial->dev->descriptor.idVendor); - idp = le16_to_cpu(port->serial->dev->descriptor.idProduct); - + unsigned int status_idx = UART_STATE_INDEX; + u8 status; + u8 delta; - if (idv == SIEMENS_VENDOR_ID) { - if (idp == SIEMENS_PRODUCT_ID_X65 || - idp == SIEMENS_PRODUCT_ID_SX1 || - idp == SIEMENS_PRODUCT_ID_X75) { - - length = 1; - status_idx = 0; - } - } + if (spriv->quirks & PL2303_QUIRK_UART_STATE_IDX0) + status_idx = 0; - if (actual_length < length) + if (actual_length < status_idx + 1) return; + status = data[status_idx]; + /* Save off the uart status for others to look at */ spin_lock_irqsave(&priv->lock, flags); - priv->line_status = data[status_idx]; + delta = priv->line_status ^ status; + priv->line_status = status; spin_unlock_irqrestore(&priv->lock, flags); - if (priv->line_status & UART_BREAK_ERROR) + + if (status & UART_BREAK_ERROR) usb_serial_handle_break(port); - wake_up_interruptible(&priv->delta_msr_wait); + + if (delta & UART_STATE_MSR_MASK) { + if (delta & UART_CTS) + port->icount.cts++; + if (delta & UART_DSR) + port->icount.dsr++; + if (delta & UART_RING) + port->icount.rng++; + if (delta & UART_DCD) { + port->icount.dcd++; + tty = tty_port_tty_get(&port->port); + if (tty) { + usb_serial_handle_dcd_change(port, tty, + status & UART_DCD); + tty_kref_put(tty); + } + } + + wake_up_interruptible(&port->port.delta_msr_wait); + } } static void pl2303_read_int_callback(struct urb *urb) @@ -716,8 +820,6 @@ static void pl2303_read_int_callback(struct urb *urb) int status = urb->status; int retval; - dbg("%s (%d)", __func__, port->number); - switch (status) { case 0: /* success */ @@ -726,33 +828,33 @@ static void pl2303_read_int_callback(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", __func__, - status); + dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n", + __func__, status); return; default: - dbg("%s - nonzero urb status received: %d", __func__, - status); + dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n", + __func__, status); goto exit; } - usb_serial_debug_data(debug, &port->dev, __func__, + usb_serial_debug_data(&port->dev, __func__, urb->actual_length, urb->transfer_buffer); pl2303_update_line_status(port, data, actual_length); exit: retval = usb_submit_urb(urb, GFP_ATOMIC); - if (retval) - dev_err(&urb->dev->dev, + if (retval) { + dev_err(&port->dev, "%s - usb_submit_urb failed with result %d\n", __func__, retval); + } } static void pl2303_process_read_urb(struct urb *urb) { struct usb_serial_port *port = urb->context; struct pl2303_private *priv = usb_get_serial_port_data(port); - struct tty_struct *tty; unsigned char *data = urb->transfer_buffer; char tty_flag = TTY_NORMAL; unsigned long flags; @@ -764,98 +866,74 @@ static void pl2303_process_read_urb(struct urb *urb) line_status = priv->line_status; priv->line_status &= ~UART_STATE_TRANSIENT_MASK; spin_unlock_irqrestore(&priv->lock, flags); - wake_up_interruptible(&priv->delta_msr_wait); if (!urb->actual_length) return; - tty = tty_port_tty_get(&port->port); - if (!tty) - return; - - /* break takes precedence over parity, */ - /* which takes precedence over framing errors */ + /* + * Break takes precedence over parity, which takes precedence over + * framing errors. + */ if (line_status & UART_BREAK_ERROR) tty_flag = TTY_BREAK; else if (line_status & UART_PARITY_ERROR) tty_flag = TTY_PARITY; else if (line_status & UART_FRAME_ERROR) tty_flag = TTY_FRAME; - dbg("%s - tty_flag = %d", __func__, tty_flag); + if (tty_flag != TTY_NORMAL) + dev_dbg(&port->dev, "%s - tty_flag = %d\n", __func__, + tty_flag); /* overrun is special, not associated with a char */ if (line_status & UART_OVERRUN_ERROR) - tty_insert_flip_char(tty, 0, TTY_OVERRUN); + tty_insert_flip_char(&port->port, 0, TTY_OVERRUN); if (port->port.console && port->sysrq) { for (i = 0; i < urb->actual_length; ++i) if (!usb_serial_handle_sysrq_char(port, data[i])) - tty_insert_flip_char(tty, data[i], tty_flag); + tty_insert_flip_char(&port->port, data[i], + tty_flag); } else { - tty_insert_flip_string_fixed_flag(tty, data, tty_flag, + tty_insert_flip_string_fixed_flag(&port->port, data, tty_flag, urb->actual_length); } - tty_flip_buffer_push(tty); - tty_kref_put(tty); + tty_flip_buffer_push(&port->port); } -/* All of the device info needed for the PL2303 SIO serial converter */ static struct usb_serial_driver pl2303_device = { .driver = { .owner = THIS_MODULE, .name = "pl2303", }, .id_table = id_table, - .usb_driver = &pl2303_driver, .num_ports = 1, .bulk_in_size = 256, .bulk_out_size = 256, .open = pl2303_open, .close = pl2303_close, - .dtr_rts = pl2303_dtr_rts, + .dtr_rts = pl2303_dtr_rts, .carrier_raised = pl2303_carrier_raised, .ioctl = pl2303_ioctl, .break_ctl = pl2303_break_ctl, .set_termios = pl2303_set_termios, .tiocmget = pl2303_tiocmget, .tiocmset = pl2303_tiocmset, + .tiocmiwait = usb_serial_generic_tiocmiwait, .process_read_urb = pl2303_process_read_urb, .read_int_callback = pl2303_read_int_callback, + .probe = pl2303_probe, .attach = pl2303_startup, .release = pl2303_release, + .port_probe = pl2303_port_probe, + .port_remove = pl2303_port_remove, }; -static int __init pl2303_init(void) -{ - int retval; - - retval = usb_serial_register(&pl2303_device); - if (retval) - goto failed_usb_serial_register; - retval = usb_register(&pl2303_driver); - if (retval) - goto failed_usb_register; - printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n"); - return 0; -failed_usb_register: - usb_serial_deregister(&pl2303_device); -failed_usb_serial_register: - return retval; -} - -static void __exit pl2303_exit(void) -{ - usb_deregister(&pl2303_driver); - usb_serial_deregister(&pl2303_device); -} +static struct usb_serial_driver * const serial_drivers[] = { + &pl2303_device, NULL +}; -module_init(pl2303_init); -module_exit(pl2303_exit); +module_usb_serial_driver(serial_drivers, id_table); -MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_DESCRIPTION("Prolific PL2303 USB to serial adaptor driver"); MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); - diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h index 43eb9bdad42..42bc082896a 100644 --- a/drivers/usb/serial/pl2303.h +++ b/drivers/usb/serial/pl2303.h @@ -21,6 +21,7 @@ #define PL2303_PRODUCT_ID_MMX 0x0612 #define PL2303_PRODUCT_ID_GPRS 0x0609 #define PL2303_PRODUCT_ID_HCR331 0x331a +#define PL2303_PRODUCT_ID_MOTOROLA 0x0307 #define ATEN_VENDOR_ID 0x0557 #define ATEN_VENDOR_ID2 0x0547 @@ -120,8 +121,11 @@ #define SUPERIAL_VENDOR_ID 0x5372 #define SUPERIAL_PRODUCT_ID 0x2303 -/* Hewlett-Packard LD220-HP POS Pole Display */ +/* Hewlett-Packard POS Pole Displays */ #define HP_VENDOR_ID 0x03f0 +#define HP_LD960_PRODUCT_ID 0x0b39 +#define HP_LCM220_PRODUCT_ID 0x3139 +#define HP_LCM960_PRODUCT_ID 0x3239 #define HP_LD220_PRODUCT_ID 0x3524 /* Cressi Edy (diving computer) PC interface */ @@ -143,3 +147,8 @@ /* ADLINK ND-6530 RS232,RS485 and RS422 adapter */ #define ADLINK_VENDOR_ID 0x0b63 #define ADLINK_ND6530_PRODUCT_ID 0x6530 + +/* SMART USB Serial Adapter */ +#define SMART_VENDOR_ID 0x0b8c +#define SMART_PRODUCT_ID 0x2303 + diff --git a/drivers/usb/serial/qcaux.c b/drivers/usb/serial/qcaux.c index 214a3e50429..6e9f8af9695 100644 --- a/drivers/usb/serial/qcaux.c +++ b/drivers/usb/serial/qcaux.c @@ -16,7 +16,6 @@ */ #include <linux/kernel.h> -#include <linux/init.h> #include <linux/tty.h> #include <linux/module.h> #include <linux/usb.h> @@ -54,7 +53,7 @@ #define SAMSUNG_VENDOR_ID 0x04e8 #define SAMSUNG_PRODUCT_U520 0x6640 /* SCH-U520 */ -static struct usb_device_id id_table[] = { +static const struct usb_device_id id_table[] = { { USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, UTSTARCOM_PRODUCT_PC5740, 0xff, 0x00, 0x00) }, { USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, UTSTARCOM_PRODUCT_PC5750, 0xff, 0x00, 0x00) }, { USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, UTSTARCOM_PRODUCT_UM150, 0xff, 0x00, 0x00) }, @@ -66,18 +65,14 @@ static struct usb_device_id id_table[] = { { USB_DEVICE_AND_INTERFACE_INFO(LG_VENDOR_ID, LG_PRODUCT_VX4400_6000, 0xff, 0xff, 0x00) }, { USB_DEVICE_AND_INTERFACE_INFO(SANYO_VENDOR_ID, SANYO_PRODUCT_KATANA_LX, 0xff, 0xff, 0x00) }, { USB_DEVICE_AND_INTERFACE_INFO(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_U520, 0xff, 0x00, 0x00) }, + { USB_VENDOR_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, 0xff, 0xfd, 0xff) }, /* NMEA */ + { USB_VENDOR_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, 0xff, 0xfe, 0xff) }, /* WMC */ + { USB_VENDOR_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, 0xff, 0xff, 0xff) }, /* DIAG */ + { USB_DEVICE_AND_INTERFACE_INFO(0x1fac, 0x0151, 0xff, 0xff, 0xff) }, { }, }; MODULE_DEVICE_TABLE(usb, id_table); -static struct usb_driver qcaux_driver = { - .name = "qcaux", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, - .no_dynamic_id = 1, -}; - static struct usb_serial_driver qcaux_device = { .driver = { .owner = THIS_MODULE, @@ -87,25 +82,9 @@ static struct usb_serial_driver qcaux_device = { .num_ports = 1, }; -static int __init qcaux_init(void) -{ - int retval; - - retval = usb_serial_register(&qcaux_device); - if (retval) - return retval; - retval = usb_register(&qcaux_driver); - if (retval) - usb_serial_deregister(&qcaux_device); - return retval; -} - -static void __exit qcaux_exit(void) -{ - usb_deregister(&qcaux_driver); - usb_serial_deregister(&qcaux_device); -} +static struct usb_serial_driver * const serial_drivers[] = { + &qcaux_device, NULL +}; -module_init(qcaux_init); -module_exit(qcaux_exit); +module_usb_serial_driver(serial_drivers, id_table); MODULE_LICENSE("GPL"); diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c index 8858201eb1d..b2aa003bf41 100644 --- a/drivers/usb/serial/qcserial.c +++ b/drivers/usb/serial/qcserial.c @@ -13,6 +13,7 @@ #include <linux/tty.h> #include <linux/tty_flip.h> +#include <linux/module.h> #include <linux/usb.h> #include <linux/usb/serial.h> #include <linux/slab.h> @@ -21,34 +22,60 @@ #define DRIVER_AUTHOR "Qualcomm Inc" #define DRIVER_DESC "Qualcomm USB Serial driver" -static int debug; +/* standard device layouts supported by this driver */ +enum qcserial_layouts { + QCSERIAL_G2K = 0, /* Gobi 2000 */ + QCSERIAL_G1K = 1, /* Gobi 1000 */ + QCSERIAL_SWI = 2, /* Sierra Wireless */ +}; + +#define DEVICE_G1K(v, p) \ + USB_DEVICE(v, p), .driver_info = QCSERIAL_G1K +#define DEVICE_SWI(v, p) \ + USB_DEVICE(v, p), .driver_info = QCSERIAL_SWI static const struct usb_device_id id_table[] = { - {USB_DEVICE(0x05c6, 0x9211)}, /* Acer Gobi QDL device */ - {USB_DEVICE(0x05c6, 0x9212)}, /* Acer Gobi Modem Device */ - {USB_DEVICE(0x03f0, 0x1f1d)}, /* HP un2400 Gobi Modem Device */ - {USB_DEVICE(0x03f0, 0x201d)}, /* HP un2400 Gobi QDL Device */ - {USB_DEVICE(0x04da, 0x250d)}, /* Panasonic Gobi Modem device */ - {USB_DEVICE(0x04da, 0x250c)}, /* Panasonic Gobi QDL device */ - {USB_DEVICE(0x413c, 0x8172)}, /* Dell Gobi Modem device */ - {USB_DEVICE(0x413c, 0x8171)}, /* Dell Gobi QDL device */ - {USB_DEVICE(0x1410, 0xa001)}, /* Novatel Gobi Modem device */ - {USB_DEVICE(0x1410, 0xa008)}, /* Novatel Gobi QDL device */ - {USB_DEVICE(0x0b05, 0x1776)}, /* Asus Gobi Modem device */ - {USB_DEVICE(0x0b05, 0x1774)}, /* Asus Gobi QDL device */ - {USB_DEVICE(0x19d2, 0xfff3)}, /* ONDA Gobi Modem device */ - {USB_DEVICE(0x19d2, 0xfff2)}, /* ONDA Gobi QDL device */ - {USB_DEVICE(0x1557, 0x0a80)}, /* OQO Gobi QDL device */ - {USB_DEVICE(0x05c6, 0x9001)}, /* Generic Gobi Modem device */ - {USB_DEVICE(0x05c6, 0x9002)}, /* Generic Gobi Modem device */ - {USB_DEVICE(0x05c6, 0x9202)}, /* Generic Gobi Modem device */ - {USB_DEVICE(0x05c6, 0x9203)}, /* Generic Gobi Modem device */ - {USB_DEVICE(0x05c6, 0x9222)}, /* Generic Gobi Modem device */ - {USB_DEVICE(0x05c6, 0x9008)}, /* Generic Gobi QDL device */ - {USB_DEVICE(0x05c6, 0x9201)}, /* Generic Gobi QDL device */ - {USB_DEVICE(0x05c6, 0x9221)}, /* Generic Gobi QDL device */ - {USB_DEVICE(0x05c6, 0x9231)}, /* Generic Gobi QDL device */ - {USB_DEVICE(0x1f45, 0x0001)}, /* Unknown Gobi QDL device */ + /* Gobi 1000 devices */ + {DEVICE_G1K(0x05c6, 0x9211)}, /* Acer Gobi QDL device */ + {DEVICE_G1K(0x05c6, 0x9212)}, /* Acer Gobi Modem Device */ + {DEVICE_G1K(0x03f0, 0x1f1d)}, /* HP un2400 Gobi Modem Device */ + {DEVICE_G1K(0x03f0, 0x201d)}, /* HP un2400 Gobi QDL Device */ + {DEVICE_G1K(0x04da, 0x250d)}, /* Panasonic Gobi Modem device */ + {DEVICE_G1K(0x04da, 0x250c)}, /* Panasonic Gobi QDL device */ + {DEVICE_G1K(0x413c, 0x8172)}, /* Dell Gobi Modem device */ + {DEVICE_G1K(0x413c, 0x8171)}, /* Dell Gobi QDL device */ + {DEVICE_G1K(0x1410, 0xa001)}, /* Novatel/Verizon USB-1000 */ + {DEVICE_G1K(0x1410, 0xa002)}, /* Novatel Gobi Modem device */ + {DEVICE_G1K(0x1410, 0xa003)}, /* Novatel Gobi Modem device */ + {DEVICE_G1K(0x1410, 0xa004)}, /* Novatel Gobi Modem device */ + {DEVICE_G1K(0x1410, 0xa005)}, /* Novatel Gobi Modem device */ + {DEVICE_G1K(0x1410, 0xa006)}, /* Novatel Gobi Modem device */ + {DEVICE_G1K(0x1410, 0xa007)}, /* Novatel Gobi Modem device */ + {DEVICE_G1K(0x1410, 0xa008)}, /* Novatel Gobi QDL device */ + {DEVICE_G1K(0x0b05, 0x1776)}, /* Asus Gobi Modem device */ + {DEVICE_G1K(0x0b05, 0x1774)}, /* Asus Gobi QDL device */ + {DEVICE_G1K(0x19d2, 0xfff3)}, /* ONDA Gobi Modem device */ + {DEVICE_G1K(0x19d2, 0xfff2)}, /* ONDA Gobi QDL device */ + {DEVICE_G1K(0x1557, 0x0a80)}, /* OQO Gobi QDL device */ + {DEVICE_G1K(0x05c6, 0x9001)}, /* Generic Gobi Modem device */ + {DEVICE_G1K(0x05c6, 0x9002)}, /* Generic Gobi Modem device */ + {DEVICE_G1K(0x05c6, 0x9202)}, /* Generic Gobi Modem device */ + {DEVICE_G1K(0x05c6, 0x9203)}, /* Generic Gobi Modem device */ + {DEVICE_G1K(0x05c6, 0x9222)}, /* Generic Gobi Modem device */ + {DEVICE_G1K(0x05c6, 0x9008)}, /* Generic Gobi QDL device */ + {DEVICE_G1K(0x05c6, 0x9009)}, /* Generic Gobi Modem device */ + {DEVICE_G1K(0x05c6, 0x9201)}, /* Generic Gobi QDL device */ + {DEVICE_G1K(0x05c6, 0x9221)}, /* Generic Gobi QDL device */ + {DEVICE_G1K(0x05c6, 0x9231)}, /* Generic Gobi QDL device */ + {DEVICE_G1K(0x1f45, 0x0001)}, /* Unknown Gobi QDL device */ + {DEVICE_G1K(0x1bc7, 0x900e)}, /* Telit Gobi QDL device */ + + /* Gobi 2000 devices */ + {USB_DEVICE(0x1410, 0xa010)}, /* Novatel Gobi 2000 QDL device */ + {USB_DEVICE(0x1410, 0xa011)}, /* Novatel Gobi 2000 QDL device */ + {USB_DEVICE(0x1410, 0xa012)}, /* Novatel Gobi 2000 QDL device */ + {USB_DEVICE(0x1410, 0xa013)}, /* Novatel Gobi 2000 QDL device */ + {USB_DEVICE(0x1410, 0xa014)}, /* Novatel Gobi 2000 QDL device */ {USB_DEVICE(0x413c, 0x8185)}, /* Dell Gobi 2000 QDL device (N0218, VU936) */ {USB_DEVICE(0x413c, 0x8186)}, /* Dell Gobi 2000 Modem device (N0218, VU936) */ {USB_DEVICE(0x05c6, 0x9208)}, /* Generic Gobi 2000 QDL device */ @@ -78,133 +105,231 @@ static const struct usb_device_id id_table[] = { {USB_DEVICE(0x1199, 0x9008)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */ {USB_DEVICE(0x1199, 0x9009)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */ {USB_DEVICE(0x1199, 0x900a)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */ + {USB_DEVICE(0x1199, 0x9011)}, /* Sierra Wireless Gobi 2000 Modem device (MC8305) */ {USB_DEVICE(0x16d8, 0x8001)}, /* CMDTech Gobi 2000 QDL device (VU922) */ {USB_DEVICE(0x16d8, 0x8002)}, /* CMDTech Gobi 2000 Modem device (VU922) */ {USB_DEVICE(0x05c6, 0x9204)}, /* Gobi 2000 QDL device */ {USB_DEVICE(0x05c6, 0x9205)}, /* Gobi 2000 Modem device */ + + /* Gobi 3000 devices */ + {USB_DEVICE(0x03f0, 0x371d)}, /* HP un2430 Gobi 3000 QDL */ + {USB_DEVICE(0x05c6, 0x920c)}, /* Gobi 3000 QDL */ + {USB_DEVICE(0x05c6, 0x920d)}, /* Gobi 3000 Composite */ + {USB_DEVICE(0x1410, 0xa020)}, /* Novatel Gobi 3000 QDL */ + {USB_DEVICE(0x1410, 0xa021)}, /* Novatel Gobi 3000 Composite */ + {USB_DEVICE(0x413c, 0x8193)}, /* Dell Gobi 3000 QDL */ + {USB_DEVICE(0x413c, 0x8194)}, /* Dell Gobi 3000 Composite */ + {USB_DEVICE(0x1199, 0x68a4)}, /* Sierra Wireless QDL */ + {USB_DEVICE(0x1199, 0x68a5)}, /* Sierra Wireless Modem */ + {USB_DEVICE(0x1199, 0x68a8)}, /* Sierra Wireless QDL */ + {USB_DEVICE(0x1199, 0x68a9)}, /* Sierra Wireless Modem */ + {USB_DEVICE(0x1199, 0x9010)}, /* Sierra Wireless Gobi 3000 QDL */ + {USB_DEVICE(0x1199, 0x9012)}, /* Sierra Wireless Gobi 3000 QDL */ + {USB_DEVICE(0x1199, 0x9013)}, /* Sierra Wireless Gobi 3000 Modem device (MC8355) */ + {USB_DEVICE(0x1199, 0x9014)}, /* Sierra Wireless Gobi 3000 QDL */ + {USB_DEVICE(0x1199, 0x9015)}, /* Sierra Wireless Gobi 3000 Modem device */ + {USB_DEVICE(0x1199, 0x9018)}, /* Sierra Wireless Gobi 3000 QDL */ + {USB_DEVICE(0x1199, 0x9019)}, /* Sierra Wireless Gobi 3000 Modem device */ + {USB_DEVICE(0x1199, 0x901b)}, /* Sierra Wireless MC7770 */ + {USB_DEVICE(0x12D1, 0x14F0)}, /* Sony Gobi 3000 QDL */ + {USB_DEVICE(0x12D1, 0x14F1)}, /* Sony Gobi 3000 Composite */ + {USB_DEVICE(0x0AF0, 0x8120)}, /* Option GTM681W */ + + /* non-Gobi Sierra Wireless devices */ + {DEVICE_SWI(0x0f3d, 0x68a2)}, /* Sierra Wireless MC7700 */ + {DEVICE_SWI(0x114f, 0x68a2)}, /* Sierra Wireless MC7750 */ + {DEVICE_SWI(0x1199, 0x68a2)}, /* Sierra Wireless MC7710 */ + {DEVICE_SWI(0x1199, 0x68c0)}, /* Sierra Wireless MC73xx */ + {DEVICE_SWI(0x1199, 0x901c)}, /* Sierra Wireless EM7700 */ + {DEVICE_SWI(0x1199, 0x901f)}, /* Sierra Wireless EM7355 */ + {DEVICE_SWI(0x1199, 0x9040)}, /* Sierra Wireless Modem */ + {DEVICE_SWI(0x1199, 0x9041)}, /* Sierra Wireless MC7305/MC7355 */ + {DEVICE_SWI(0x1199, 0x9051)}, /* Netgear AirCard 340U */ + {DEVICE_SWI(0x1199, 0x9053)}, /* Sierra Wireless Modem */ + {DEVICE_SWI(0x1199, 0x9054)}, /* Sierra Wireless Modem */ + {DEVICE_SWI(0x1199, 0x9055)}, /* Netgear AirCard 341U */ + {DEVICE_SWI(0x1199, 0x9056)}, /* Sierra Wireless Modem */ + {DEVICE_SWI(0x1199, 0x9060)}, /* Sierra Wireless Modem */ + {DEVICE_SWI(0x1199, 0x9061)}, /* Sierra Wireless Modem */ + {DEVICE_SWI(0x413c, 0x81a2)}, /* Dell Wireless 5806 Gobi(TM) 4G LTE Mobile Broadband Card */ + {DEVICE_SWI(0x413c, 0x81a3)}, /* Dell Wireless 5570 HSPA+ (42Mbps) Mobile Broadband Card */ + {DEVICE_SWI(0x413c, 0x81a4)}, /* Dell Wireless 5570e HSPA+ (42Mbps) Mobile Broadband Card */ + {DEVICE_SWI(0x413c, 0x81a8)}, /* Dell Wireless 5808 Gobi(TM) 4G LTE Mobile Broadband Card */ + {DEVICE_SWI(0x413c, 0x81a9)}, /* Dell Wireless 5808e Gobi(TM) 4G LTE Mobile Broadband Card */ + { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, id_table); -static struct usb_driver qcdriver = { - .name = "qcserial", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, - .suspend = usb_serial_suspend, - .resume = usb_serial_resume, - .supports_autosuspend = true, -}; - static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id) { - struct usb_wwan_intf_private *data; struct usb_host_interface *intf = serial->interface->cur_altsetting; + struct device *dev = &serial->dev->dev; int retval = -ENODEV; __u8 nintf; __u8 ifnum; - - dbg("%s", __func__); + int altsetting = -1; nintf = serial->dev->actconfig->desc.bNumInterfaces; - dbg("Num Interfaces = %d", nintf); + dev_dbg(dev, "Num Interfaces = %d\n", nintf); ifnum = intf->desc.bInterfaceNumber; - dbg("This Interface = %d", ifnum); + dev_dbg(dev, "This Interface = %d\n", ifnum); - data = serial->private = kzalloc(sizeof(struct usb_wwan_intf_private), - GFP_KERNEL); - if (!data) - return -ENOMEM; - - spin_lock_init(&data->susp_lock); - - usb_enable_autosuspend(serial->dev); - - switch (nintf) { - case 1: + if (nintf == 1) { /* QDL mode */ /* Gobi 2000 has a single altsetting, older ones have two */ if (serial->interface->num_altsetting == 2) intf = &serial->interface->altsetting[1]; else if (serial->interface->num_altsetting > 2) - break; + goto done; if (intf->desc.bNumEndpoints == 2 && usb_endpoint_is_bulk_in(&intf->endpoint[0].desc) && usb_endpoint_is_bulk_out(&intf->endpoint[1].desc)) { - dbg("QDL port found"); + dev_dbg(dev, "QDL port found\n"); if (serial->interface->num_altsetting == 1) - return 0; - - retval = usb_set_interface(serial->dev, ifnum, 1); - if (retval < 0) { - dev_err(&serial->dev->dev, - "Could not set interface, error %d\n", - retval); - retval = -ENODEV; - kfree(data); - } - return retval; + retval = 0; /* Success */ + else + altsetting = 1; } + goto done; + + } + + /* default to enabling interface */ + altsetting = 0; + + /* + * Composite mode; don't bind to the QMI/net interface as that + * gets handled by other drivers. + */ + + switch (id->driver_info) { + case QCSERIAL_G1K: + /* + * Gobi 1K USB layout: + * 0: DM/DIAG (use libqcdm from ModemManager for communication) + * 1: serial port (doesn't respond) + * 2: AT-capable modem port + * 3: QMI/net + */ + if (nintf < 3 || nintf > 4) { + dev_err(dev, "unknown number of interfaces: %d\n", nintf); + altsetting = -1; + goto done; + } + + if (ifnum == 0) { + dev_dbg(dev, "Gobi 1K DM/DIAG interface found\n"); + altsetting = 1; + } else if (ifnum == 2) + dev_dbg(dev, "Modem port found\n"); + else + altsetting = -1; break; + case QCSERIAL_G2K: + /* + * Gobi 2K+ USB layout: + * 0: QMI/net + * 1: DM/DIAG (use libqcdm from ModemManager for communication) + * 2: AT-capable modem port + * 3: NMEA + */ + if (nintf < 3 || nintf > 4) { + dev_err(dev, "unknown number of interfaces: %d\n", nintf); + altsetting = -1; + goto done; + } - case 3: - case 4: - /* Composite mode */ - /* ifnum == 0 is a broadband network adapter */ - if (ifnum == 1) { - /* - * Diagnostics Monitor (serial line 9600 8N1) - * Qualcomm DM protocol - * use "libqcdm" (ModemManager) for communication - */ - dbg("Diagnostics Monitor found"); - retval = usb_set_interface(serial->dev, ifnum, 0); - if (retval < 0) { - dev_err(&serial->dev->dev, - "Could not set interface, error %d\n", - retval); - retval = -ENODEV; - } - } else if (ifnum == 2) { - dbg("Modem port found"); - retval = usb_set_interface(serial->dev, ifnum, 0); - if (retval < 0) { - dev_err(&serial->dev->dev, - "Could not set interface, error %d\n", - retval); - retval = -ENODEV; - kfree(data); - } - return retval; - } else if (ifnum==3) { + switch (ifnum) { + case 0: + /* Don't claim the QMI/net interface */ + altsetting = -1; + break; + case 1: + dev_dbg(dev, "Gobi 2K+ DM/DIAG interface found\n"); + break; + case 2: + dev_dbg(dev, "Modem port found\n"); + break; + case 3: /* * NMEA (serial line 9600 8N1) * # echo "\$GPS_START" > /dev/ttyUSBx * # echo "\$GPS_STOP" > /dev/ttyUSBx */ - dbg("NMEA GPS interface found"); - retval = usb_set_interface(serial->dev, ifnum, 0); - if (retval < 0) { - dev_err(&serial->dev->dev, - "Could not set interface, error %d\n", - retval); - retval = -ENODEV; - } + dev_dbg(dev, "Gobi 2K+ NMEA GPS interface found\n"); + break; + } + break; + case QCSERIAL_SWI: + /* + * Sierra Wireless layout: + * 0: DM/DIAG (use libqcdm from ModemManager for communication) + * 2: NMEA + * 3: AT-capable modem port + * 8: QMI/net + */ + switch (ifnum) { + case 0: + dev_dbg(dev, "DM/DIAG interface found\n"); + break; + case 2: + dev_dbg(dev, "NMEA GPS interface found\n"); + break; + case 3: + dev_dbg(dev, "Modem port found\n"); + break; + default: + /* don't claim any unsupported interface */ + altsetting = -1; + break; } break; - default: - dev_err(&serial->dev->dev, - "unknown number of interfaces: %d\n", nintf); - kfree(data); - return -ENODEV; + dev_err(dev, "unsupported device layout type: %lu\n", + id->driver_info); + break; + } + +done: + if (altsetting >= 0) { + retval = usb_set_interface(serial->dev, ifnum, altsetting); + if (retval < 0) { + dev_err(dev, + "Could not set interface, error %d\n", + retval); + retval = -ENODEV; + } } return retval; } +static int qc_attach(struct usb_serial *serial) +{ + struct usb_wwan_intf_private *data; + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + spin_lock_init(&data->susp_lock); + + usb_set_serial_data(serial, data); + + return 0; +} + +static void qc_release(struct usb_serial *serial) +{ + struct usb_wwan_intf_private *priv = usb_get_serial_data(serial); + + usb_set_serial_data(serial, NULL); + kfree(priv); +} + static struct usb_serial_driver qcdevice = { .driver = { .owner = THIS_MODULE, @@ -212,7 +337,6 @@ static struct usb_serial_driver qcdevice = { }, .description = "Qualcomm USB modem", .id_table = id_table, - .usb_driver = &qcdriver, .num_ports = 1, .probe = qcprobe, .open = usb_wwan_open, @@ -220,44 +344,22 @@ static struct usb_serial_driver qcdevice = { .write = usb_wwan_write, .write_room = usb_wwan_write_room, .chars_in_buffer = usb_wwan_chars_in_buffer, - .attach = usb_wwan_startup, - .disconnect = usb_wwan_disconnect, - .release = usb_wwan_release, + .attach = qc_attach, + .release = qc_release, + .port_probe = usb_wwan_port_probe, + .port_remove = usb_wwan_port_remove, #ifdef CONFIG_PM .suspend = usb_wwan_suspend, .resume = usb_wwan_resume, #endif }; -static int __init qcinit(void) -{ - int retval; - - retval = usb_serial_register(&qcdevice); - if (retval) - return retval; - - retval = usb_register(&qcdriver); - if (retval) { - usb_serial_deregister(&qcdevice); - return retval; - } - - return 0; -} - -static void __exit qcexit(void) -{ - usb_deregister(&qcdriver); - usb_serial_deregister(&qcdevice); -} +static struct usb_serial_driver * const serial_drivers[] = { + &qcdevice, NULL +}; -module_init(qcinit); -module_exit(qcexit); +module_usb_serial_driver(serial_drivers, id_table); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL v2"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/drivers/usb/serial/quatech2.c b/drivers/usb/serial/quatech2.c new file mode 100644 index 00000000000..504f5bff79c --- /dev/null +++ b/drivers/usb/serial/quatech2.c @@ -0,0 +1,1036 @@ +/* + * usb-serial driver for Quatech USB 2 devices + * + * Copyright (C) 2012 Bill Pemberton (wfp5p@virginia.edu) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * + * These devices all have only 1 bulk in and 1 bulk out that is shared + * for all serial ports. + * + */ + +#include <asm/unaligned.h> +#include <linux/errno.h> +#include <linux/slab.h> +#include <linux/tty.h> +#include <linux/tty_driver.h> +#include <linux/tty_flip.h> +#include <linux/module.h> +#include <linux/serial.h> +#include <linux/usb.h> +#include <linux/usb/serial.h> +#include <linux/serial_reg.h> +#include <linux/uaccess.h> + +/* default urb timeout for usb operations */ +#define QT2_USB_TIMEOUT USB_CTRL_SET_TIMEOUT + +#define QT_OPEN_CLOSE_CHANNEL 0xca +#define QT_SET_GET_DEVICE 0xc2 +#define QT_SET_GET_REGISTER 0xc0 +#define QT_GET_SET_PREBUF_TRIG_LVL 0xcc +#define QT_SET_ATF 0xcd +#define QT_TRANSFER_IN 0xc0 +#define QT_HW_FLOW_CONTROL_MASK 0xc5 +#define QT_SW_FLOW_CONTROL_MASK 0xc6 +#define QT2_BREAK_CONTROL 0xc8 +#define QT2_GET_SET_UART 0xc1 +#define QT2_FLUSH_DEVICE 0xc4 +#define QT2_GET_SET_QMCR 0xe1 +#define QT2_QMCR_RS232 0x40 +#define QT2_QMCR_RS422 0x10 + +#define SERIAL_CRTSCTS ((UART_MCR_RTS << 8) | UART_MSR_CTS) + +#define SERIAL_EVEN_PARITY (UART_LCR_PARITY | UART_LCR_EPAR) + +/* status bytes for the device */ +#define QT2_CONTROL_BYTE 0x1b +#define QT2_LINE_STATUS 0x00 /* following 1 byte is line status */ +#define QT2_MODEM_STATUS 0x01 /* following 1 byte is modem status */ +#define QT2_XMIT_HOLD 0x02 /* following 2 bytes are ?? */ +#define QT2_CHANGE_PORT 0x03 /* following 1 byte is port to change to */ +#define QT2_REC_FLUSH 0x04 /* no following info */ +#define QT2_XMIT_FLUSH 0x05 /* no following info */ +#define QT2_CONTROL_ESCAPE 0xff /* pass through previous 2 control bytes */ + +#define MAX_BAUD_RATE 921600 +#define DEFAULT_BAUD_RATE 9600 + +#define QT2_READ_BUFFER_SIZE 512 /* size of read buffer */ +#define QT2_WRITE_BUFFER_SIZE 512 /* size of write buffer */ +#define QT2_WRITE_CONTROL_SIZE 5 /* control bytes used for a write */ + +#define DRIVER_DESC "Quatech 2nd gen USB to Serial Driver" + +#define USB_VENDOR_ID_QUATECH 0x061d +#define QUATECH_SSU2_100 0xC120 /* RS232 single port */ +#define QUATECH_DSU2_100 0xC140 /* RS232 dual port */ +#define QUATECH_DSU2_400 0xC150 /* RS232/422/485 dual port */ +#define QUATECH_QSU2_100 0xC160 /* RS232 four port */ +#define QUATECH_QSU2_400 0xC170 /* RS232/422/485 four port */ +#define QUATECH_ESU2_100 0xC1A0 /* RS232 eight port */ +#define QUATECH_ESU2_400 0xC180 /* RS232/422/485 eight port */ + +struct qt2_device_detail { + int product_id; + int num_ports; +}; + +#define QT_DETAILS(prod, ports) \ + .product_id = (prod), \ + .num_ports = (ports) + +static const struct qt2_device_detail qt2_device_details[] = { + {QT_DETAILS(QUATECH_SSU2_100, 1)}, + {QT_DETAILS(QUATECH_DSU2_400, 2)}, + {QT_DETAILS(QUATECH_DSU2_100, 2)}, + {QT_DETAILS(QUATECH_QSU2_400, 4)}, + {QT_DETAILS(QUATECH_QSU2_100, 4)}, + {QT_DETAILS(QUATECH_ESU2_400, 8)}, + {QT_DETAILS(QUATECH_ESU2_100, 8)}, + {QT_DETAILS(0, 0)} /* Terminating entry */ +}; + +static const struct usb_device_id id_table[] = { + {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_SSU2_100)}, + {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_DSU2_100)}, + {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_DSU2_400)}, + {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_QSU2_100)}, + {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_QSU2_400)}, + {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_ESU2_100)}, + {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_ESU2_400)}, + {} /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(usb, id_table); + +struct qt2_serial_private { + unsigned char current_port; /* current port for incoming data */ + + struct urb *read_urb; /* shared among all ports */ + char *read_buffer; +}; + +struct qt2_port_private { + u8 device_port; + + spinlock_t urb_lock; + bool urb_in_use; + struct urb *write_urb; + char *write_buffer; + + spinlock_t lock; + u8 shadowLSR; + u8 shadowMSR; + + struct usb_serial_port *port; +}; + +static void qt2_update_lsr(struct usb_serial_port *port, unsigned char *ch); +static void qt2_update_msr(struct usb_serial_port *port, unsigned char *ch); +static void qt2_write_bulk_callback(struct urb *urb); +static void qt2_read_bulk_callback(struct urb *urb); + +static void qt2_release(struct usb_serial *serial) +{ + struct qt2_serial_private *serial_priv; + + serial_priv = usb_get_serial_data(serial); + + usb_free_urb(serial_priv->read_urb); + kfree(serial_priv->read_buffer); + kfree(serial_priv); +} + +static inline int calc_baud_divisor(int baudrate) +{ + int divisor, rem; + + divisor = MAX_BAUD_RATE / baudrate; + rem = MAX_BAUD_RATE % baudrate; + /* Round to nearest divisor */ + if (((rem * 2) >= baudrate) && (baudrate != 110)) + divisor++; + + return divisor; +} + +static inline int qt2_set_port_config(struct usb_device *dev, + unsigned char port_number, + u16 baudrate, u16 lcr) +{ + int divisor = calc_baud_divisor(baudrate); + u16 index = ((u16) (lcr << 8) | (u16) (port_number)); + + return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + QT2_GET_SET_UART, 0x40, + divisor, index, NULL, 0, QT2_USB_TIMEOUT); +} + +static inline int qt2_control_msg(struct usb_device *dev, + u8 request, u16 data, u16 index) +{ + return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + request, 0x40, data, index, + NULL, 0, QT2_USB_TIMEOUT); +} + +static inline int qt2_setdevice(struct usb_device *dev, u8 *data) +{ + u16 x = ((u16) (data[1] << 8) | (u16) (data[0])); + + return qt2_control_msg(dev, QT_SET_GET_DEVICE, x, 0); +} + + +static inline int qt2_getdevice(struct usb_device *dev, u8 *data) +{ + return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + QT_SET_GET_DEVICE, 0xc0, 0, 0, + data, 3, QT2_USB_TIMEOUT); +} + +static inline int qt2_getregister(struct usb_device *dev, + u8 uart, + u8 reg, + u8 *data) +{ + return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + QT_SET_GET_REGISTER, 0xc0, reg, + uart, data, sizeof(*data), QT2_USB_TIMEOUT); + +} + +static inline int qt2_setregister(struct usb_device *dev, + u8 uart, u8 reg, u16 data) +{ + u16 value = (data << 8) | reg; + + return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + QT_SET_GET_REGISTER, 0x40, value, uart, + NULL, 0, QT2_USB_TIMEOUT); +} + +static inline int update_mctrl(struct qt2_port_private *port_priv, + unsigned int set, unsigned int clear) +{ + struct usb_serial_port *port = port_priv->port; + struct usb_device *dev = port->serial->dev; + unsigned urb_value; + int status; + + if (((set | clear) & (TIOCM_DTR | TIOCM_RTS)) == 0) { + dev_dbg(&port->dev, + "update_mctrl - DTR|RTS not being set|cleared\n"); + return 0; /* no change */ + } + + clear &= ~set; /* 'set' takes precedence over 'clear' */ + urb_value = 0; + if (set & TIOCM_DTR) + urb_value |= UART_MCR_DTR; + if (set & TIOCM_RTS) + urb_value |= UART_MCR_RTS; + + status = qt2_setregister(dev, port_priv->device_port, UART_MCR, + urb_value); + if (status < 0) + dev_err(&port->dev, + "update_mctrl - Error from MODEM_CTRL urb: %i\n", + status); + return status; +} + +static int qt2_calc_num_ports(struct usb_serial *serial) +{ + struct qt2_device_detail d; + int i; + + for (i = 0; d = qt2_device_details[i], d.product_id != 0; i++) { + if (d.product_id == le16_to_cpu(serial->dev->descriptor.idProduct)) + return d.num_ports; + } + + /* we didn't recognize the device */ + dev_err(&serial->dev->dev, + "don't know the number of ports, assuming 1\n"); + + return 1; +} + +static void qt2_set_termios(struct tty_struct *tty, + struct usb_serial_port *port, + struct ktermios *old_termios) +{ + struct usb_device *dev = port->serial->dev; + struct qt2_port_private *port_priv; + struct ktermios *termios = &tty->termios; + u16 baud; + unsigned int cflag = termios->c_cflag; + u16 new_lcr = 0; + int status; + + port_priv = usb_get_serial_port_data(port); + + if (cflag & PARENB) { + if (cflag & PARODD) + new_lcr |= UART_LCR_PARITY; + else + new_lcr |= SERIAL_EVEN_PARITY; + } + + switch (cflag & CSIZE) { + case CS5: + new_lcr |= UART_LCR_WLEN5; + break; + case CS6: + new_lcr |= UART_LCR_WLEN6; + break; + case CS7: + new_lcr |= UART_LCR_WLEN7; + break; + default: + case CS8: + new_lcr |= UART_LCR_WLEN8; + break; + } + + baud = tty_get_baud_rate(tty); + if (!baud) + baud = 9600; + + status = qt2_set_port_config(dev, port_priv->device_port, baud, + new_lcr); + if (status < 0) + dev_err(&port->dev, "%s - qt2_set_port_config failed: %i\n", + __func__, status); + + if (cflag & CRTSCTS) + status = qt2_control_msg(dev, QT_HW_FLOW_CONTROL_MASK, + SERIAL_CRTSCTS, + port_priv->device_port); + else + status = qt2_control_msg(dev, QT_HW_FLOW_CONTROL_MASK, + 0, port_priv->device_port); + if (status < 0) + dev_err(&port->dev, "%s - set HW flow control failed: %i\n", + __func__, status); + + if (I_IXOFF(tty) || I_IXON(tty)) { + u16 x = ((u16) (START_CHAR(tty) << 8) | (u16) (STOP_CHAR(tty))); + + status = qt2_control_msg(dev, QT_SW_FLOW_CONTROL_MASK, + x, port_priv->device_port); + } else + status = qt2_control_msg(dev, QT_SW_FLOW_CONTROL_MASK, + 0, port_priv->device_port); + + if (status < 0) + dev_err(&port->dev, "%s - set SW flow control failed: %i\n", + __func__, status); + +} + +static int qt2_open(struct tty_struct *tty, struct usb_serial_port *port) +{ + struct usb_serial *serial; + struct qt2_port_private *port_priv; + u8 *data; + u16 device_port; + int status; + unsigned long flags; + + device_port = port->port_number; + + serial = port->serial; + + port_priv = usb_get_serial_port_data(port); + + /* set the port to RS232 mode */ + status = qt2_control_msg(serial->dev, QT2_GET_SET_QMCR, + QT2_QMCR_RS232, device_port); + if (status < 0) { + dev_err(&port->dev, + "%s failed to set RS232 mode for port %i error %i\n", + __func__, device_port, status); + return status; + } + + data = kzalloc(2, GFP_KERNEL); + if (!data) + return -ENOMEM; + + /* open the port */ + status = usb_control_msg(serial->dev, + usb_rcvctrlpipe(serial->dev, 0), + QT_OPEN_CLOSE_CHANNEL, + 0xc0, 0, + device_port, data, 2, QT2_USB_TIMEOUT); + + if (status < 0) { + dev_err(&port->dev, "%s - open port failed %i\n", __func__, + status); + kfree(data); + return status; + } + + spin_lock_irqsave(&port_priv->lock, flags); + port_priv->shadowLSR = data[0]; + port_priv->shadowMSR = data[1]; + spin_unlock_irqrestore(&port_priv->lock, flags); + + kfree(data); + + /* set to default speed and 8bit word size */ + status = qt2_set_port_config(serial->dev, device_port, + DEFAULT_BAUD_RATE, UART_LCR_WLEN8); + if (status < 0) { + dev_err(&port->dev, "%s - initial setup failed (%i)\n", + __func__, device_port); + return status; + } + + port_priv->device_port = (u8) device_port; + + if (tty) + qt2_set_termios(tty, port, &tty->termios); + + return 0; + +} + +static void qt2_close(struct usb_serial_port *port) +{ + struct usb_serial *serial; + struct qt2_port_private *port_priv; + unsigned long flags; + int i; + + serial = port->serial; + port_priv = usb_get_serial_port_data(port); + + spin_lock_irqsave(&port_priv->urb_lock, flags); + usb_kill_urb(port_priv->write_urb); + port_priv->urb_in_use = false; + spin_unlock_irqrestore(&port_priv->urb_lock, flags); + + /* flush the port transmit buffer */ + i = usb_control_msg(serial->dev, + usb_rcvctrlpipe(serial->dev, 0), + QT2_FLUSH_DEVICE, 0x40, 1, + port_priv->device_port, NULL, 0, QT2_USB_TIMEOUT); + + if (i < 0) + dev_err(&port->dev, "%s - transmit buffer flush failed: %i\n", + __func__, i); + + /* flush the port receive buffer */ + i = usb_control_msg(serial->dev, + usb_rcvctrlpipe(serial->dev, 0), + QT2_FLUSH_DEVICE, 0x40, 0, + port_priv->device_port, NULL, 0, QT2_USB_TIMEOUT); + + if (i < 0) + dev_err(&port->dev, "%s - receive buffer flush failed: %i\n", + __func__, i); + + /* close the port */ + i = usb_control_msg(serial->dev, + usb_sndctrlpipe(serial->dev, 0), + QT_OPEN_CLOSE_CHANNEL, + 0x40, 0, + port_priv->device_port, NULL, 0, QT2_USB_TIMEOUT); + + if (i < 0) + dev_err(&port->dev, "%s - close port failed %i\n", + __func__, i); +} + +static void qt2_disconnect(struct usb_serial *serial) +{ + struct qt2_serial_private *serial_priv = usb_get_serial_data(serial); + + usb_kill_urb(serial_priv->read_urb); +} + +static int get_serial_info(struct usb_serial_port *port, + struct serial_struct __user *retinfo) +{ + struct serial_struct tmp; + + if (!retinfo) + return -EFAULT; + + memset(&tmp, 0, sizeof(tmp)); + tmp.line = port->minor; + tmp.port = 0; + tmp.irq = 0; + tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ; + tmp.xmit_fifo_size = port->bulk_out_size; + tmp.baud_base = 9600; + tmp.close_delay = 5*HZ; + tmp.closing_wait = 30*HZ; + + if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) + return -EFAULT; + return 0; +} + +static int qt2_ioctl(struct tty_struct *tty, + unsigned int cmd, unsigned long arg) +{ + struct usb_serial_port *port = tty->driver_data; + + switch (cmd) { + case TIOCGSERIAL: + return get_serial_info(port, + (struct serial_struct __user *)arg); + default: + break; + } + + return -ENOIOCTLCMD; +} + +static void qt2_process_status(struct usb_serial_port *port, unsigned char *ch) +{ + switch (*ch) { + case QT2_LINE_STATUS: + qt2_update_lsr(port, ch + 1); + break; + case QT2_MODEM_STATUS: + qt2_update_msr(port, ch + 1); + break; + } +} + +/* not needed, kept to document functionality */ +static void qt2_process_xmit_empty(struct usb_serial_port *port, + unsigned char *ch) +{ + int bytes_written; + + bytes_written = (int)(*ch) + (int)(*(ch + 1) << 4); +} + +/* not needed, kept to document functionality */ +static void qt2_process_flush(struct usb_serial_port *port, unsigned char *ch) +{ + return; +} + +static void qt2_process_read_urb(struct urb *urb) +{ + struct usb_serial *serial; + struct qt2_serial_private *serial_priv; + struct usb_serial_port *port; + struct qt2_port_private *port_priv; + bool escapeflag; + unsigned char *ch; + int i; + unsigned char newport; + int len = urb->actual_length; + + if (!len) + return; + + ch = urb->transfer_buffer; + serial = urb->context; + serial_priv = usb_get_serial_data(serial); + port = serial->port[serial_priv->current_port]; + port_priv = usb_get_serial_port_data(port); + + for (i = 0; i < urb->actual_length; i++) { + ch = (unsigned char *)urb->transfer_buffer + i; + if ((i <= (len - 3)) && + (*ch == QT2_CONTROL_BYTE) && + (*(ch + 1) == QT2_CONTROL_BYTE)) { + escapeflag = false; + switch (*(ch + 2)) { + case QT2_LINE_STATUS: + case QT2_MODEM_STATUS: + if (i > (len - 4)) { + dev_warn(&port->dev, + "%s - status message too short\n", + __func__); + break; + } + qt2_process_status(port, ch + 2); + i += 3; + escapeflag = true; + break; + case QT2_XMIT_HOLD: + if (i > (len - 5)) { + dev_warn(&port->dev, + "%s - xmit_empty message too short\n", + __func__); + break; + } + qt2_process_xmit_empty(port, ch + 3); + i += 4; + escapeflag = true; + break; + case QT2_CHANGE_PORT: + if (i > (len - 4)) { + dev_warn(&port->dev, + "%s - change_port message too short\n", + __func__); + break; + } + tty_flip_buffer_push(&port->port); + + newport = *(ch + 3); + + if (newport > serial->num_ports) { + dev_err(&port->dev, + "%s - port change to invalid port: %i\n", + __func__, newport); + break; + } + + serial_priv->current_port = newport; + port = serial->port[serial_priv->current_port]; + port_priv = usb_get_serial_port_data(port); + i += 3; + escapeflag = true; + break; + case QT2_REC_FLUSH: + case QT2_XMIT_FLUSH: + qt2_process_flush(port, ch + 2); + i += 2; + escapeflag = true; + break; + case QT2_CONTROL_ESCAPE: + tty_buffer_request_room(&port->port, 2); + tty_insert_flip_string(&port->port, ch, 2); + i += 2; + escapeflag = true; + break; + default: + dev_warn(&port->dev, + "%s - unsupported command %i\n", + __func__, *(ch + 2)); + break; + } + if (escapeflag) + continue; + } + + tty_buffer_request_room(&port->port, 1); + tty_insert_flip_string(&port->port, ch, 1); + } + + tty_flip_buffer_push(&port->port); +} + +static void qt2_write_bulk_callback(struct urb *urb) +{ + struct usb_serial_port *port; + struct qt2_port_private *port_priv; + + port = urb->context; + port_priv = usb_get_serial_port_data(port); + + spin_lock(&port_priv->urb_lock); + + port_priv->urb_in_use = false; + usb_serial_port_softint(port); + + spin_unlock(&port_priv->urb_lock); + +} + +static void qt2_read_bulk_callback(struct urb *urb) +{ + struct usb_serial *serial = urb->context; + int status; + + if (urb->status) { + dev_warn(&serial->dev->dev, + "%s - non-zero urb status: %i\n", __func__, + urb->status); + return; + } + + qt2_process_read_urb(urb); + + status = usb_submit_urb(urb, GFP_ATOMIC); + if (status != 0) + dev_err(&serial->dev->dev, + "%s - resubmit read urb failed: %i\n", + __func__, status); +} + +static int qt2_setup_urbs(struct usb_serial *serial) +{ + struct usb_serial_port *port0; + struct qt2_serial_private *serial_priv; + int status; + + port0 = serial->port[0]; + + serial_priv = usb_get_serial_data(serial); + serial_priv->read_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!serial_priv->read_urb) + return -ENOMEM; + + usb_fill_bulk_urb(serial_priv->read_urb, serial->dev, + usb_rcvbulkpipe(serial->dev, + port0->bulk_in_endpointAddress), + serial_priv->read_buffer, + QT2_READ_BUFFER_SIZE, + qt2_read_bulk_callback, serial); + + status = usb_submit_urb(serial_priv->read_urb, GFP_KERNEL); + if (status != 0) { + dev_err(&serial->dev->dev, + "%s - submit read urb failed %i\n", __func__, status); + usb_free_urb(serial_priv->read_urb); + return status; + } + + return 0; +} + +static int qt2_attach(struct usb_serial *serial) +{ + struct qt2_serial_private *serial_priv; + int status; + + /* power on unit */ + status = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), + 0xc2, 0x40, 0x8000, 0, NULL, 0, + QT2_USB_TIMEOUT); + if (status < 0) { + dev_err(&serial->dev->dev, + "%s - failed to power on unit: %i\n", __func__, status); + return status; + } + + serial_priv = kzalloc(sizeof(*serial_priv), GFP_KERNEL); + if (!serial_priv) + return -ENOMEM; + + serial_priv->read_buffer = kmalloc(QT2_READ_BUFFER_SIZE, GFP_KERNEL); + if (!serial_priv->read_buffer) { + status = -ENOMEM; + goto err_buf; + } + + usb_set_serial_data(serial, serial_priv); + + status = qt2_setup_urbs(serial); + if (status != 0) + goto attach_failed; + + return 0; + +attach_failed: + kfree(serial_priv->read_buffer); +err_buf: + kfree(serial_priv); + return status; +} + +static int qt2_port_probe(struct usb_serial_port *port) +{ + struct usb_serial *serial = port->serial; + struct qt2_port_private *port_priv; + u8 bEndpointAddress; + + port_priv = kzalloc(sizeof(*port_priv), GFP_KERNEL); + if (!port_priv) + return -ENOMEM; + + spin_lock_init(&port_priv->lock); + spin_lock_init(&port_priv->urb_lock); + port_priv->port = port; + + port_priv->write_buffer = kmalloc(QT2_WRITE_BUFFER_SIZE, GFP_KERNEL); + if (!port_priv->write_buffer) + goto err_buf; + + port_priv->write_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!port_priv->write_urb) + goto err_urb; + + bEndpointAddress = serial->port[0]->bulk_out_endpointAddress; + usb_fill_bulk_urb(port_priv->write_urb, serial->dev, + usb_sndbulkpipe(serial->dev, bEndpointAddress), + port_priv->write_buffer, + QT2_WRITE_BUFFER_SIZE, + qt2_write_bulk_callback, port); + + usb_set_serial_port_data(port, port_priv); + + return 0; +err_urb: + kfree(port_priv->write_buffer); +err_buf: + kfree(port_priv); + return -ENOMEM; +} + +static int qt2_port_remove(struct usb_serial_port *port) +{ + struct qt2_port_private *port_priv; + + port_priv = usb_get_serial_port_data(port); + usb_free_urb(port_priv->write_urb); + kfree(port_priv->write_buffer); + kfree(port_priv); + + return 0; +} + +static int qt2_tiocmget(struct tty_struct *tty) +{ + struct usb_serial_port *port = tty->driver_data; + struct usb_device *dev = port->serial->dev; + struct qt2_port_private *port_priv = usb_get_serial_port_data(port); + u8 *d; + int r; + + d = kzalloc(2, GFP_KERNEL); + if (!d) + return -ENOMEM; + + r = qt2_getregister(dev, port_priv->device_port, UART_MCR, d); + if (r < 0) + goto mget_out; + + r = qt2_getregister(dev, port_priv->device_port, UART_MSR, d + 1); + if (r < 0) + goto mget_out; + + r = (d[0] & UART_MCR_DTR ? TIOCM_DTR : 0) | + (d[0] & UART_MCR_RTS ? TIOCM_RTS : 0) | + (d[1] & UART_MSR_CTS ? TIOCM_CTS : 0) | + (d[1] & UART_MSR_DCD ? TIOCM_CAR : 0) | + (d[1] & UART_MSR_RI ? TIOCM_RI : 0) | + (d[1] & UART_MSR_DSR ? TIOCM_DSR : 0); + +mget_out: + kfree(d); + return r; +} + +static int qt2_tiocmset(struct tty_struct *tty, + unsigned int set, unsigned int clear) +{ + struct qt2_port_private *port_priv; + + port_priv = usb_get_serial_port_data(tty->driver_data); + return update_mctrl(port_priv, set, clear); +} + +static void qt2_break_ctl(struct tty_struct *tty, int break_state) +{ + struct usb_serial_port *port = tty->driver_data; + struct qt2_port_private *port_priv; + int status; + u16 val; + + port_priv = usb_get_serial_port_data(port); + + val = (break_state == -1) ? 1 : 0; + + status = qt2_control_msg(port->serial->dev, QT2_BREAK_CONTROL, + val, port_priv->device_port); + if (status < 0) + dev_warn(&port->dev, + "%s - failed to send control message: %i\n", __func__, + status); +} + + + +static void qt2_dtr_rts(struct usb_serial_port *port, int on) +{ + struct usb_device *dev = port->serial->dev; + struct qt2_port_private *port_priv = usb_get_serial_port_data(port); + + /* Disable flow control */ + if (!on) { + if (qt2_setregister(dev, port_priv->device_port, + UART_MCR, 0) < 0) + dev_warn(&port->dev, "error from flowcontrol urb\n"); + } + /* drop RTS and DTR */ + if (on) + update_mctrl(port_priv, TIOCM_DTR | TIOCM_RTS, 0); + else + update_mctrl(port_priv, 0, TIOCM_DTR | TIOCM_RTS); +} + +static void qt2_update_msr(struct usb_serial_port *port, unsigned char *ch) +{ + struct qt2_port_private *port_priv; + u8 newMSR = (u8) *ch; + unsigned long flags; + + port_priv = usb_get_serial_port_data(port); + + spin_lock_irqsave(&port_priv->lock, flags); + port_priv->shadowMSR = newMSR; + spin_unlock_irqrestore(&port_priv->lock, flags); + + if (newMSR & UART_MSR_ANY_DELTA) { + /* update input line counters */ + if (newMSR & UART_MSR_DCTS) + port->icount.cts++; + if (newMSR & UART_MSR_DDSR) + port->icount.dsr++; + if (newMSR & UART_MSR_DDCD) + port->icount.dcd++; + if (newMSR & UART_MSR_TERI) + port->icount.rng++; + + wake_up_interruptible(&port->port.delta_msr_wait); + } +} + +static void qt2_update_lsr(struct usb_serial_port *port, unsigned char *ch) +{ + struct qt2_port_private *port_priv; + struct async_icount *icount; + unsigned long flags; + u8 newLSR = (u8) *ch; + + port_priv = usb_get_serial_port_data(port); + + if (newLSR & UART_LSR_BI) + newLSR &= (u8) (UART_LSR_OE | UART_LSR_BI); + + spin_lock_irqsave(&port_priv->lock, flags); + port_priv->shadowLSR = newLSR; + spin_unlock_irqrestore(&port_priv->lock, flags); + + icount = &port->icount; + + if (newLSR & UART_LSR_BRK_ERROR_BITS) { + + if (newLSR & UART_LSR_BI) + icount->brk++; + + if (newLSR & UART_LSR_OE) + icount->overrun++; + + if (newLSR & UART_LSR_PE) + icount->parity++; + + if (newLSR & UART_LSR_FE) + icount->frame++; + } + +} + +static int qt2_write_room(struct tty_struct *tty) +{ + struct usb_serial_port *port = tty->driver_data; + struct qt2_port_private *port_priv; + unsigned long flags = 0; + int r; + + port_priv = usb_get_serial_port_data(port); + + spin_lock_irqsave(&port_priv->urb_lock, flags); + + if (port_priv->urb_in_use) + r = 0; + else + r = QT2_WRITE_BUFFER_SIZE - QT2_WRITE_CONTROL_SIZE; + + spin_unlock_irqrestore(&port_priv->urb_lock, flags); + + return r; +} + +static int qt2_write(struct tty_struct *tty, + struct usb_serial_port *port, + const unsigned char *buf, int count) +{ + struct qt2_port_private *port_priv; + struct urb *write_urb; + unsigned char *data; + unsigned long flags; + int status; + int bytes_out = 0; + + port_priv = usb_get_serial_port_data(port); + + if (port_priv->write_urb == NULL) { + dev_err(&port->dev, "%s - no output urb\n", __func__); + return 0; + } + write_urb = port_priv->write_urb; + + count = min(count, QT2_WRITE_BUFFER_SIZE - QT2_WRITE_CONTROL_SIZE); + + data = write_urb->transfer_buffer; + spin_lock_irqsave(&port_priv->urb_lock, flags); + if (port_priv->urb_in_use == true) { + dev_err(&port->dev, "qt2_write - urb is in use\n"); + goto write_out; + } + + *data++ = QT2_CONTROL_BYTE; + *data++ = QT2_CONTROL_BYTE; + *data++ = port_priv->device_port; + put_unaligned_le16(count, data); + data += 2; + memcpy(data, buf, count); + + write_urb->transfer_buffer_length = count + QT2_WRITE_CONTROL_SIZE; + + status = usb_submit_urb(write_urb, GFP_ATOMIC); + if (status == 0) { + port_priv->urb_in_use = true; + bytes_out += count; + } + +write_out: + spin_unlock_irqrestore(&port_priv->urb_lock, flags); + return bytes_out; +} + + +static struct usb_serial_driver qt2_device = { + .driver = { + .owner = THIS_MODULE, + .name = "quatech-serial", + }, + .description = DRIVER_DESC, + .id_table = id_table, + .open = qt2_open, + .close = qt2_close, + .write = qt2_write, + .write_room = qt2_write_room, + .calc_num_ports = qt2_calc_num_ports, + .attach = qt2_attach, + .release = qt2_release, + .disconnect = qt2_disconnect, + .port_probe = qt2_port_probe, + .port_remove = qt2_port_remove, + .dtr_rts = qt2_dtr_rts, + .break_ctl = qt2_break_ctl, + .tiocmget = qt2_tiocmget, + .tiocmset = qt2_tiocmset, + .tiocmiwait = usb_serial_generic_tiocmiwait, + .get_icount = usb_serial_generic_get_icount, + .ioctl = qt2_ioctl, + .set_termios = qt2_set_termios, +}; + +static struct usb_serial_driver *const serial_drivers[] = { + &qt2_device, NULL +}; + +module_usb_serial_driver(serial_drivers, id_table); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c index a36e2313eed..b2dff0f1474 100644 --- a/drivers/usb/serial/safe_serial.c +++ b/drivers/usb/serial/safe_serial.c @@ -62,11 +62,11 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/kernel.h> #include <linux/errno.h> #include <linux/gfp.h> -#include <linux/init.h> #include <linux/tty.h> #include <linux/tty_driver.h> #include <linux/tty_flip.h> @@ -81,11 +81,9 @@ #define CONFIG_USB_SERIAL_SAFE_PADDED 0 #endif -static int debug; -static int safe = 1; -static int padded = CONFIG_USB_SERIAL_SAFE_PADDED; +static bool safe = 1; +static bool padded = CONFIG_USB_SERIAL_SAFE_PADDED; -#define DRIVER_VERSION "v0.1" #define DRIVER_AUTHOR "sl@lineo.com, tbr@lineo.com, Johan Hovold <jhovold@gmail.com>" #define DRIVER_DESC "USB Safe Encapsulated Serial" @@ -93,16 +91,6 @@ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); -static __u16 vendor; /* no default */ -static __u16 product; /* no default */ -module_param(vendor, ushort, 0); -MODULE_PARM_DESC(vendor, "User specified USB idVendor (required)"); -module_param(product, ushort, 0); -MODULE_PARM_DESC(product, "User specified USB idProduct (required)"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); - module_param(safe, bool, 0); MODULE_PARM_DESC(safe, "Turn Safe Encapsulation On/Off"); @@ -136,7 +124,7 @@ MODULE_PARM_DESC(padded, "Pad to full wMaxPacketSize On/Off"); .bInterfaceClass = (ic), \ .bInterfaceSubClass = (isc), -static struct usb_device_id id_table[] = { +static const struct usb_device_id id_table[] = { {MY_USB_DEVICE(0x49f, 0xffff, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, /* Itsy */ {MY_USB_DEVICE(0x3f0, 0x2101, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, /* Calypso */ {MY_USB_DEVICE(0x4dd, 0x8001, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, /* Iris */ @@ -144,21 +132,11 @@ static struct usb_device_id id_table[] = { {MY_USB_DEVICE(0x4dd, 0x8003, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, /* Collie */ {MY_USB_DEVICE(0x4dd, 0x8004, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, /* Collie */ {MY_USB_DEVICE(0x5f9, 0xffff, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, /* Sharp tmp */ - /* extra null entry for module vendor/produc parameters */ - {MY_USB_DEVICE(0, 0, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, {} /* terminating entry */ }; MODULE_DEVICE_TABLE(usb, id_table); -static struct usb_driver safe_driver = { - .name = "safe_serial", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, - .no_dynamic_id = 1, -}; - static const __u16 crc10_table[256] = { 0x000, 0x233, 0x255, 0x066, 0x299, 0x0aa, 0x0cc, 0x2ff, 0x301, 0x132, 0x154, 0x367, 0x198, 0x3ab, 0x3cd, 0x1fe, @@ -219,38 +197,31 @@ static void safe_process_read_urb(struct urb *urb) unsigned char *data = urb->transfer_buffer; unsigned char length = urb->actual_length; int actual_length; - struct tty_struct *tty; __u16 fcs; if (!length) return; - tty = tty_port_tty_get(&port->port); - if (!tty) - return; - if (!safe) goto out; fcs = fcs_compute10(data, length, CRC10_INITFCS); if (fcs) { dev_err(&port->dev, "%s - bad CRC %x\n", __func__, fcs); - goto err; + return; } actual_length = data[length - 2] >> 2; if (actual_length > (length - 2)) { dev_err(&port->dev, "%s - inconsistent lengths %d:%d\n", __func__, actual_length, length); - goto err; + return; } dev_info(&urb->dev->dev, "%s - actual: %d\n", __func__, actual_length); length = actual_length; out: - tty_insert_flip_string(tty, data, length); - tty_flip_buffer_push(tty); -err: - tty_kref_put(tty); + tty_insert_flip_string(&port->port, data, length); + tty_flip_buffer_push(&port->port); } static int safe_prepare_write_buffer(struct usb_serial_port *port, @@ -291,7 +262,19 @@ static int safe_prepare_write_buffer(struct usb_serial_port *port, static int safe_startup(struct usb_serial *serial) { - switch (serial->interface->cur_altsetting->desc.bInterfaceProtocol) { + struct usb_interface_descriptor *desc; + + if (serial->dev->descriptor.bDeviceClass != CDC_DEVICE_CLASS) + return -ENODEV; + + desc = &serial->interface->cur_altsetting->desc; + + if (desc->bInterfaceClass != LINEO_INTERFACE_CLASS) + return -ENODEV; + if (desc->bInterfaceSubClass != LINEO_INTERFACE_SUBCLASS_SAFESERIAL) + return -ENODEV; + + switch (desc->bInterfaceProtocol) { case LINEO_SAFESERIAL_CRC: break; case LINEO_SAFESERIAL_CRC_PADDED: @@ -309,53 +292,14 @@ static struct usb_serial_driver safe_device = { .name = "safe_serial", }, .id_table = id_table, - .usb_driver = &safe_driver, .num_ports = 1, .process_read_urb = safe_process_read_urb, .prepare_write_buffer = safe_prepare_write_buffer, .attach = safe_startup, }; -static int __init safe_init(void) -{ - int i, retval; - - printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" - DRIVER_DESC "\n"); - - /* if we have vendor / product parameters patch them into id list */ - if (vendor || product) { - printk(KERN_INFO KBUILD_MODNAME ": vendor: %x product: %x\n", - vendor, product); - - for (i = 0; i < ARRAY_SIZE(id_table); i++) { - if (!id_table[i].idVendor && !id_table[i].idProduct) { - id_table[i].idVendor = vendor; - id_table[i].idProduct = product; - break; - } - } - } - - retval = usb_serial_register(&safe_device); - if (retval) - goto failed_usb_serial_register; - retval = usb_register(&safe_driver); - if (retval) - goto failed_usb_register; - - return 0; -failed_usb_register: - usb_serial_deregister(&safe_device); -failed_usb_serial_register: - return retval; -} - -static void __exit safe_exit(void) -{ - usb_deregister(&safe_driver); - usb_serial_deregister(&safe_device); -} +static struct usb_serial_driver * const serial_drivers[] = { + &safe_device, NULL +}; -module_init(safe_init); -module_exit(safe_exit); +module_usb_serial_driver(serial_drivers, id_table); diff --git a/drivers/usb/serial/sam-ba.c b/drivers/usb/serial/sam-ba.c deleted file mode 100644 index e3bba64afc5..00000000000 --- a/drivers/usb/serial/sam-ba.c +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Atmel SAM Boot Assistant (SAM-BA) driver - * - * Copyright (C) 2010 Johan Hovold <jhovold@gmail.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - */ - -#include <linux/kernel.h> -#include <linux/tty.h> -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/usb.h> -#include <linux/usb/serial.h> - - -#define DRIVER_VERSION "v1.0" -#define DRIVER_AUTHOR "Johan Hovold <jhovold@gmail.com>" -#define DRIVER_DESC "Atmel SAM Boot Assistant (SAM-BA) driver" - -#define SAMBA_VENDOR_ID 0x3eb -#define SAMBA_PRODUCT_ID 0x6124 - - -static int debug; - -static const struct usb_device_id id_table[] = { - /* - * NOTE: Only match the CDC Data interface. - */ - { USB_DEVICE_AND_INTERFACE_INFO(SAMBA_VENDOR_ID, SAMBA_PRODUCT_ID, - USB_CLASS_CDC_DATA, 0, 0) }, - { } -}; -MODULE_DEVICE_TABLE(usb, id_table); - -static struct usb_driver samba_driver = { - .name = "sam-ba", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, - .no_dynamic_id = 1, -}; - - -/* - * NOTE: The SAM-BA firmware cannot handle merged write requests so we cannot - * use the generic write implementation (which uses the port write fifo). - */ -static int samba_write(struct tty_struct *tty, struct usb_serial_port *port, - const unsigned char *buf, int count) -{ - struct urb *urb; - unsigned long flags; - int result; - int i; - - if (!count) - return 0; - - count = min_t(int, count, port->bulk_out_size); - - spin_lock_irqsave(&port->lock, flags); - if (!port->write_urbs_free) { - spin_unlock_irqrestore(&port->lock, flags); - return 0; - } - i = find_first_bit(&port->write_urbs_free, - ARRAY_SIZE(port->write_urbs)); - __clear_bit(i, &port->write_urbs_free); - port->tx_bytes += count; - spin_unlock_irqrestore(&port->lock, flags); - - urb = port->write_urbs[i]; - memcpy(urb->transfer_buffer, buf, count); - urb->transfer_buffer_length = count; - usb_serial_debug_data(debug, &port->dev, __func__, count, - urb->transfer_buffer); - result = usb_submit_urb(urb, GFP_ATOMIC); - if (result) { - dev_err(&port->dev, "%s - error submitting urb: %d\n", - __func__, result); - spin_lock_irqsave(&port->lock, flags); - __set_bit(i, &port->write_urbs_free); - port->tx_bytes -= count; - spin_unlock_irqrestore(&port->lock, flags); - - return result; - } - - return count; -} - -static int samba_write_room(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - unsigned long flags; - unsigned long free; - int count; - int room; - - spin_lock_irqsave(&port->lock, flags); - free = port->write_urbs_free; - spin_unlock_irqrestore(&port->lock, flags); - - count = hweight_long(free); - room = count * port->bulk_out_size; - - dbg("%s - returns %d", __func__, room); - - return room; -} - -static int samba_chars_in_buffer(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - unsigned long flags; - int chars; - - spin_lock_irqsave(&port->lock, flags); - chars = port->tx_bytes; - spin_unlock_irqrestore(&port->lock, flags); - - dbg("%s - returns %d", __func__, chars); - - return chars; -} - -static void samba_write_bulk_callback(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - unsigned long flags; - int i; - - dbg("%s - port %d", __func__, port->number); - - for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) { - if (port->write_urbs[i] == urb) - break; - } - spin_lock_irqsave(&port->lock, flags); - __set_bit(i, &port->write_urbs_free); - port->tx_bytes -= urb->transfer_buffer_length; - spin_unlock_irqrestore(&port->lock, flags); - - if (urb->status) - dbg("%s - non-zero urb status: %d", __func__, urb->status); - - usb_serial_port_softint(port); -} - -static struct usb_serial_driver samba_device = { - .driver = { - .owner = THIS_MODULE, - .name = "sam-ba", - }, - .usb_driver = &samba_driver, - .id_table = id_table, - .num_ports = 1, - .bulk_in_size = 512, - .bulk_out_size = 2048, - .write = samba_write, - .write_room = samba_write_room, - .chars_in_buffer = samba_chars_in_buffer, - .write_bulk_callback = samba_write_bulk_callback, - .throttle = usb_serial_generic_throttle, - .unthrottle = usb_serial_generic_unthrottle, -}; - -static int __init samba_init(void) -{ - int retval; - - retval = usb_serial_register(&samba_device); - if (retval) - return retval; - - retval = usb_register(&samba_driver); - if (retval) { - usb_serial_deregister(&samba_device); - return retval; - } - - printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ": " - DRIVER_DESC "\n"); - return 0; -} - -static void __exit samba_exit(void) -{ - usb_deregister(&samba_driver); - usb_serial_deregister(&samba_device); -} - -module_init(samba_init); -module_exit(samba_exit); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_VERSION(DRIVER_VERSION); -MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Enable verbose debugging messages"); diff --git a/drivers/usb/serial/siemens_mpi.c b/drivers/usb/serial/siemens_mpi.c deleted file mode 100644 index cb8195cabfd..00000000000 --- a/drivers/usb/serial/siemens_mpi.c +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Siemens USB-MPI Serial USB driver - * - * Copyright (C) 2005 Thomas Hergenhahn <thomas.hergenhahn@suse.de> - * Copyright (C) 2005,2008 Greg Kroah-Hartman <gregkh@suse.de> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - */ - -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/tty.h> -#include <linux/module.h> -#include <linux/usb.h> -#include <linux/usb/serial.h> - -/* Version Information */ -#define DRIVER_VERSION "Version 0.1 09/26/2005" -#define DRIVER_AUTHOR "Thomas Hergenhahn@web.de http://libnodave.sf.net" -#define DRIVER_DESC "Driver for Siemens USB/MPI adapter" - - -static const struct usb_device_id id_table[] = { - /* Vendor and product id for 6ES7-972-0CB20-0XA0 */ - { USB_DEVICE(0x908, 0x0004) }, - { }, -}; -MODULE_DEVICE_TABLE(usb, id_table); - -static struct usb_driver siemens_usb_mpi_driver = { - .name = "siemens_mpi", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - -static struct usb_serial_driver siemens_usb_mpi_device = { - .driver = { - .owner = THIS_MODULE, - .name = "siemens_mpi", - }, - .id_table = id_table, - .num_ports = 1, -}; - -static int __init siemens_usb_mpi_init(void) -{ - int retval; - - retval = usb_serial_register(&siemens_usb_mpi_device); - if (retval) - goto failed_usb_serial_register; - retval = usb_register(&siemens_usb_mpi_driver); - if (retval) - goto failed_usb_register; - printk(KERN_INFO DRIVER_DESC "\n"); - printk(KERN_INFO DRIVER_VERSION " " DRIVER_AUTHOR "\n"); - return retval; -failed_usb_register: - usb_serial_deregister(&siemens_usb_mpi_device); -failed_usb_serial_register: - return retval; -} - -static void __exit siemens_usb_mpi_exit(void) -{ - usb_deregister(&siemens_usb_mpi_driver); - usb_serial_deregister(&siemens_usb_mpi_device); -} - -module_init(siemens_usb_mpi_init); -module_exit(siemens_usb_mpi_exit); -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index 7481ff8a49e..6f7f01eb556 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c @@ -18,7 +18,7 @@ */ /* Uncomment to log function calls */ /* #define DEBUG */ -#define DRIVER_VERSION "v.1.7.16" + #define DRIVER_AUTHOR "Kevin Lloyd, Elina Pasheva, Matthew Safar, Rory Filer" #define DRIVER_DESC "USB Driver for Sierra Wireless USB modems" @@ -46,8 +46,7 @@ allocations > PAGE_SIZE and the number of packets in a page is an integer 512 is the largest possible packet on EHCI */ -static int debug; -static int nmea; +static bool nmea; /* Used in interface blacklisting */ struct sierra_iface_info { @@ -59,13 +58,12 @@ struct sierra_intf_private { spinlock_t susp_lock; unsigned int suspended:1; int in_flight; + unsigned int open_ports; }; static int sierra_set_power_state(struct usb_device *udev, __u16 swiState) { - int result; - dev_dbg(&udev->dev, "%s\n", __func__); - result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), SWIMS_USB_REQUEST_SetPower, /* __u8 request */ USB_TYPE_VENDOR, /* __u8 request type */ swiState, /* __u16 value */ @@ -73,14 +71,11 @@ static int sierra_set_power_state(struct usb_device *udev, __u16 swiState) NULL, /* void *data */ 0, /* __u16 size */ USB_CTRL_SET_TIMEOUT); /* int timeout */ - return result; } static int sierra_vsc_set_nmea(struct usb_device *udev, __u16 enable) { - int result; - dev_dbg(&udev->dev, "%s\n", __func__); - result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), SWIMS_USB_REQUEST_SetNmea, /* __u8 request */ USB_TYPE_VENDOR, /* __u8 request type */ enable, /* __u16 value */ @@ -88,7 +83,6 @@ static int sierra_vsc_set_nmea(struct usb_device *udev, __u16 enable) NULL, /* void *data */ 0, /* __u16 size */ USB_CTRL_SET_TIMEOUT); /* int timeout */ - return result; } static int sierra_calc_num_ports(struct usb_serial *serial) @@ -96,8 +90,6 @@ static int sierra_calc_num_ports(struct usb_serial *serial) int num_ports = 0; u8 ifnum, numendpoints; - dev_dbg(&serial->dev->dev, "%s\n", __func__); - ifnum = serial->interface->cur_altsetting->desc.bInterfaceNumber; numendpoints = serial->interface->cur_altsetting->desc.bNumEndpoints; @@ -150,7 +142,6 @@ static int sierra_calc_interface(struct usb_serial *serial) int interface; struct usb_interface *p_interface; struct usb_host_interface *p_host_interface; - dev_dbg(&serial->dev->dev, "%s\n", __func__); /* Get the interface structure pointer from the serial struct */ p_interface = serial->interface; @@ -171,13 +162,11 @@ static int sierra_probe(struct usb_serial *serial, { int result = 0; struct usb_device *udev; - struct sierra_intf_private *data; u8 ifnum; udev = serial->dev; - dev_dbg(&udev->dev, "%s\n", __func__); - ifnum = sierra_calc_interface(serial); + /* * If this interface supports more than 1 alternate * select the 2nd one @@ -199,11 +188,6 @@ static int sierra_probe(struct usb_serial *serial, return -ENODEV; } - data = serial->private = kzalloc(sizeof(struct sierra_intf_private), GFP_KERNEL); - if (!data) - return -ENOMEM; - spin_lock_init(&data->susp_lock); - return result; } @@ -221,7 +205,7 @@ static const struct sierra_iface_info typeB_interface_list = { }; /* 'blacklist' of interfaces not served by this driver */ -static const u8 direct_ip_non_serial_ifaces[] = { 7, 8, 9, 10, 11 }; +static const u8 direct_ip_non_serial_ifaces[] = { 7, 8, 9, 10, 11, 19, 20 }; static const struct sierra_iface_info direct_ip_interface_blacklist = { .infolen = ARRAY_SIZE(direct_ip_non_serial_ifaces), .ifaceinfo = direct_ip_non_serial_ifaces, @@ -301,7 +285,13 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x1199, 0x68A3), /* Sierra Wireless Direct IP modems */ .driver_info = (kernel_ulong_t)&direct_ip_interface_blacklist }, - { USB_DEVICE(0x413C, 0x08133) }, /* Dell Computer Corp. Wireless 5720 VZW Mobile Broadband (EVDO Rev-A) Minicard GPS Port */ + /* AT&T Direct IP LTE modems */ + { USB_DEVICE_AND_INTERFACE_INFO(0x0F3D, 0x68AA, 0xFF, 0xFF, 0xFF), + .driver_info = (kernel_ulong_t)&direct_ip_interface_blacklist + }, + { USB_DEVICE(0x0f3d, 0x68A3), /* Airprime/Sierra Wireless Direct IP modems */ + .driver_info = (kernel_ulong_t)&direct_ip_interface_blacklist + }, { } }; @@ -326,7 +316,6 @@ struct sierra_port_private { int dsr_state; int dcd_state; int ri_state; - unsigned int opened:1; }; static int sierra_send_setup(struct usb_serial_port *port) @@ -338,8 +327,6 @@ static int sierra_send_setup(struct usb_serial_port *port) int do_send = 0; int retval; - dev_dbg(&port->dev, "%s\n", __func__); - portdata = usb_get_serial_port_data(port); if (portdata->dtr_state) @@ -373,29 +360,23 @@ static int sierra_send_setup(struct usb_serial_port *port) if (!do_send) return 0; - usb_autopm_get_interface(serial->interface); - retval = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), + retval = usb_autopm_get_interface(serial->interface); + if (retval < 0) + return retval; + + retval = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), 0x22, 0x21, val, interface, NULL, 0, USB_CTRL_SET_TIMEOUT); usb_autopm_put_interface(serial->interface); return retval; } -static void sierra_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old_termios) -{ - dev_dbg(&port->dev, "%s\n", __func__); - tty_termios_copy_hw(tty->termios, old_termios); - sierra_send_setup(port); -} - -static int sierra_tiocmget(struct tty_struct *tty, struct file *file) +static int sierra_tiocmget(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; unsigned int value; struct sierra_port_private *portdata; - dev_dbg(&port->dev, "%s\n", __func__); portdata = usb_get_serial_port_data(port); value = ((portdata->rts_state) ? TIOCM_RTS : 0) | @@ -408,7 +389,7 @@ static int sierra_tiocmget(struct tty_struct *tty, struct file *file) return value; } -static int sierra_tiocmset(struct tty_struct *tty, struct file *file, +static int sierra_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) { struct usb_serial_port *port = tty->driver_data; @@ -430,10 +411,7 @@ static int sierra_tiocmset(struct tty_struct *tty, struct file *file, static void sierra_release_urb(struct urb *urb) { - struct usb_serial_port *port; if (urb) { - port = urb->context; - dev_dbg(&port->dev, "%s: %p\n", __func__, urb); kfree(urb->transfer_buffer); usb_free_urb(urb); } @@ -446,8 +424,7 @@ static void sierra_outdat_callback(struct urb *urb) struct sierra_intf_private *intfdata; int status = urb->status; - dev_dbg(&port->dev, "%s - port %d\n", __func__, port->number); - intfdata = port->serial->private; + intfdata = usb_get_serial_data(port->serial); /* free up the transfer buffer, as usb_free_urb() does not do this */ kfree(urb->transfer_buffer); @@ -484,7 +461,7 @@ static int sierra_write(struct tty_struct *tty, struct usb_serial_port *port, return 0; portdata = usb_get_serial_port_data(port); - intfdata = serial->private; + intfdata = usb_get_serial_data(serial); dev_dbg(&port->dev, "%s: write (%zd bytes)\n", __func__, writesize); spin_lock_irqsave(&portdata->lock, flags); @@ -510,21 +487,19 @@ static int sierra_write(struct tty_struct *tty, struct usb_serial_port *port, buffer = kmalloc(writesize, GFP_ATOMIC); if (!buffer) { - dev_err(&port->dev, "out of memory\n"); retval = -ENOMEM; goto error_no_buffer; } urb = usb_alloc_urb(0, GFP_ATOMIC); if (!urb) { - dev_err(&port->dev, "no more free urbs\n"); retval = -ENOMEM; goto error_no_urb; } memcpy(buffer, buf, writesize); - usb_serial_debug_data(debug, &port->dev, __func__, writesize, buffer); + usb_serial_debug_data(&port->dev, __func__, writesize, buffer); usb_fill_bulk_urb(urb, serial->dev, usb_sndbulkpipe(serial->dev, @@ -582,30 +557,23 @@ static void sierra_indat_callback(struct urb *urb) int err; int endpoint; struct usb_serial_port *port; - struct tty_struct *tty; unsigned char *data = urb->transfer_buffer; int status = urb->status; endpoint = usb_pipeendpoint(urb->pipe); port = urb->context; - dev_dbg(&port->dev, "%s: %p\n", __func__, urb); - if (status) { dev_dbg(&port->dev, "%s: nonzero status: %d on" " endpoint %02x\n", __func__, status, endpoint); } else { if (urb->actual_length) { - tty = tty_port_tty_get(&port->port); - if (tty) { - tty_insert_flip_string(tty, data, - urb->actual_length); - tty_flip_buffer_push(tty); - - tty_kref_put(tty); - usb_serial_debug_data(debug, &port->dev, - __func__, urb->actual_length, data); - } + tty_insert_flip_string(&port->port, data, + urb->actual_length); + tty_flip_buffer_push(&port->port); + + usb_serial_debug_data(&port->dev, __func__, + urb->actual_length, data); } else { dev_dbg(&port->dev, "%s: empty read urb" " received\n", __func__); @@ -648,7 +616,6 @@ static void sierra_instat_callback(struct urb *urb) unsigned char signals = *((unsigned char *) urb->transfer_buffer + sizeof(struct usb_ctrlrequest)); - struct tty_struct *tty; dev_dbg(&port->dev, "%s: signal x%x\n", __func__, signals); @@ -659,11 +626,8 @@ static void sierra_instat_callback(struct urb *urb) portdata->dsr_state = ((signals & 0x02) ? 1 : 0); portdata->ri_state = ((signals & 0x08) ? 1 : 0); - tty = tty_port_tty_get(&port->port); - if (tty && !C_CLOCAL(tty) && - old_dcd_state && !portdata->dcd_state) - tty_hangup(tty); - tty_kref_put(tty); + if (old_dcd_state && !portdata->dcd_state) + tty_port_tty_hangup(&port->port, true); } else { dev_dbg(&port->dev, "%s: type %x req %x\n", __func__, req_pkt->bRequestType, @@ -675,7 +639,6 @@ static void sierra_instat_callback(struct urb *urb) /* Resubmit urb so we continue receiving IRQ data */ if (status != -ESHUTDOWN && status != -ENOENT) { usb_mark_last_busy(serial->dev); - urb->dev = serial->dev; err = usb_submit_urb(urb, GFP_ATOMIC); if (err && err != -EPERM) dev_err(&port->dev, "%s: resubmit intr urb " @@ -689,8 +652,6 @@ static int sierra_write_room(struct tty_struct *tty) struct sierra_port_private *portdata = usb_get_serial_port_data(port); unsigned long flags; - dev_dbg(&port->dev, "%s - port %d\n", __func__, port->number); - /* try to give a good number back based on if we have any free urbs at * this point in time */ spin_lock_irqsave(&portdata->lock, flags); @@ -704,6 +665,23 @@ static int sierra_write_room(struct tty_struct *tty) return 2048; } +static int sierra_chars_in_buffer(struct tty_struct *tty) +{ + struct usb_serial_port *port = tty->driver_data; + struct sierra_port_private *portdata = usb_get_serial_port_data(port); + unsigned long flags; + int chars; + + /* NOTE: This overcounts somewhat. */ + spin_lock_irqsave(&portdata->lock, flags); + chars = portdata->outstanding_urbs * MAX_TRANSFER; + spin_unlock_irqrestore(&portdata->lock, flags); + + dev_dbg(&port->dev, "%s - %d\n", __func__, chars); + + return chars; +} + static void sierra_stop_rx_urbs(struct usb_serial_port *port) { int i; @@ -759,15 +737,9 @@ static struct urb *sierra_setup_urb(struct usb_serial *serial, int endpoint, struct urb *urb; u8 *buf; - if (endpoint == -1) - return NULL; - urb = usb_alloc_urb(0, mem_flags); - if (urb == NULL) { - dev_dbg(&serial->dev->dev, "%s: alloc for endpoint %d failed\n", - __func__, endpoint); + if (!urb) return NULL; - } buf = kmalloc(len, mem_flags); if (buf) { @@ -776,13 +748,9 @@ static struct urb *sierra_setup_urb(struct usb_serial *serial, int endpoint, usb_sndbulkpipe(serial->dev, endpoint) | dir, buf, len, callback, ctx); - /* debug */ dev_dbg(&serial->dev->dev, "%s %c u : %p d:%p\n", __func__, dir == USB_DIR_IN ? 'i' : 'o', urb, buf); } else { - dev_dbg(&serial->dev->dev, "%s %c u:%p d:%p\n", __func__, - dir == USB_DIR_IN ? 'i' : 'o', urb, buf); - sierra_release_urb(urb); urb = NULL; } @@ -795,43 +763,48 @@ static void sierra_close(struct usb_serial_port *port) int i; struct usb_serial *serial = port->serial; struct sierra_port_private *portdata; - struct sierra_intf_private *intfdata = port->serial->private; - + struct sierra_intf_private *intfdata = usb_get_serial_data(serial); + struct urb *urb; - dev_dbg(&port->dev, "%s\n", __func__); portdata = usb_get_serial_port_data(port); - portdata->rts_state = 0; - portdata->dtr_state = 0; + /* + * Need to take susp_lock to make sure port is not already being + * resumed, but no need to hold it due to ASYNC_INITIALIZED. + */ + spin_lock_irq(&intfdata->susp_lock); + if (--intfdata->open_ports == 0) + serial->interface->needs_remote_wakeup = 0; + spin_unlock_irq(&intfdata->susp_lock); - if (serial->dev) { - mutex_lock(&serial->disc_mutex); - if (!serial->disconnected) { - serial->interface->needs_remote_wakeup = 0; - usb_autopm_get_interface(serial->interface); - sierra_send_setup(port); - } - mutex_unlock(&serial->disc_mutex); - spin_lock_irq(&intfdata->susp_lock); - portdata->opened = 0; - spin_unlock_irq(&intfdata->susp_lock); + for (;;) { + urb = usb_get_from_anchor(&portdata->delayed); + if (!urb) + break; + kfree(urb->transfer_buffer); + usb_free_urb(urb); + usb_autopm_put_interface_async(serial->interface); + spin_lock(&portdata->lock); + portdata->outstanding_urbs--; + spin_unlock(&portdata->lock); + } + sierra_stop_rx_urbs(port); + usb_kill_anchored_urbs(&portdata->active); - /* Stop reading urbs */ - sierra_stop_rx_urbs(port); - /* .. and release them */ - for (i = 0; i < portdata->num_in_urbs; i++) { - sierra_release_urb(portdata->in_urbs[i]); - portdata->in_urbs[i] = NULL; - } + for (i = 0; i < portdata->num_in_urbs; i++) { + sierra_release_urb(portdata->in_urbs[i]); + portdata->in_urbs[i] = NULL; } + + usb_autopm_get_interface_no_resume(serial->interface); } static int sierra_open(struct tty_struct *tty, struct usb_serial_port *port) { struct sierra_port_private *portdata; struct usb_serial *serial = port->serial; - struct sierra_intf_private *intfdata = serial->private; + struct sierra_intf_private *intfdata = usb_get_serial_data(serial); int i; int err; int endpoint; @@ -839,13 +812,6 @@ static int sierra_open(struct tty_struct *tty, struct usb_serial_port *port) portdata = usb_get_serial_port_data(port); - dev_dbg(&port->dev, "%s\n", __func__); - - /* Set some sane defaults */ - portdata->rts_state = 1; - portdata->dtr_state = 1; - - endpoint = port->bulk_in_endpointAddress; for (i = 0; i < portdata->num_in_urbs; i++) { urb = sierra_setup_urb(serial, endpoint, USB_DIR_IN, port, @@ -858,51 +824,51 @@ static int sierra_open(struct tty_struct *tty, struct usb_serial_port *port) usb_sndbulkpipe(serial->dev, endpoint) | USB_DIR_IN); err = sierra_submit_rx_urbs(port, GFP_KERNEL); - if (err) { - /* get rid of everything as in close */ - sierra_close(port); - /* restore balance for autopm */ - usb_autopm_put_interface(serial->interface); - return err; - } - sierra_send_setup(port); + if (err) + goto err_submit; - serial->interface->needs_remote_wakeup = 1; spin_lock_irq(&intfdata->susp_lock); - portdata->opened = 1; + if (++intfdata->open_ports == 1) + serial->interface->needs_remote_wakeup = 1; spin_unlock_irq(&intfdata->susp_lock); usb_autopm_put_interface(serial->interface); return 0; + +err_submit: + sierra_stop_rx_urbs(port); + + for (i = 0; i < portdata->num_in_urbs; i++) { + sierra_release_urb(portdata->in_urbs[i]); + portdata->in_urbs[i] = NULL; + } + + return err; } static void sierra_dtr_rts(struct usb_serial_port *port, int on) { - struct usb_serial *serial = port->serial; struct sierra_port_private *portdata; portdata = usb_get_serial_port_data(port); portdata->rts_state = on; portdata->dtr_state = on; - if (serial->dev) { - mutex_lock(&serial->disc_mutex); - if (!serial->disconnected) - sierra_send_setup(port); - mutex_unlock(&serial->disc_mutex); - } + sierra_send_setup(port); } static int sierra_startup(struct usb_serial *serial) { - struct usb_serial_port *port; - struct sierra_port_private *portdata; - struct sierra_iface_info *himemoryp = NULL; - int i; - u8 ifnum; + struct sierra_intf_private *intfdata; - dev_dbg(&serial->dev->dev, "%s\n", __func__); + intfdata = kzalloc(sizeof(*intfdata), GFP_KERNEL); + if (!intfdata) + return -ENOMEM; + + spin_lock_init(&intfdata->susp_lock); + + usb_set_serial_data(serial, intfdata); /* Set Device mode to D0 */ sierra_set_power_state(serial->dev, 0x0000); @@ -911,70 +877,72 @@ static int sierra_startup(struct usb_serial *serial) if (nmea) sierra_vsc_set_nmea(serial->dev, 1); - /* Now setup per port private data */ - for (i = 0; i < serial->num_ports; i++) { - port = serial->port[i]; - portdata = kzalloc(sizeof(*portdata), GFP_KERNEL); - if (!portdata) { - dev_dbg(&port->dev, "%s: kmalloc for " - "sierra_port_private (%d) failed!\n", - __func__, i); - return -ENOMEM; - } - spin_lock_init(&portdata->lock); - init_usb_anchor(&portdata->active); - init_usb_anchor(&portdata->delayed); - ifnum = i; - /* Assume low memory requirements */ - portdata->num_out_urbs = N_OUT_URB; - portdata->num_in_urbs = N_IN_URB; - - /* Determine actual memory requirements */ - if (serial->num_ports == 1) { - /* Get interface number for composite device */ - ifnum = sierra_calc_interface(serial); - himemoryp = - (struct sierra_iface_info *)&typeB_interface_list; - if (is_himemory(ifnum, himemoryp)) { - portdata->num_out_urbs = N_OUT_URB_HM; - portdata->num_in_urbs = N_IN_URB_HM; - } - } - else { - himemoryp = - (struct sierra_iface_info *)&typeA_interface_list; - if (is_himemory(i, himemoryp)) { - portdata->num_out_urbs = N_OUT_URB_HM; - portdata->num_in_urbs = N_IN_URB_HM; - } - } - dev_dbg(&serial->dev->dev, - "Memory usage (urbs) interface #%d, in=%d, out=%d\n", - ifnum,portdata->num_in_urbs, portdata->num_out_urbs ); - /* Set the port private data pointer */ - usb_set_serial_port_data(port, portdata); - } - return 0; } static void sierra_release(struct usb_serial *serial) { - int i; - struct usb_serial_port *port; + struct sierra_intf_private *intfdata; + + intfdata = usb_get_serial_data(serial); + kfree(intfdata); +} + +static int sierra_port_probe(struct usb_serial_port *port) +{ + struct usb_serial *serial = port->serial; struct sierra_port_private *portdata; + const struct sierra_iface_info *himemoryp; + u8 ifnum; - dev_dbg(&serial->dev->dev, "%s\n", __func__); + portdata = kzalloc(sizeof(*portdata), GFP_KERNEL); + if (!portdata) + return -ENOMEM; - for (i = 0; i < serial->num_ports; ++i) { - port = serial->port[i]; - if (!port) - continue; - portdata = usb_get_serial_port_data(port); - if (!portdata) - continue; - kfree(portdata); + spin_lock_init(&portdata->lock); + init_usb_anchor(&portdata->active); + init_usb_anchor(&portdata->delayed); + + /* Assume low memory requirements */ + portdata->num_out_urbs = N_OUT_URB; + portdata->num_in_urbs = N_IN_URB; + + /* Determine actual memory requirements */ + if (serial->num_ports == 1) { + /* Get interface number for composite device */ + ifnum = sierra_calc_interface(serial); + himemoryp = &typeB_interface_list; + } else { + /* This is really the usb-serial port number of the interface + * rather than the interface number. + */ + ifnum = port->port_number; + himemoryp = &typeA_interface_list; } + + if (is_himemory(ifnum, himemoryp)) { + portdata->num_out_urbs = N_OUT_URB_HM; + portdata->num_in_urbs = N_IN_URB_HM; + } + + dev_dbg(&port->dev, + "Memory usage (urbs) interface #%d, in=%d, out=%d\n", + ifnum, portdata->num_in_urbs, portdata->num_out_urbs); + + usb_set_serial_port_data(port, portdata); + + return 0; +} + +static int sierra_port_remove(struct usb_serial_port *port) +{ + struct sierra_port_private *portdata; + + portdata = usb_get_serial_port_data(port); + usb_set_serial_port_data(port, NULL); + kfree(portdata); + + return 0; } #ifdef CONFIG_PM @@ -988,6 +956,8 @@ static void stop_read_write_urbs(struct usb_serial *serial) for (i = 0; i < serial->num_ports; ++i) { port = serial->port[i]; portdata = usb_get_serial_port_data(port); + if (!portdata) + continue; sierra_stop_rx_urbs(port); usb_kill_anchored_urbs(&portdata->active); } @@ -995,58 +965,84 @@ static void stop_read_write_urbs(struct usb_serial *serial) static int sierra_suspend(struct usb_serial *serial, pm_message_t message) { - struct sierra_intf_private *intfdata; - int b; - - if (message.event & PM_EVENT_AUTO) { - intfdata = serial->private; - spin_lock_irq(&intfdata->susp_lock); - b = intfdata->in_flight; + struct sierra_intf_private *intfdata = usb_get_serial_data(serial); - if (b) { + spin_lock_irq(&intfdata->susp_lock); + if (PMSG_IS_AUTO(message)) { + if (intfdata->in_flight) { spin_unlock_irq(&intfdata->susp_lock); return -EBUSY; - } else { - intfdata->suspended = 1; - spin_unlock_irq(&intfdata->susp_lock); } } + intfdata->suspended = 1; + spin_unlock_irq(&intfdata->susp_lock); + stop_read_write_urbs(serial); return 0; } +/* Caller must hold susp_lock. */ +static int sierra_submit_delayed_urbs(struct usb_serial_port *port) +{ + struct sierra_port_private *portdata = usb_get_serial_port_data(port); + struct sierra_intf_private *intfdata; + struct urb *urb; + int ec = 0; + int err; + + intfdata = usb_get_serial_data(port->serial); + + for (;;) { + urb = usb_get_from_anchor(&portdata->delayed); + if (!urb) + break; + + usb_anchor_urb(urb, &portdata->active); + intfdata->in_flight++; + err = usb_submit_urb(urb, GFP_ATOMIC); + if (err) { + dev_err(&port->dev, "%s - submit urb failed: %d", + __func__, err); + ec++; + intfdata->in_flight--; + usb_unanchor_urb(urb); + kfree(urb->transfer_buffer); + usb_free_urb(urb); + + spin_lock(&portdata->lock); + portdata->outstanding_urbs--; + spin_unlock(&portdata->lock); + } + } + + if (ec) + return -EIO; + + return 0; +} + static int sierra_resume(struct usb_serial *serial) { struct usb_serial_port *port; - struct sierra_intf_private *intfdata = serial->private; - struct sierra_port_private *portdata; - struct urb *urb; + struct sierra_intf_private *intfdata = usb_get_serial_data(serial); int ec = 0; int i, err; spin_lock_irq(&intfdata->susp_lock); for (i = 0; i < serial->num_ports; i++) { port = serial->port[i]; - portdata = usb_get_serial_port_data(port); - while ((urb = usb_get_from_anchor(&portdata->delayed))) { - usb_anchor_urb(urb, &portdata->active); - intfdata->in_flight++; - err = usb_submit_urb(urb, GFP_ATOMIC); - if (err < 0) { - intfdata->in_flight--; - usb_unanchor_urb(urb); - usb_scuttle_anchored_urbs(&portdata->delayed); - break; - } - } + if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags)) + continue; - if (portdata->opened) { - err = sierra_submit_rx_urbs(port, GFP_ATOMIC); - if (err) - ec++; - } + err = sierra_submit_delayed_urbs(port); + if (err) + ec++; + + err = sierra_submit_rx_urbs(port, GFP_ATOMIC); + if (err) + ec++; } intfdata->suspended = 0; spin_unlock_irq(&intfdata->susp_lock); @@ -1054,30 +1050,11 @@ static int sierra_resume(struct usb_serial *serial) return ec ? -EIO : 0; } -static int sierra_reset_resume(struct usb_interface *intf) -{ - struct usb_serial *serial = usb_get_intfdata(intf); - dev_err(&serial->dev->dev, "%s\n", __func__); - return usb_serial_resume(intf); -} #else #define sierra_suspend NULL #define sierra_resume NULL -#define sierra_reset_resume NULL #endif -static struct usb_driver sierra_driver = { - .name = "sierra", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .suspend = usb_serial_suspend, - .resume = usb_serial_resume, - .reset_resume = sierra_reset_resume, - .id_table = id_table, - .no_dynamic_id = 1, - .supports_autosuspend = 1, -}; - static struct usb_serial_driver sierra_device = { .driver = { .owner = THIS_MODULE, @@ -1085,7 +1062,6 @@ static struct usb_serial_driver sierra_device = { }, .description = "Sierra USB modem", .id_table = id_table, - .usb_driver = &sierra_driver, .calc_num_ports = sierra_calc_num_ports, .probe = sierra_probe, .open = sierra_open, @@ -1093,56 +1069,27 @@ static struct usb_serial_driver sierra_device = { .dtr_rts = sierra_dtr_rts, .write = sierra_write, .write_room = sierra_write_room, - .set_termios = sierra_set_termios, + .chars_in_buffer = sierra_chars_in_buffer, .tiocmget = sierra_tiocmget, .tiocmset = sierra_tiocmset, .attach = sierra_startup, .release = sierra_release, + .port_probe = sierra_port_probe, + .port_remove = sierra_port_remove, .suspend = sierra_suspend, .resume = sierra_resume, .read_int_callback = sierra_instat_callback, }; -/* Functions used by new usb-serial code. */ -static int __init sierra_init(void) -{ - int retval; - retval = usb_serial_register(&sierra_device); - if (retval) - goto failed_device_register; - - - retval = usb_register(&sierra_driver); - if (retval) - goto failed_driver_register; - - printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" - DRIVER_DESC "\n"); - - return 0; - -failed_driver_register: - usb_serial_deregister(&sierra_device); -failed_device_register: - return retval; -} - -static void __exit sierra_exit(void) -{ - usb_deregister(&sierra_driver); - usb_serial_deregister(&sierra_device); -} +static struct usb_serial_driver * const serial_drivers[] = { + &sierra_device, NULL +}; -module_init(sierra_init); -module_exit(sierra_exit); +module_usb_serial_driver(serial_drivers, id_table); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_VERSION(DRIVER_VERSION); MODULE_LICENSE("GPL"); module_param(nmea, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(nmea, "NMEA streaming"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug messages"); diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c index 765aa983bf5..ef0dbf0703c 100644 --- a/drivers/usb/serial/spcp8x5.c +++ b/drivers/usb/serial/spcp8x5.c @@ -1,7 +1,7 @@ /* * spcp8x5 USB to serial adaptor driver * - * Copyright (C) 2010 Johan Hovold (jhovold@gmail.com) + * Copyright (C) 2010-2013 Johan Hovold (jhovold@gmail.com) * Copyright (C) 2006 Linxb (xubin.lin@worldplus.com.cn) * Copyright (C) 2006 S1 Corp. * @@ -13,12 +13,9 @@ * 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. - * - * */ #include <linux/kernel.h> #include <linux/errno.h> -#include <linux/init.h> #include <linux/slab.h> #include <linux/tty.h> #include <linux/tty_driver.h> @@ -28,12 +25,10 @@ #include <linux/usb.h> #include <linux/usb/serial.h> +#define DRIVER_DESC "SPCP8x5 USB to serial adaptor driver" -/* Version Information */ -#define DRIVER_VERSION "v0.10" -#define DRIVER_DESC "SPCP8x5 USB to serial adaptor driver" - -static int debug; +#define SPCP825_QUIRK_NO_UART_STATUS 0x01 +#define SPCP825_QUIRK_NO_WORK_MODE 0x02 #define SPCP8x5_007_VID 0x04FC #define SPCP8x5_007_PID 0x0201 @@ -51,13 +46,15 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(SPCP8x5_INTERMATIC_VID, SPCP8x5_INTERMATIC_PID)}, { USB_DEVICE(SPCP8x5_835_VID, SPCP8x5_835_PID)}, { USB_DEVICE(SPCP8x5_008_VID, SPCP8x5_008_PID)}, - { USB_DEVICE(SPCP8x5_007_VID, SPCP8x5_007_PID)}, + { USB_DEVICE(SPCP8x5_007_VID, SPCP8x5_007_PID), + .driver_info = SPCP825_QUIRK_NO_UART_STATUS | + SPCP825_QUIRK_NO_WORK_MODE }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, id_table); struct spcp8x5_usb_ctrl_arg { - u8 type; + u8 type; u8 cmd; u8 cmd_type; u16 value; @@ -133,7 +130,7 @@ struct spcp8x5_usb_ctrl_arg { /* how come ??? */ #define UART_STATE 0x08 -#define UART_STATE_TRANSIENT_MASK 0x74 +#define UART_STATE_TRANSIENT_MASK 0x75 #define UART_DCD 0x01 #define UART_DSR 0x02 #define UART_BREAK_ERROR 0x04 @@ -143,164 +140,122 @@ struct spcp8x5_usb_ctrl_arg { #define UART_OVERRUN_ERROR 0x40 #define UART_CTS 0x80 -enum spcp8x5_type { - SPCP825_007_TYPE, - SPCP825_008_TYPE, - SPCP825_PHILIP_TYPE, - SPCP825_INTERMATIC_TYPE, - SPCP835_TYPE, -}; - -static struct usb_driver spcp8x5_driver = { - .name = "spcp8x5", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, - .no_dynamic_id = 1, +struct spcp8x5_private { + unsigned quirks; + spinlock_t lock; + u8 line_control; }; +static int spcp8x5_probe(struct usb_serial *serial, + const struct usb_device_id *id) +{ + usb_set_serial_data(serial, (void *)id); -struct spcp8x5_private { - spinlock_t lock; - enum spcp8x5_type type; - wait_queue_head_t delta_msr_wait; - u8 line_control; - u8 line_status; -}; + return 0; +} -/* desc : when device plug in,this function would be called. - * thanks to usb_serial subsystem,then do almost every things for us. And what - * we should do just alloc the buffer */ -static int spcp8x5_startup(struct usb_serial *serial) +static int spcp8x5_port_probe(struct usb_serial_port *port) { + const struct usb_device_id *id = usb_get_serial_data(port->serial); struct spcp8x5_private *priv; - int i; - enum spcp8x5_type type = SPCP825_007_TYPE; - u16 product = le16_to_cpu(serial->dev->descriptor.idProduct); - - if (product == 0x0201) - type = SPCP825_007_TYPE; - else if (product == 0x0231) - type = SPCP835_TYPE; - else if (product == 0x0235) - type = SPCP825_008_TYPE; - else if (product == 0x0204) - type = SPCP825_INTERMATIC_TYPE; - else if (product == 0x0471 && - serial->dev->descriptor.idVendor == cpu_to_le16(0x081e)) - type = SPCP825_PHILIP_TYPE; - dev_dbg(&serial->dev->dev, "device type = %d\n", (int)type); - - for (i = 0; i < serial->num_ports; ++i) { - priv = kzalloc(sizeof(struct spcp8x5_private), GFP_KERNEL); - if (!priv) - goto cleanup; - - spin_lock_init(&priv->lock); - init_waitqueue_head(&priv->delta_msr_wait); - priv->type = type; - usb_set_serial_port_data(serial->port[i] , priv); - } + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + spin_lock_init(&priv->lock); + priv->quirks = id->driver_info; + + usb_set_serial_port_data(port, priv); + + port->port.drain_delay = 256; return 0; -cleanup: - for (--i; i >= 0; --i) { - priv = usb_get_serial_port_data(serial->port[i]); - kfree(priv); - usb_set_serial_port_data(serial->port[i] , NULL); - } - return -ENOMEM; } -/* call when the device plug out. free all the memory alloced by probe */ -static void spcp8x5_release(struct usb_serial *serial) +static int spcp8x5_port_remove(struct usb_serial_port *port) { - int i; + struct spcp8x5_private *priv; + + priv = usb_get_serial_port_data(port); + kfree(priv); - for (i = 0; i < serial->num_ports; i++) - kfree(usb_get_serial_port_data(serial->port[i])); + return 0; } -/* set the modem control line of the device. - * NOTE spcp825-007 not supported this */ -static int spcp8x5_set_ctrlLine(struct usb_device *dev, u8 value, - enum spcp8x5_type type) +static int spcp8x5_set_ctrl_line(struct usb_serial_port *port, u8 mcr) { + struct spcp8x5_private *priv = usb_get_serial_port_data(port); + struct usb_device *dev = port->serial->dev; int retval; - u8 mcr = 0 ; - if (type == SPCP825_007_TYPE) + if (priv->quirks & SPCP825_QUIRK_NO_UART_STATUS) return -EPERM; - mcr = (unsigned short)value; retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_UART_STATUS_TYPE, SET_UART_STATUS, mcr, 0x04, NULL, 0, 100); - if (retval != 0) - dev_dbg(&dev->dev, "usb_control_msg return %#x\n", retval); + if (retval != 0) { + dev_err(&port->dev, "failed to set control lines: %d\n", + retval); + } return retval; } -/* get the modem status register of the device - * NOTE spcp825-007 not supported this */ -static int spcp8x5_get_msr(struct usb_device *dev, u8 *status, - enum spcp8x5_type type) +static int spcp8x5_get_msr(struct usb_serial_port *port, u8 *status) { - u8 *status_buffer; + struct spcp8x5_private *priv = usb_get_serial_port_data(port); + struct usb_device *dev = port->serial->dev; + u8 *buf; int ret; - /* I return Permited not support here but seem inval device - * is more fix */ - if (type == SPCP825_007_TYPE) + if (priv->quirks & SPCP825_QUIRK_NO_UART_STATUS) return -EPERM; - if (status == NULL) - return -EINVAL; - status_buffer = kmalloc(1, GFP_KERNEL); - if (!status_buffer) + buf = kzalloc(1, GFP_KERNEL); + if (!buf) return -ENOMEM; - status_buffer[0] = status[0]; ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_UART_STATUS, GET_UART_STATUS_TYPE, - 0, GET_UART_STATUS_MSR, status_buffer, 1, 100); + 0, GET_UART_STATUS_MSR, buf, 1, 100); if (ret < 0) - dev_dbg(&dev->dev, "Get MSR = 0x%p failed (error = %d)", - status_buffer, ret); + dev_err(&port->dev, "failed to get modem status: %d\n", ret); - dev_dbg(&dev->dev, "0xc0:0x22:0:6 %d - 0x%p ", ret, status_buffer); - status[0] = status_buffer[0]; - kfree(status_buffer); + dev_dbg(&port->dev, "0xc0:0x22:0:6 %d - 0x02%x\n", ret, *buf); + *status = *buf; + kfree(buf); return ret; } -/* select the work mode. - * NOTE this function not supported by spcp825-007 */ -static void spcp8x5_set_workMode(struct usb_device *dev, u16 value, - u16 index, enum spcp8x5_type type) +static void spcp8x5_set_work_mode(struct usb_serial_port *port, u16 value, + u16 index) { + struct spcp8x5_private *priv = usb_get_serial_port_data(port); + struct usb_device *dev = port->serial->dev; int ret; - /* I return Permited not support here but seem inval device - * is more fix */ - if (type == SPCP825_007_TYPE) + if (priv->quirks & SPCP825_QUIRK_NO_WORK_MODE) return; ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_WORKING_MODE_TYPE, SET_WORKING_MODE, value, index, NULL, 0, 100); - dev_dbg(&dev->dev, "value = %#x , index = %#x\n", value, index); + dev_dbg(&port->dev, "value = %#x , index = %#x\n", value, index); if (ret < 0) - dev_dbg(&dev->dev, - "RTSCTS usb_control_msg(enable flowctrl) = %d\n", ret); + dev_err(&port->dev, "failed to set work mode: %d\n", ret); } static int spcp8x5_carrier_raised(struct usb_serial_port *port) { - struct spcp8x5_private *priv = usb_get_serial_port_data(port); - if (priv->line_status & MSR_STATUS_LINE_DCD) + u8 msr; + int ret; + + ret = spcp8x5_get_msr(port, &msr); + if (ret || msr & MSR_STATUS_LINE_DCD) return 1; + return 0; } @@ -319,51 +274,46 @@ static void spcp8x5_dtr_rts(struct usb_serial_port *port, int on) | MCR_CONTROL_LINE_RTS); control = priv->line_control; spin_unlock_irqrestore(&priv->lock, flags); - spcp8x5_set_ctrlLine(port->serial->dev, control , priv->type); + spcp8x5_set_ctrl_line(port, control); } static void spcp8x5_init_termios(struct tty_struct *tty) { - /* for the 1st time call this function */ - *(tty->termios) = tty_std_termios; - tty->termios->c_cflag = B115200 | CS8 | CREAD | HUPCL | CLOCAL; - tty->termios->c_ispeed = 115200; - tty->termios->c_ospeed = 115200; + tty->termios = tty_std_termios; + tty->termios.c_cflag = B115200 | CS8 | CREAD | HUPCL | CLOCAL; + tty->termios.c_ispeed = 115200; + tty->termios.c_ospeed = 115200; } -/* set the serial param for transfer. we should check if we really need to - * transfer. if we set flow control we should do this too. */ static void spcp8x5_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios) { struct usb_serial *serial = port->serial; struct spcp8x5_private *priv = usb_get_serial_port_data(port); unsigned long flags; - unsigned int cflag = tty->termios->c_cflag; - unsigned int old_cflag = old_termios->c_cflag; + unsigned int cflag = tty->termios.c_cflag; unsigned short uartdata; unsigned char buf[2] = {0, 0}; int baud; int i; u8 control; - /* check that they really want us to change something */ - if (!tty_termios_hw_change(tty->termios, old_termios)) + if (old_termios && !tty_termios_hw_change(&tty->termios, old_termios)) return; /* set DTR/RTS active */ spin_lock_irqsave(&priv->lock, flags); control = priv->line_control; - if ((old_cflag & CBAUD) == B0) { + if (old_termios && (old_termios->c_cflag & CBAUD) == B0) { priv->line_control |= MCR_DTR; - if (!(old_cflag & CRTSCTS)) + if (!(old_termios->c_cflag & CRTSCTS)) priv->line_control |= MCR_RTS; } if (control != priv->line_control) { control = priv->line_control; spin_unlock_irqrestore(&priv->lock, flags); - spcp8x5_set_ctrlLine(serial->dev, control , priv->type); + spcp8x5_set_ctrl_line(port, control); } else { spin_unlock_irqrestore(&priv->lock, flags); } @@ -392,27 +342,24 @@ static void spcp8x5_set_termios(struct tty_struct *tty, case 1000000: buf[0] = 0x0b; break; default: - dev_err(&port->dev, "spcp825 driver does not support the " - "baudrate requested, using default of 9600.\n"); + dev_err(&port->dev, "unsupported baudrate, using 9600\n"); } /* Set Data Length : 00:5bit, 01:6bit, 10:7bit, 11:8bit */ - if (cflag & CSIZE) { - switch (cflag & CSIZE) { - case CS5: - buf[1] |= SET_UART_FORMAT_SIZE_5; - break; - case CS6: - buf[1] |= SET_UART_FORMAT_SIZE_6; - break; - case CS7: - buf[1] |= SET_UART_FORMAT_SIZE_7; - break; - default: - case CS8: - buf[1] |= SET_UART_FORMAT_SIZE_8; - break; - } + switch (cflag & CSIZE) { + case CS5: + buf[1] |= SET_UART_FORMAT_SIZE_5; + break; + case CS6: + buf[1] |= SET_UART_FORMAT_SIZE_6; + break; + case CS7: + buf[1] |= SET_UART_FORMAT_SIZE_7; + break; + default: + case CS8: + buf[1] |= SET_UART_FORMAT_SIZE_8; + break; } /* Set Stop bit2 : 0:1bit 1:2bit */ @@ -423,9 +370,9 @@ static void spcp8x5_set_termios(struct tty_struct *tty, if (cflag & PARENB) { buf[1] |= (cflag & PARODD) ? SET_UART_FORMAT_PAR_ODD : SET_UART_FORMAT_PAR_EVEN ; - } else + } else { buf[1] |= SET_UART_FORMAT_PAR_NONE; - + } uartdata = buf[0] | buf[1]<<8; i = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), @@ -434,28 +381,19 @@ static void spcp8x5_set_termios(struct tty_struct *tty, if (i < 0) dev_err(&port->dev, "Set UART format %#x failed (error = %d)\n", uartdata, i); - dbg("0x21:0x40:0:0 %d", i); + dev_dbg(&port->dev, "0x21:0x40:0:0 %d\n", i); if (cflag & CRTSCTS) { /* enable hardware flow control */ - spcp8x5_set_workMode(serial->dev, 0x000a, - SET_WORKING_MODE_U2C, priv->type); + spcp8x5_set_work_mode(port, 0x000a, SET_WORKING_MODE_U2C); } } -/* open the serial port. do some usb system call. set termios and get the line - * status of the device. */ static int spcp8x5_open(struct tty_struct *tty, struct usb_serial_port *port) { - struct ktermios tmp_termios; struct usb_serial *serial = port->serial; struct spcp8x5_private *priv = usb_get_serial_port_data(port); int ret; - unsigned long flags; - u8 status = 0x30; - /* status 0x30 means DSR and CTS = 1 other CDC RI and delta = 0 */ - - dbg("%s - port %d", __func__, port->number); usb_clear_halt(serial->dev, port->write_urb->pipe); usb_clear_halt(serial->dev, port->read_urb->pipe); @@ -466,132 +404,15 @@ static int spcp8x5_open(struct tty_struct *tty, struct usb_serial_port *port) if (ret) return ret; - spcp8x5_set_ctrlLine(serial->dev, priv->line_control , priv->type); + spcp8x5_set_ctrl_line(port, priv->line_control); - /* Setup termios */ if (tty) - spcp8x5_set_termios(tty, port, &tmp_termios); - - spcp8x5_get_msr(serial->dev, &status, priv->type); - - /* may be we should update uart status here but now we did not do */ - spin_lock_irqsave(&priv->lock, flags); - priv->line_status = status & 0xf0 ; - spin_unlock_irqrestore(&priv->lock, flags); - - port->port.drain_delay = 256; + spcp8x5_set_termios(tty, port, NULL); return usb_serial_generic_open(tty, port); } -static void spcp8x5_process_read_urb(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - struct spcp8x5_private *priv = usb_get_serial_port_data(port); - struct tty_struct *tty; - unsigned char *data = urb->transfer_buffer; - unsigned long flags; - u8 status; - char tty_flag; - - /* get tty_flag from status */ - tty_flag = TTY_NORMAL; - - spin_lock_irqsave(&priv->lock, flags); - status = priv->line_status; - priv->line_status &= ~UART_STATE_TRANSIENT_MASK; - spin_unlock_irqrestore(&priv->lock, flags); - /* wake up the wait for termios */ - wake_up_interruptible(&priv->delta_msr_wait); - - if (!urb->actual_length) - return; - - tty = tty_port_tty_get(&port->port); - if (!tty) - return; - - if (status & UART_STATE_TRANSIENT_MASK) { - /* break takes precedence over parity, which takes precedence - * over framing errors */ - if (status & UART_BREAK_ERROR) - tty_flag = TTY_BREAK; - else if (status & UART_PARITY_ERROR) - tty_flag = TTY_PARITY; - else if (status & UART_FRAME_ERROR) - tty_flag = TTY_FRAME; - dev_dbg(&port->dev, "tty_flag = %d\n", tty_flag); - - /* overrun is special, not associated with a char */ - if (status & UART_OVERRUN_ERROR) - tty_insert_flip_char(tty, 0, TTY_OVERRUN); - } - - tty_insert_flip_string_fixed_flag(tty, data, tty_flag, - urb->actual_length); - tty_flip_buffer_push(tty); - tty_kref_put(tty); -} - -static int spcp8x5_wait_modem_info(struct usb_serial_port *port, - unsigned int arg) -{ - struct spcp8x5_private *priv = usb_get_serial_port_data(port); - unsigned long flags; - unsigned int prevstatus; - unsigned int status; - unsigned int changed; - - spin_lock_irqsave(&priv->lock, flags); - prevstatus = priv->line_status; - spin_unlock_irqrestore(&priv->lock, flags); - - while (1) { - /* wake up in bulk read */ - interruptible_sleep_on(&priv->delta_msr_wait); - - /* see if a signal did it */ - if (signal_pending(current)) - return -ERESTARTSYS; - - spin_lock_irqsave(&priv->lock, flags); - status = priv->line_status; - spin_unlock_irqrestore(&priv->lock, flags); - - changed = prevstatus^status; - - if (((arg & TIOCM_RNG) && (changed & MSR_STATUS_LINE_RI)) || - ((arg & TIOCM_DSR) && (changed & MSR_STATUS_LINE_DSR)) || - ((arg & TIOCM_CD) && (changed & MSR_STATUS_LINE_DCD)) || - ((arg & TIOCM_CTS) && (changed & MSR_STATUS_LINE_CTS))) - return 0; - - prevstatus = status; - } - /* NOTREACHED */ - return 0; -} - -static int spcp8x5_ioctl(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct usb_serial_port *port = tty->driver_data; - dbg("%s (%d) cmd = 0x%04x", __func__, port->number, cmd); - - switch (cmd) { - case TIOCMIWAIT: - dbg("%s (%d) TIOCMIWAIT", __func__, port->number); - return spcp8x5_wait_modem_info(port, arg); - - default: - dbg("%s not supported = 0x%04x", __func__, cmd); - break; - } - - return -ENOIOCTLCMD; -} - -static int spcp8x5_tiocmset(struct tty_struct *tty, struct file *file, +static int spcp8x5_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) { struct usb_serial_port *port = tty->driver_data; @@ -611,21 +432,24 @@ static int spcp8x5_tiocmset(struct tty_struct *tty, struct file *file, control = priv->line_control; spin_unlock_irqrestore(&priv->lock, flags); - return spcp8x5_set_ctrlLine(port->serial->dev, control , priv->type); + return spcp8x5_set_ctrl_line(port, control); } -static int spcp8x5_tiocmget(struct tty_struct *tty, struct file *file) +static int spcp8x5_tiocmget(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; struct spcp8x5_private *priv = usb_get_serial_port_data(port); unsigned long flags; unsigned int mcr; - unsigned int status; + u8 status; unsigned int result; + result = spcp8x5_get_msr(port, &status); + if (result) + return result; + spin_lock_irqsave(&priv->lock, flags); mcr = priv->line_control; - status = priv->line_status; spin_unlock_irqrestore(&priv->lock, flags); result = ((mcr & MCR_DTR) ? TIOCM_DTR : 0) @@ -638,7 +462,6 @@ static int spcp8x5_tiocmget(struct tty_struct *tty, struct file *file) return result; } -/* All of the device info needed for the spcp8x5 SIO serial converter */ static struct usb_serial_driver spcp8x5_device = { .driver = { .owner = THIS_MODULE, @@ -646,49 +469,23 @@ static struct usb_serial_driver spcp8x5_device = { }, .id_table = id_table, .num_ports = 1, - .open = spcp8x5_open, + .open = spcp8x5_open, .dtr_rts = spcp8x5_dtr_rts, .carrier_raised = spcp8x5_carrier_raised, - .set_termios = spcp8x5_set_termios, + .set_termios = spcp8x5_set_termios, .init_termios = spcp8x5_init_termios, - .ioctl = spcp8x5_ioctl, - .tiocmget = spcp8x5_tiocmget, - .tiocmset = spcp8x5_tiocmset, - .attach = spcp8x5_startup, - .release = spcp8x5_release, - .process_read_urb = spcp8x5_process_read_urb, + .tiocmget = spcp8x5_tiocmget, + .tiocmset = spcp8x5_tiocmset, + .probe = spcp8x5_probe, + .port_probe = spcp8x5_port_probe, + .port_remove = spcp8x5_port_remove, }; -static int __init spcp8x5_init(void) -{ - int retval; - retval = usb_serial_register(&spcp8x5_device); - if (retval) - goto failed_usb_serial_register; - retval = usb_register(&spcp8x5_driver); - if (retval) - goto failed_usb_register; - printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" - DRIVER_DESC "\n"); - return 0; -failed_usb_register: - usb_serial_deregister(&spcp8x5_device); -failed_usb_serial_register: - return retval; -} - -static void __exit spcp8x5_exit(void) -{ - usb_deregister(&spcp8x5_driver); - usb_serial_deregister(&spcp8x5_device); -} +static struct usb_serial_driver * const serial_drivers[] = { + &spcp8x5_device, NULL +}; -module_init(spcp8x5_init); -module_exit(spcp8x5_exit); +module_usb_serial_driver(serial_drivers, id_table); MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_VERSION(DRIVER_VERSION); MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c index f5312dd3331..a7fe664b6b7 100644 --- a/drivers/usb/serial/ssu100.c +++ b/drivers/usb/serial/ssu100.c @@ -6,7 +6,6 @@ */ #include <linux/errno.h> -#include <linux/init.h> #include <linux/slab.h> #include <linux/tty.h> #include <linux/tty_driver.h> @@ -46,10 +45,6 @@ #define FULLPWRBIT 0x00000080 #define NEXT_BOARD_POWER_BIT 0x00000004 -static int debug; - -/* Version Information */ -#define DRIVER_VERSION "v0.1" #define DRIVER_DESC "Quatech SSU-100 USB to Serial Driver" #define USB_VENDOR_ID_QUATECH 0x061d /* Quatech VID */ @@ -59,38 +54,14 @@ static const struct usb_device_id id_table[] = { {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_SSU100)}, {} /* Terminating entry */ }; - MODULE_DEVICE_TABLE(usb, id_table); - -static struct usb_driver ssu100_driver = { - .name = "ssu100", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, - .suspend = usb_serial_suspend, - .resume = usb_serial_resume, - .no_dynamic_id = 1, - .supports_autosuspend = 1, -}; - struct ssu100_port_private { spinlock_t status_lock; u8 shadowLSR; u8 shadowMSR; - wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */ - unsigned short max_packet_size; - struct async_icount icount; }; -static void ssu100_release(struct usb_serial *serial) -{ - struct ssu100_port_private *priv = usb_get_serial_port_data(*serial->port); - - dbg("%s", __func__); - kfree(priv); -} - static inline int ssu100_control_msg(struct usb_device *dev, u8 request, u16 data, u16 index) { @@ -150,7 +121,7 @@ static inline int update_mctrl(struct usb_device *dev, unsigned int set, int result; if (((set | clear) & (TIOCM_DTR | TIOCM_RTS)) == 0) { - dbg("%s - DTR|RTS not being set|cleared", __func__); + dev_dbg(&dev->dev, "%s - DTR|RTS not being set|cleared\n", __func__); return 0; /* no change */ } @@ -163,7 +134,7 @@ static inline int update_mctrl(struct usb_device *dev, unsigned int set, result = ssu100_setregister(dev, 0, UART_MCR, urb_value); if (result < 0) - dbg("%s Error from MODEM_CTRL urb", __func__); + dev_dbg(&dev->dev, "%s Error from MODEM_CTRL urb\n", __func__); return result; } @@ -173,15 +144,13 @@ static int ssu100_initdevice(struct usb_device *dev) u8 *data; int result = 0; - dbg("%s", __func__); - data = kzalloc(3, GFP_KERNEL); if (!data) return -ENOMEM; result = ssu100_getdevice(dev, data); if (result < 0) { - dbg("%s - get_device failed %i", __func__, result); + dev_dbg(&dev->dev, "%s - get_device failed %i\n", __func__, result); goto out; } @@ -189,25 +158,25 @@ static int ssu100_initdevice(struct usb_device *dev) result = ssu100_setdevice(dev, data); if (result < 0) { - dbg("%s - setdevice failed %i", __func__, result); + dev_dbg(&dev->dev, "%s - setdevice failed %i\n", __func__, result); goto out; } result = ssu100_control_msg(dev, QT_GET_SET_PREBUF_TRIG_LVL, 128, 0); if (result < 0) { - dbg("%s - set prebuffer level failed %i", __func__, result); + dev_dbg(&dev->dev, "%s - set prebuffer level failed %i\n", __func__, result); goto out; } result = ssu100_control_msg(dev, QT_SET_ATF, ATC_DISABLED, 0); if (result < 0) { - dbg("%s - set ATFprebuffer level failed %i", __func__, result); + dev_dbg(&dev->dev, "%s - set ATFprebuffer level failed %i\n", __func__, result); goto out; } result = ssu100_getdevice(dev, data); if (result < 0) { - dbg("%s - get_device failed %i", __func__, result); + dev_dbg(&dev->dev, "%s - get_device failed %i\n", __func__, result); goto out; } @@ -218,7 +187,7 @@ static int ssu100_initdevice(struct usb_device *dev) result = ssu100_setdevice(dev, data); if (result < 0) { - dbg("%s - setdevice failed %i", __func__, result); + dev_dbg(&dev->dev, "%s - setdevice failed %i\n", __func__, result); goto out; } @@ -233,14 +202,12 @@ static void ssu100_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { struct usb_device *dev = port->serial->dev; - struct ktermios *termios = tty->termios; + struct ktermios *termios = &tty->termios; u16 baud, divisor, remainder; unsigned int cflag = termios->c_cflag; u16 urb_value = 0; /* will hold the new flags */ int result; - dbg("%s", __func__); - if (cflag & PARENB) { if (cflag & PARODD) urb_value |= UART_LCR_PARITY; @@ -268,7 +235,7 @@ static void ssu100_set_termios(struct tty_struct *tty, if (!baud) baud = 9600; - dbg("%s - got baud = %d\n", __func__, baud); + dev_dbg(&port->dev, "%s - got baud = %d\n", __func__, baud); divisor = MAX_BAUD_RATE / baud; @@ -280,7 +247,7 @@ static void ssu100_set_termios(struct tty_struct *tty, result = ssu100_control_msg(dev, QT_GET_SET_UART, divisor, urb_value); if (result < 0) - dbg("%s - set uart failed", __func__); + dev_dbg(&port->dev, "%s - set uart failed\n", __func__); if (cflag & CRTSCTS) result = ssu100_control_msg(dev, QT_HW_FLOW_CONTROL_MASK, @@ -289,7 +256,7 @@ static void ssu100_set_termios(struct tty_struct *tty, result = ssu100_control_msg(dev, QT_HW_FLOW_CONTROL_MASK, 0, 0); if (result < 0) - dbg("%s - set HW flow control failed", __func__); + dev_dbg(&port->dev, "%s - set HW flow control failed\n", __func__); if (I_IXOFF(tty) || I_IXON(tty)) { u16 x = ((u16)(START_CHAR(tty) << 8) | (u16)(STOP_CHAR(tty))); @@ -301,7 +268,7 @@ static void ssu100_set_termios(struct tty_struct *tty, 0, 0); if (result < 0) - dbg("%s - set SW flow control failed", __func__); + dev_dbg(&port->dev, "%s - set SW flow control failed\n", __func__); } @@ -314,8 +281,6 @@ static int ssu100_open(struct tty_struct *tty, struct usb_serial_port *port) int result; unsigned long flags; - dbg("%s - port %d", __func__, port->number); - data = kzalloc(2, GFP_KERNEL); if (!data) return -ENOMEM; @@ -325,7 +290,7 @@ static int ssu100_open(struct tty_struct *tty, struct usb_serial_port *port) QT_TRANSFER_IN, 0x01, 0, data, 2, 300); if (result < 0) { - dbg("%s - open failed %i", __func__, result); + dev_dbg(&port->dev, "%s - open failed %i\n", __func__, result); kfree(data); return result; } @@ -340,20 +305,14 @@ static int ssu100_open(struct tty_struct *tty, struct usb_serial_port *port) /* set to 9600 */ result = ssu100_control_msg(dev, QT_GET_SET_UART, 0x30, 0x0300); if (result < 0) - dbg("%s - set uart failed", __func__); + dev_dbg(&port->dev, "%s - set uart failed\n", __func__); if (tty) - ssu100_set_termios(tty, port, tty->termios); + ssu100_set_termios(tty, port, &tty->termios); return usb_serial_generic_open(tty, port); } -static void ssu100_close(struct usb_serial_port *port) -{ - dbg("%s", __func__); - usb_serial_generic_close(port); -} - static int get_serial_info(struct usb_serial_port *port, struct serial_struct __user *retinfo) { @@ -363,7 +322,7 @@ static int get_serial_info(struct usb_serial_port *port, return -EFAULT; memset(&tmp, 0, sizeof(tmp)); - tmp.line = port->serial->minor; + tmp.line = port->minor; tmp.port = 0; tmp.irq = 0; tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ; @@ -377,154 +336,59 @@ static int get_serial_info(struct usb_serial_port *port, return 0; } -static int wait_modem_info(struct usb_serial_port *port, unsigned int arg) -{ - struct ssu100_port_private *priv = usb_get_serial_port_data(port); - struct async_icount prev, cur; - unsigned long flags; - - spin_lock_irqsave(&priv->status_lock, flags); - prev = priv->icount; - spin_unlock_irqrestore(&priv->status_lock, flags); - - while (1) { - wait_event_interruptible(priv->delta_msr_wait, - ((priv->icount.rng != prev.rng) || - (priv->icount.dsr != prev.dsr) || - (priv->icount.dcd != prev.dcd) || - (priv->icount.cts != prev.cts))); - - if (signal_pending(current)) - return -ERESTARTSYS; - - spin_lock_irqsave(&priv->status_lock, flags); - cur = priv->icount; - spin_unlock_irqrestore(&priv->status_lock, flags); - - if ((prev.rng == cur.rng) && - (prev.dsr == cur.dsr) && - (prev.dcd == cur.dcd) && - (prev.cts == cur.cts)) - return -EIO; - - if ((arg & TIOCM_RNG && (prev.rng != cur.rng)) || - (arg & TIOCM_DSR && (prev.dsr != cur.dsr)) || - (arg & TIOCM_CD && (prev.dcd != cur.dcd)) || - (arg & TIOCM_CTS && (prev.cts != cur.cts))) - return 0; - } - return 0; -} - -static int ssu100_get_icount(struct tty_struct *tty, - struct serial_icounter_struct *icount) -{ - struct usb_serial_port *port = tty->driver_data; - struct ssu100_port_private *priv = usb_get_serial_port_data(port); - struct async_icount cnow = priv->icount; - - icount->cts = cnow.cts; - icount->dsr = cnow.dsr; - icount->rng = cnow.rng; - icount->dcd = cnow.dcd; - icount->rx = cnow.rx; - icount->tx = cnow.tx; - icount->frame = cnow.frame; - icount->overrun = cnow.overrun; - icount->parity = cnow.parity; - icount->brk = cnow.brk; - icount->buf_overrun = cnow.buf_overrun; - - return 0; -} - - - -static int ssu100_ioctl(struct tty_struct *tty, struct file *file, +static int ssu100_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { struct usb_serial_port *port = tty->driver_data; - dbg("%s cmd 0x%04x", __func__, cmd); - switch (cmd) { case TIOCGSERIAL: return get_serial_info(port, (struct serial_struct __user *) arg); - - case TIOCMIWAIT: - return wait_modem_info(port, arg); - default: break; } - dbg("%s arg not supported", __func__); - return -ENOIOCTLCMD; } -static void ssu100_set_max_packet_size(struct usb_serial_port *port) +static int ssu100_attach(struct usb_serial *serial) { - struct ssu100_port_private *priv = usb_get_serial_port_data(port); - struct usb_serial *serial = port->serial; - struct usb_device *udev = serial->dev; - - struct usb_interface *interface = serial->interface; - struct usb_endpoint_descriptor *ep_desc = &interface->cur_altsetting->endpoint[1].desc; - - unsigned num_endpoints; - int i; - unsigned long flags; - - num_endpoints = interface->cur_altsetting->desc.bNumEndpoints; - dev_info(&udev->dev, "Number of endpoints %d\n", num_endpoints); - - for (i = 0; i < num_endpoints; i++) { - dev_info(&udev->dev, "Endpoint %d MaxPacketSize %d\n", i+1, - interface->cur_altsetting->endpoint[i].desc.wMaxPacketSize); - ep_desc = &interface->cur_altsetting->endpoint[i].desc; - } - - /* set max packet size based on descriptor */ - spin_lock_irqsave(&priv->status_lock, flags); - priv->max_packet_size = ep_desc->wMaxPacketSize; - spin_unlock_irqrestore(&priv->status_lock, flags); - - dev_info(&udev->dev, "Setting MaxPacketSize %d\n", priv->max_packet_size); + return ssu100_initdevice(serial->dev); } -static int ssu100_attach(struct usb_serial *serial) +static int ssu100_port_probe(struct usb_serial_port *port) { struct ssu100_port_private *priv; - struct usb_serial_port *port = *serial->port; - - dbg("%s", __func__); priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) { - dev_err(&port->dev, "%s- kmalloc(%Zd) failed.\n", __func__, - sizeof(*priv)); + if (!priv) return -ENOMEM; - } spin_lock_init(&priv->status_lock); - init_waitqueue_head(&priv->delta_msr_wait); + usb_set_serial_port_data(port, priv); - ssu100_set_max_packet_size(port); - return ssu100_initdevice(serial->dev); + return 0; +} + +static int ssu100_port_remove(struct usb_serial_port *port) +{ + struct ssu100_port_private *priv; + + priv = usb_get_serial_port_data(port); + kfree(priv); + + return 0; } -static int ssu100_tiocmget(struct tty_struct *tty, struct file *file) +static int ssu100_tiocmget(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; struct usb_device *dev = port->serial->dev; u8 *d; int r; - dbg("%s\n", __func__); - d = kzalloc(2, GFP_KERNEL); if (!d) return -ENOMEM; @@ -549,13 +413,12 @@ mget_out: return r; } -static int ssu100_tiocmset(struct tty_struct *tty, struct file *file, +static int ssu100_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) { struct usb_serial_port *port = tty->driver_data; struct usb_device *dev = port->serial->dev; - dbg("%s\n", __func__); return update_mctrl(dev, set, clear); } @@ -563,21 +426,16 @@ static void ssu100_dtr_rts(struct usb_serial_port *port, int on) { struct usb_device *dev = port->serial->dev; - dbg("%s\n", __func__); - - mutex_lock(&port->serial->disc_mutex); - if (!port->serial->disconnected) { - /* Disable flow control */ - if (!on && - ssu100_setregister(dev, 0, UART_MCR, 0) < 0) + /* Disable flow control */ + if (!on) { + if (ssu100_setregister(dev, 0, UART_MCR, 0) < 0) dev_err(&port->dev, "error from flowcontrol urb\n"); - /* drop RTS and DTR */ - if (on) - set_mctrl(dev, TIOCM_DTR | TIOCM_RTS); - else - clear_mctrl(dev, TIOCM_DTR | TIOCM_RTS); } - mutex_unlock(&port->serial->disc_mutex); + /* drop RTS and DTR */ + if (on) + set_mctrl(dev, TIOCM_DTR | TIOCM_RTS); + else + clear_mctrl(dev, TIOCM_DTR | TIOCM_RTS); } static void ssu100_update_msr(struct usb_serial_port *port, u8 msr) @@ -592,14 +450,14 @@ static void ssu100_update_msr(struct usb_serial_port *port, u8 msr) if (msr & UART_MSR_ANY_DELTA) { /* update input line counters */ if (msr & UART_MSR_DCTS) - priv->icount.cts++; + port->icount.cts++; if (msr & UART_MSR_DDSR) - priv->icount.dsr++; + port->icount.dsr++; if (msr & UART_MSR_DDCD) - priv->icount.dcd++; + port->icount.dcd++; if (msr & UART_MSR_TERI) - priv->icount.rng++; - wake_up_interruptible(&priv->delta_msr_wait); + port->icount.rng++; + wake_up_interruptible(&port->port.delta_msr_wait); } } @@ -618,22 +476,22 @@ static void ssu100_update_lsr(struct usb_serial_port *port, u8 lsr, /* we always want to update icount, but we only want to * update tty_flag for one case */ if (lsr & UART_LSR_BI) { - priv->icount.brk++; + port->icount.brk++; *tty_flag = TTY_BREAK; usb_serial_handle_break(port); } if (lsr & UART_LSR_PE) { - priv->icount.parity++; + port->icount.parity++; if (*tty_flag == TTY_NORMAL) *tty_flag = TTY_PARITY; } if (lsr & UART_LSR_FE) { - priv->icount.frame++; + port->icount.frame++; if (*tty_flag == TTY_NORMAL) *tty_flag = TTY_FRAME; } if (lsr & UART_LSR_OE){ - priv->icount.overrun++; + port->icount.overrun++; if (*tty_flag == TTY_NORMAL) *tty_flag = TTY_OVERRUN; } @@ -641,24 +499,23 @@ static void ssu100_update_lsr(struct usb_serial_port *port, u8 lsr, } -static int ssu100_process_packet(struct tty_struct *tty, - struct usb_serial_port *port, - struct ssu100_port_private *priv, - char *packet, int len) +static void ssu100_process_read_urb(struct urb *urb) { - int i; + struct usb_serial_port *port = urb->context; + char *packet = (char *)urb->transfer_buffer; char flag = TTY_NORMAL; + u32 len = urb->actual_length; + int i; char *ch; - dbg("%s - port %d", __func__, port->number); - if ((len >= 4) && (packet[0] == 0x1b) && (packet[1] == 0x1b) && ((packet[2] == 0x00) || (packet[2] == 0x01))) { if (packet[2] == 0x00) { ssu100_update_lsr(port, packet[3], &flag); if (flag == TTY_OVERRUN) - tty_insert_flip_char(tty, 0, TTY_OVERRUN); + tty_insert_flip_char(&port->port, 0, + TTY_OVERRUN); } if (packet[2] == 0x01) ssu100_update_msr(port, packet[3]); @@ -669,43 +526,17 @@ static int ssu100_process_packet(struct tty_struct *tty, ch = packet; if (!len) - return 0; /* status only */ + return; /* status only */ if (port->port.console && port->sysrq) { for (i = 0; i < len; i++, ch++) { if (!usb_serial_handle_sysrq_char(port, *ch)) - tty_insert_flip_char(tty, *ch, flag); + tty_insert_flip_char(&port->port, *ch, flag); } } else - tty_insert_flip_string_fixed_flag(tty, ch, flag, len); - - return len; -} - -static void ssu100_process_read_urb(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - struct ssu100_port_private *priv = usb_get_serial_port_data(port); - char *data = (char *)urb->transfer_buffer; - struct tty_struct *tty; - int count = 0; - int i; - int len; + tty_insert_flip_string_fixed_flag(&port->port, ch, flag, len); - dbg("%s", __func__); - - tty = tty_port_tty_get(&port->port); - if (!tty) - return; - - for (i = 0; i < urb->actual_length; i += priv->max_packet_size) { - len = min_t(int, urb->actual_length - i, priv->max_packet_size); - count += ssu100_process_packet(tty, port, priv, &data[i], len); - } - - if (count) - tty_flip_buffer_push(tty); - tty_kref_put(tty); + tty_flip_buffer_push(&port->port); } static struct usb_serial_driver ssu100_device = { @@ -715,62 +546,26 @@ static struct usb_serial_driver ssu100_device = { }, .description = DRIVER_DESC, .id_table = id_table, - .usb_driver = &ssu100_driver, .num_ports = 1, - .bulk_in_size = 256, - .bulk_out_size = 256, .open = ssu100_open, - .close = ssu100_close, .attach = ssu100_attach, - .release = ssu100_release, + .port_probe = ssu100_port_probe, + .port_remove = ssu100_port_remove, .dtr_rts = ssu100_dtr_rts, .process_read_urb = ssu100_process_read_urb, .tiocmget = ssu100_tiocmget, .tiocmset = ssu100_tiocmset, - .get_icount = ssu100_get_icount, + .tiocmiwait = usb_serial_generic_tiocmiwait, + .get_icount = usb_serial_generic_get_icount, .ioctl = ssu100_ioctl, .set_termios = ssu100_set_termios, - .disconnect = usb_serial_generic_disconnect, }; -static int __init ssu100_init(void) -{ - int retval; - - dbg("%s", __func__); - - /* register with usb-serial */ - retval = usb_serial_register(&ssu100_device); - - if (retval) - goto failed_usb_sio_register; - - retval = usb_register(&ssu100_driver); - if (retval) - goto failed_usb_register; - - printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" - DRIVER_DESC "\n"); - - return 0; - -failed_usb_register: - usb_serial_deregister(&ssu100_device); -failed_usb_sio_register: - return retval; -} - -static void __exit ssu100_exit(void) -{ - usb_deregister(&ssu100_driver); - usb_serial_deregister(&ssu100_device); -} +static struct usb_serial_driver * const serial_drivers[] = { + &ssu100_device, NULL +}; -module_init(ssu100_init); -module_exit(ssu100_exit); +module_usb_serial_driver(serial_drivers, id_table); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/drivers/usb/serial/symbolserial.c b/drivers/usb/serial/symbolserial.c index d9457bd4fe1..8fceec7298e 100644 --- a/drivers/usb/serial/symbolserial.c +++ b/drivers/usb/serial/symbolserial.c @@ -1,6 +1,7 @@ /* * Symbol USB barcode to serial driver * + * Copyright (C) 2013 Johan Hovold <jhovold@gmail.com> * Copyright (C) 2009 Greg Kroah-Hartman <gregkh@suse.de> * Copyright (C) 2009 Novell Inc. * @@ -10,7 +11,6 @@ */ #include <linux/kernel.h> -#include <linux/init.h> #include <linux/tty.h> #include <linux/slab.h> #include <linux/tty_driver.h> @@ -20,42 +20,27 @@ #include <linux/usb/serial.h> #include <linux/uaccess.h> -static int debug; - static const struct usb_device_id id_table[] = { { USB_DEVICE(0x05e0, 0x0600) }, { }, }; MODULE_DEVICE_TABLE(usb, id_table); -/* This structure holds all of the individual device information */ struct symbol_private { - struct usb_device *udev; - struct usb_serial *serial; - struct usb_serial_port *port; - unsigned char *int_buffer; - struct urb *int_urb; - int buffer_size; - u8 bInterval; - u8 int_address; spinlock_t lock; /* protects the following flags */ bool throttled; bool actually_throttled; - bool rts; }; static void symbol_int_callback(struct urb *urb) { - struct symbol_private *priv = urb->context; + struct usb_serial_port *port = urb->context; + struct symbol_private *priv = usb_get_serial_port_data(port); unsigned char *data = urb->transfer_buffer; - struct usb_serial_port *port = priv->port; int status = urb->status; - struct tty_struct *tty; int result; int data_length; - dbg("%s - port %d", __func__, port->number); - switch (status) { case 0: /* success */ @@ -64,17 +49,16 @@ static void symbol_int_callback(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", - __func__, status); + dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n", + __func__, status); return; default: - dbg("%s - nonzero urb status received: %d", - __func__, status); + dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n", + __func__, status); goto exit; } - usb_serial_debug_data(debug, &port->dev, __func__, urb->actual_length, - data); + usb_serial_debug_data(&port->dev, __func__, urb->actual_length, data); if (urb->actual_length > 1) { data_length = urb->actual_length - 1; @@ -87,16 +71,10 @@ static void symbol_int_callback(struct urb *urb) * we pretty much just ignore the size and send everything * else to the tty layer. */ - tty = tty_port_tty_get(&port->port); - if (tty) { - tty_insert_flip_string(tty, &data[1], data_length); - tty_flip_buffer_push(tty); - tty_kref_put(tty); - } + tty_insert_flip_string(&port->port, &data[1], data_length); + tty_flip_buffer_push(&port->port); } else { - dev_dbg(&priv->udev->dev, - "Improper amount of data received from the device, " - "%d bytes", urb->actual_length); + dev_dbg(&port->dev, "%s - short packet\n", __func__); } exit: @@ -104,12 +82,7 @@ exit: /* Continue trying to always read if we should */ if (!priv->throttled) { - usb_fill_int_urb(priv->int_urb, priv->udev, - usb_rcvintpipe(priv->udev, - priv->int_address), - priv->int_buffer, priv->buffer_size, - symbol_int_callback, priv, priv->bInterval); - result = usb_submit_urb(priv->int_urb, GFP_ATOMIC); + result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC); if (result) dev_err(&port->dev, "%s - failed resubmitting read urb, error %d\n", @@ -125,20 +98,13 @@ static int symbol_open(struct tty_struct *tty, struct usb_serial_port *port) unsigned long flags; int result = 0; - dbg("%s - port %d", __func__, port->number); - spin_lock_irqsave(&priv->lock, flags); priv->throttled = false; priv->actually_throttled = false; - priv->port = port; spin_unlock_irqrestore(&priv->lock, flags); /* Start reading from the device */ - usb_fill_int_urb(priv->int_urb, priv->udev, - usb_rcvintpipe(priv->udev, priv->int_address), - priv->int_buffer, priv->buffer_size, - symbol_int_callback, priv, priv->bInterval); - result = usb_submit_urb(priv->int_urb, GFP_KERNEL); + result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); if (result) dev_err(&port->dev, "%s - failed resubmitting read urb, error %d\n", @@ -148,12 +114,7 @@ static int symbol_open(struct tty_struct *tty, struct usb_serial_port *port) static void symbol_close(struct usb_serial_port *port) { - struct symbol_private *priv = usb_get_serial_data(port->serial); - - dbg("%s - port %d", __func__, port->number); - - /* shutdown our urbs */ - usb_kill_urb(priv->int_urb); + usb_kill_urb(port->interrupt_in_urb); } static void symbol_throttle(struct tty_struct *tty) @@ -161,7 +122,6 @@ static void symbol_throttle(struct tty_struct *tty) struct usb_serial_port *port = tty->driver_data; struct symbol_private *priv = usb_get_serial_data(port->serial); - dbg("%s - port %d", __func__, port->number); spin_lock_irq(&priv->lock); priv->throttled = true; spin_unlock_irq(&priv->lock); @@ -174,17 +134,14 @@ static void symbol_unthrottle(struct tty_struct *tty) int result; bool was_throttled; - dbg("%s - port %d", __func__, port->number); - spin_lock_irq(&priv->lock); priv->throttled = false; was_throttled = priv->actually_throttled; priv->actually_throttled = false; spin_unlock_irq(&priv->lock); - priv->int_urb->dev = port->serial->dev; if (was_throttled) { - result = usb_submit_urb(priv->int_urb, GFP_KERNEL); + result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); if (result) dev_err(&port->dev, "%s - failed submitting read urb, error %d\n", @@ -194,102 +151,37 @@ static void symbol_unthrottle(struct tty_struct *tty) static int symbol_startup(struct usb_serial *serial) { - struct symbol_private *priv; - struct usb_host_interface *intf; - int i; - int retval = -ENOMEM; - bool int_in_found = false; - - /* create our private serial structure */ - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (priv == NULL) { - dev_err(&serial->dev->dev, "%s - Out of memory\n", __func__); - return -ENOMEM; + if (!serial->num_interrupt_in) { + dev_err(&serial->dev->dev, "no interrupt-in endpoint\n"); + return -ENODEV; } - spin_lock_init(&priv->lock); - priv->serial = serial; - priv->port = serial->port[0]; - priv->udev = serial->dev; - - /* find our interrupt endpoint */ - intf = serial->interface->altsetting; - for (i = 0; i < intf->desc.bNumEndpoints; ++i) { - struct usb_endpoint_descriptor *endpoint; - - endpoint = &intf->endpoint[i].desc; - if (!usb_endpoint_is_int_in(endpoint)) - continue; - - priv->int_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!priv->int_urb) { - dev_err(&priv->udev->dev, "out of memory\n"); - goto error; - } - - priv->buffer_size = le16_to_cpu(endpoint->wMaxPacketSize) * 2; - priv->int_buffer = kmalloc(priv->buffer_size, GFP_KERNEL); - if (!priv->int_buffer) { - dev_err(&priv->udev->dev, "out of memory\n"); - goto error; - } - - priv->int_address = endpoint->bEndpointAddress; - priv->bInterval = endpoint->bInterval; - - /* set up our int urb */ - usb_fill_int_urb(priv->int_urb, priv->udev, - usb_rcvintpipe(priv->udev, - endpoint->bEndpointAddress), - priv->int_buffer, priv->buffer_size, - symbol_int_callback, priv, priv->bInterval); - - int_in_found = true; - break; - } - if (!int_in_found) { - dev_err(&priv->udev->dev, - "Error - the proper endpoints were not found!\n"); - goto error; - } - - usb_set_serial_data(serial, priv); return 0; - -error: - usb_free_urb(priv->int_urb); - kfree(priv->int_buffer); - kfree(priv); - return retval; } -static void symbol_disconnect(struct usb_serial *serial) +static int symbol_port_probe(struct usb_serial_port *port) { - struct symbol_private *priv = usb_get_serial_data(serial); + struct symbol_private *priv; - dbg("%s", __func__); + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + spin_lock_init(&priv->lock); + + usb_set_serial_port_data(port, priv); - usb_kill_urb(priv->int_urb); - usb_free_urb(priv->int_urb); + return 0; } -static void symbol_release(struct usb_serial *serial) +static int symbol_port_remove(struct usb_serial_port *port) { - struct symbol_private *priv = usb_get_serial_data(serial); - - dbg("%s", __func__); + struct symbol_private *priv = usb_get_serial_port_data(port); - kfree(priv->int_buffer); kfree(priv); -} -static struct usb_driver symbol_driver = { - .name = "symbol", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, - .no_dynamic_id = 1, -}; + return 0; +} static struct usb_serial_driver symbol_device = { .driver = { @@ -297,39 +189,21 @@ static struct usb_serial_driver symbol_device = { .name = "symbol", }, .id_table = id_table, - .usb_driver = &symbol_driver, .num_ports = 1, .attach = symbol_startup, + .port_probe = symbol_port_probe, + .port_remove = symbol_port_remove, .open = symbol_open, .close = symbol_close, - .disconnect = symbol_disconnect, - .release = symbol_release, .throttle = symbol_throttle, .unthrottle = symbol_unthrottle, + .read_int_callback = symbol_int_callback, }; -static int __init symbol_init(void) -{ - int retval; - - retval = usb_serial_register(&symbol_device); - if (retval) - return retval; - retval = usb_register(&symbol_driver); - if (retval) - usb_serial_deregister(&symbol_device); - return retval; -} +static struct usb_serial_driver * const serial_drivers[] = { + &symbol_device, NULL +}; -static void __exit symbol_exit(void) -{ - usb_deregister(&symbol_driver); - usb_serial_deregister(&symbol_device); -} +module_usb_serial_driver(serial_drivers, id_table); -module_init(symbol_init); -module_exit(symbol_exit); MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index b2902f307b4..3dd3ff8c50d 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -21,7 +21,6 @@ #include <linux/kernel.h> #include <linux/errno.h> #include <linux/firmware.h> -#include <linux/init.h> #include <linux/slab.h> #include <linux/tty.h> #include <linux/tty_driver.h> @@ -40,14 +39,11 @@ /* Defines */ -#define TI_DRIVER_VERSION "v0.10" #define TI_DRIVER_AUTHOR "Al Borchers <alborchers@steinerpoint.com>" #define TI_DRIVER_DESC "TI USB 3410/5052 Serial Driver" #define TI_FIRMWARE_BUF_SIZE 16284 -#define TI_WRITE_BUF_SIZE 1024 - #define TI_TRANSFER_TIMEOUT 2 #define TI_DEFAULT_CLOSING_WAIT 4000 /* in .01 secs */ @@ -68,21 +64,15 @@ struct ti_port { int tp_is_open; __u8 tp_msr; - __u8 tp_lsr; __u8 tp_shadow_mcr; __u8 tp_uart_mode; /* 232 or 485 modes */ unsigned int tp_uart_base_addr; int tp_flags; - int tp_closing_wait;/* in .01 secs */ - struct async_icount tp_icount; - wait_queue_head_t tp_msr_wait; /* wait for msr change */ - wait_queue_head_t tp_write_wait; struct ti_device *tp_tdev; struct usb_serial_port *tp_port; spinlock_t tp_lock; int tp_read_urb_state; int tp_write_urb_in_use; - struct kfifo write_fifo; }; struct ti_device { @@ -98,41 +88,40 @@ struct ti_device { static int ti_startup(struct usb_serial *serial); static void ti_release(struct usb_serial *serial); +static int ti_port_probe(struct usb_serial_port *port); +static int ti_port_remove(struct usb_serial_port *port); static int ti_open(struct tty_struct *tty, struct usb_serial_port *port); static void ti_close(struct usb_serial_port *port); static int ti_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *data, int count); static int ti_write_room(struct tty_struct *tty); static int ti_chars_in_buffer(struct tty_struct *tty); +static bool ti_tx_empty(struct usb_serial_port *port); static void ti_throttle(struct tty_struct *tty); static void ti_unthrottle(struct tty_struct *tty); -static int ti_ioctl(struct tty_struct *tty, struct file *file, +static int ti_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg); -static int ti_get_icount(struct tty_struct *tty, - struct serial_icounter_struct *icount); static void ti_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios); -static int ti_tiocmget(struct tty_struct *tty, struct file *file); -static int ti_tiocmset(struct tty_struct *tty, struct file *file, +static int ti_tiocmget(struct tty_struct *tty); +static int ti_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear); static void ti_break(struct tty_struct *tty, int break_state); static void ti_interrupt_callback(struct urb *urb); static void ti_bulk_in_callback(struct urb *urb); static void ti_bulk_out_callback(struct urb *urb); -static void ti_recv(struct device *dev, struct tty_struct *tty, - unsigned char *data, int length); +static void ti_recv(struct usb_serial_port *port, unsigned char *data, + int length); static void ti_send(struct ti_port *tport); static int ti_set_mcr(struct ti_port *tport, unsigned int mcr); -static int ti_get_lsr(struct ti_port *tport); +static int ti_get_lsr(struct ti_port *tport, u8 *lsr); static int ti_get_serial_info(struct ti_port *tport, struct serial_struct __user *ret_arg); static int ti_set_serial_info(struct tty_struct *tty, struct ti_port *tport, struct serial_struct __user *new_arg); static void ti_handle_new_msr(struct ti_port *tport, __u8 msr); -static void ti_drain(struct ti_port *tport, unsigned long timeout, int flush); - static void ti_stop_read(struct ti_port *tport, struct tty_struct *tty); static int ti_restart_read(struct ti_port *tport, struct tty_struct *tty); @@ -141,8 +130,8 @@ static int ti_command_out_sync(struct ti_device *tdev, __u8 command, static int ti_command_in_sync(struct ti_device *tdev, __u8 command, __u16 moduleid, __u16 value, __u8 *data, int size); -static int ti_write_byte(struct ti_device *tdev, unsigned long addr, - __u8 mask, __u8 byte); +static int ti_write_byte(struct usb_serial_port *port, struct ti_device *tdev, + unsigned long addr, __u8 mask, __u8 byte); static int ti_download_firmware(struct ti_device *tdev); @@ -150,22 +139,10 @@ static int ti_download_firmware(struct ti_device *tdev); /* Data */ /* module parameters */ -static int debug; static int closing_wait = TI_DEFAULT_CLOSING_WAIT; -static ushort vendor_3410[TI_EXTRA_VID_PID_COUNT]; -static unsigned int vendor_3410_count; -static ushort product_3410[TI_EXTRA_VID_PID_COUNT]; -static unsigned int product_3410_count; -static ushort vendor_5052[TI_EXTRA_VID_PID_COUNT]; -static unsigned int vendor_5052_count; -static ushort product_5052[TI_EXTRA_VID_PID_COUNT]; -static unsigned int product_5052_count; /* supported devices */ -/* the array dimension is the number of default entries plus */ -/* TI_EXTRA_VID_PID_COUNT user defined entries plus 1 terminating */ -/* null entry */ -static struct usb_device_id ti_id_table_3410[13+TI_EXTRA_VID_PID_COUNT+1] = { +static const struct usb_device_id ti_id_table_3410[] = { { USB_DEVICE(TI_VENDOR_ID, TI_3410_PRODUCT_ID) }, { USB_DEVICE(TI_VENDOR_ID, TI_3410_EZ430_ID) }, { USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_NO_FW_PRODUCT_ID) }, @@ -179,16 +156,21 @@ static struct usb_device_id ti_id_table_3410[13+TI_EXTRA_VID_PID_COUNT+1] = { { USB_DEVICE(IBM_VENDOR_ID, IBM_4543_PRODUCT_ID) }, { USB_DEVICE(IBM_VENDOR_ID, IBM_454B_PRODUCT_ID) }, { USB_DEVICE(IBM_VENDOR_ID, IBM_454C_PRODUCT_ID) }, + { USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_STEREO_PLUG_ID) }, + { USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_STRIP_PORT_ID) }, + { USB_DEVICE(TI_VENDOR_ID, FRI2_PRODUCT_ID) }, + { } /* terminator */ }; -static struct usb_device_id ti_id_table_5052[5+TI_EXTRA_VID_PID_COUNT+1] = { +static const struct usb_device_id ti_id_table_5052[] = { { USB_DEVICE(TI_VENDOR_ID, TI_5052_BOOT_PRODUCT_ID) }, { USB_DEVICE(TI_VENDOR_ID, TI_5152_BOOT_PRODUCT_ID) }, { USB_DEVICE(TI_VENDOR_ID, TI_5052_EEPROM_PRODUCT_ID) }, { USB_DEVICE(TI_VENDOR_ID, TI_5052_FIRMWARE_PRODUCT_ID) }, + { } /* terminator */ }; -static struct usb_device_id ti_id_table_combined[17+2*TI_EXTRA_VID_PID_COUNT+1] = { +static const struct usb_device_id ti_id_table_combined[] = { { USB_DEVICE(TI_VENDOR_ID, TI_3410_PRODUCT_ID) }, { USB_DEVICE(TI_VENDOR_ID, TI_3410_EZ430_ID) }, { USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_NO_FW_PRODUCT_ID) }, @@ -206,15 +188,10 @@ static struct usb_device_id ti_id_table_combined[17+2*TI_EXTRA_VID_PID_COUNT+1] { USB_DEVICE(IBM_VENDOR_ID, IBM_4543_PRODUCT_ID) }, { USB_DEVICE(IBM_VENDOR_ID, IBM_454B_PRODUCT_ID) }, { USB_DEVICE(IBM_VENDOR_ID, IBM_454C_PRODUCT_ID) }, - { } -}; - -static struct usb_driver ti_usb_driver = { - .name = "ti_usb_3410_5052", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = ti_id_table_combined, - .no_dynamic_id = 1, + { USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_PRODUCT_ID) }, + { USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_STRIP_PORT_ID) }, + { USB_DEVICE(TI_VENDOR_ID, FRI2_PRODUCT_ID) }, + { } /* terminator */ }; static struct usb_serial_driver ti_1port_device = { @@ -223,23 +200,26 @@ static struct usb_serial_driver ti_1port_device = { .name = "ti_usb_3410_5052_1", }, .description = "TI USB 3410 1 port adapter", - .usb_driver = &ti_usb_driver, .id_table = ti_id_table_3410, .num_ports = 1, .attach = ti_startup, .release = ti_release, + .port_probe = ti_port_probe, + .port_remove = ti_port_remove, .open = ti_open, .close = ti_close, .write = ti_write, .write_room = ti_write_room, .chars_in_buffer = ti_chars_in_buffer, + .tx_empty = ti_tx_empty, .throttle = ti_throttle, .unthrottle = ti_unthrottle, .ioctl = ti_ioctl, .set_termios = ti_set_termios, .tiocmget = ti_tiocmget, .tiocmset = ti_tiocmset, - .get_icount = ti_get_icount, + .tiocmiwait = usb_serial_generic_tiocmiwait, + .get_icount = usb_serial_generic_get_icount, .break_ctl = ti_break, .read_int_callback = ti_interrupt_callback, .read_bulk_callback = ti_bulk_in_callback, @@ -252,35 +232,40 @@ static struct usb_serial_driver ti_2port_device = { .name = "ti_usb_3410_5052_2", }, .description = "TI USB 5052 2 port adapter", - .usb_driver = &ti_usb_driver, .id_table = ti_id_table_5052, .num_ports = 2, .attach = ti_startup, .release = ti_release, + .port_probe = ti_port_probe, + .port_remove = ti_port_remove, .open = ti_open, .close = ti_close, .write = ti_write, .write_room = ti_write_room, .chars_in_buffer = ti_chars_in_buffer, + .tx_empty = ti_tx_empty, .throttle = ti_throttle, .unthrottle = ti_unthrottle, .ioctl = ti_ioctl, .set_termios = ti_set_termios, .tiocmget = ti_tiocmget, .tiocmset = ti_tiocmset, - .get_icount = ti_get_icount, + .tiocmiwait = usb_serial_generic_tiocmiwait, + .get_icount = usb_serial_generic_get_icount, .break_ctl = ti_break, .read_int_callback = ti_interrupt_callback, .read_bulk_callback = ti_bulk_in_callback, .write_bulk_callback = ti_bulk_out_callback, }; +static struct usb_serial_driver * const serial_drivers[] = { + &ti_1port_device, &ti_2port_device, NULL +}; /* Module */ MODULE_AUTHOR(TI_DRIVER_AUTHOR); MODULE_DESCRIPTION(TI_DRIVER_DESC); -MODULE_VERSION(TI_DRIVER_VERSION); MODULE_LICENSE("GPL"); MODULE_FIRMWARE("ti_3410.fw"); @@ -291,127 +276,48 @@ MODULE_FIRMWARE("mts_edge.fw"); MODULE_FIRMWARE("mts_mt9234mu.fw"); MODULE_FIRMWARE("mts_mt9234zba.fw"); -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Enable debugging, 0=no, 1=yes"); - module_param(closing_wait, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(closing_wait, "Maximum wait for data to drain in close, in .01 secs, default is 4000"); -module_param_array(vendor_3410, ushort, &vendor_3410_count, S_IRUGO); -MODULE_PARM_DESC(vendor_3410, - "Vendor ids for 3410 based devices, 1-5 short integers"); -module_param_array(product_3410, ushort, &product_3410_count, S_IRUGO); -MODULE_PARM_DESC(product_3410, - "Product ids for 3410 based devices, 1-5 short integers"); -module_param_array(vendor_5052, ushort, &vendor_5052_count, S_IRUGO); -MODULE_PARM_DESC(vendor_5052, - "Vendor ids for 5052 based devices, 1-5 short integers"); -module_param_array(product_5052, ushort, &product_5052_count, S_IRUGO); -MODULE_PARM_DESC(product_5052, - "Product ids for 5052 based devices, 1-5 short integers"); - MODULE_DEVICE_TABLE(usb, ti_id_table_combined); +module_usb_serial_driver(serial_drivers, ti_id_table_combined); /* Functions */ -static int __init ti_init(void) -{ - int i, j, c; - int ret; - - /* insert extra vendor and product ids */ - c = ARRAY_SIZE(ti_id_table_combined) - 2 * TI_EXTRA_VID_PID_COUNT - 1; - j = ARRAY_SIZE(ti_id_table_3410) - TI_EXTRA_VID_PID_COUNT - 1; - for (i = 0; i < min(vendor_3410_count, product_3410_count); i++, j++, c++) { - ti_id_table_3410[j].idVendor = vendor_3410[i]; - ti_id_table_3410[j].idProduct = product_3410[i]; - ti_id_table_3410[j].match_flags = USB_DEVICE_ID_MATCH_DEVICE; - ti_id_table_combined[c].idVendor = vendor_3410[i]; - ti_id_table_combined[c].idProduct = product_3410[i]; - ti_id_table_combined[c].match_flags = USB_DEVICE_ID_MATCH_DEVICE; - } - j = ARRAY_SIZE(ti_id_table_5052) - TI_EXTRA_VID_PID_COUNT - 1; - for (i = 0; i < min(vendor_5052_count, product_5052_count); i++, j++, c++) { - ti_id_table_5052[j].idVendor = vendor_5052[i]; - ti_id_table_5052[j].idProduct = product_5052[i]; - ti_id_table_5052[j].match_flags = USB_DEVICE_ID_MATCH_DEVICE; - ti_id_table_combined[c].idVendor = vendor_5052[i]; - ti_id_table_combined[c].idProduct = product_5052[i]; - ti_id_table_combined[c].match_flags = USB_DEVICE_ID_MATCH_DEVICE; - } - - ret = usb_serial_register(&ti_1port_device); - if (ret) - goto failed_1port; - ret = usb_serial_register(&ti_2port_device); - if (ret) - goto failed_2port; - - ret = usb_register(&ti_usb_driver); - if (ret) - goto failed_usb; - - printk(KERN_INFO KBUILD_MODNAME ": " TI_DRIVER_VERSION ":" - TI_DRIVER_DESC "\n"); - - return 0; - -failed_usb: - usb_serial_deregister(&ti_2port_device); -failed_2port: - usb_serial_deregister(&ti_1port_device); -failed_1port: - return ret; -} - - -static void __exit ti_exit(void) -{ - usb_serial_deregister(&ti_1port_device); - usb_serial_deregister(&ti_2port_device); - usb_deregister(&ti_usb_driver); -} - - -module_init(ti_init); -module_exit(ti_exit); - - static int ti_startup(struct usb_serial *serial) { struct ti_device *tdev; - struct ti_port *tport; struct usb_device *dev = serial->dev; int status; - int i; - - dbg("%s - product 0x%4X, num configurations %d, configuration value %d", - __func__, le16_to_cpu(dev->descriptor.idProduct), - dev->descriptor.bNumConfigurations, - dev->actconfig->desc.bConfigurationValue); + dev_dbg(&dev->dev, + "%s - product 0x%4X, num configurations %d, configuration value %d\n", + __func__, le16_to_cpu(dev->descriptor.idProduct), + dev->descriptor.bNumConfigurations, + dev->actconfig->desc.bConfigurationValue); /* create device structure */ tdev = kzalloc(sizeof(struct ti_device), GFP_KERNEL); - if (tdev == NULL) { - dev_err(&dev->dev, "%s - out of memory\n", __func__); + if (!tdev) return -ENOMEM; - } + mutex_init(&tdev->td_open_close_lock); tdev->td_serial = serial; usb_set_serial_data(serial, tdev); /* determine device type */ - if (usb_match_id(serial->interface, ti_id_table_3410)) + if (serial->type == &ti_1port_device) tdev->td_is_3410 = 1; - dbg("%s - device type is %s", __func__, - tdev->td_is_3410 ? "3410" : "5052"); + dev_dbg(&dev->dev, "%s - device type is %s\n", __func__, + tdev->td_is_3410 ? "3410" : "5052"); /* if we have only 1 configuration, download firmware */ if (dev->descriptor.bNumConfigurations == 1) { - if ((status = ti_download_firmware(tdev)) != 0) + status = ti_download_firmware(tdev); + + if (status != 0) goto free_tdev; /* 3410 must be reset, 5052 resets itself */ @@ -431,42 +337,8 @@ static int ti_startup(struct usb_serial *serial) goto free_tdev; } - /* set up port structures */ - for (i = 0; i < serial->num_ports; ++i) { - tport = kzalloc(sizeof(struct ti_port), GFP_KERNEL); - if (tport == NULL) { - dev_err(&dev->dev, "%s - out of memory\n", __func__); - status = -ENOMEM; - goto free_tports; - } - spin_lock_init(&tport->tp_lock); - tport->tp_uart_base_addr = (i == 0 ? - TI_UART1_BASE_ADDR : TI_UART2_BASE_ADDR); - tport->tp_closing_wait = closing_wait; - init_waitqueue_head(&tport->tp_msr_wait); - init_waitqueue_head(&tport->tp_write_wait); - if (kfifo_alloc(&tport->write_fifo, TI_WRITE_BUF_SIZE, - GFP_KERNEL)) { - dev_err(&dev->dev, "%s - out of memory\n", __func__); - kfree(tport); - status = -ENOMEM; - goto free_tports; - } - tport->tp_port = serial->port[i]; - tport->tp_tdev = tdev; - usb_set_serial_port_data(serial->port[i], tport); - tport->tp_uart_mode = 0; /* default is RS232 */ - } - return 0; -free_tports: - for (--i; i >= 0; --i) { - tport = usb_get_serial_port_data(serial->port[i]); - kfifo_free(&tport->write_fifo); - kfree(tport); - usb_set_serial_port_data(serial->port[i], NULL); - } free_tdev: kfree(tdev); usb_set_serial_data(serial, NULL); @@ -476,23 +348,45 @@ free_tdev: static void ti_release(struct usb_serial *serial) { - int i; struct ti_device *tdev = usb_get_serial_data(serial); + + kfree(tdev); +} + +static int ti_port_probe(struct usb_serial_port *port) +{ struct ti_port *tport; - dbg("%s", __func__); + tport = kzalloc(sizeof(*tport), GFP_KERNEL); + if (!tport) + return -ENOMEM; - for (i = 0; i < serial->num_ports; ++i) { - tport = usb_get_serial_port_data(serial->port[i]); - if (tport) { - kfifo_free(&tport->write_fifo); - kfree(tport); - } - } + spin_lock_init(&tport->tp_lock); + if (port == port->serial->port[0]) + tport->tp_uart_base_addr = TI_UART1_BASE_ADDR; + else + tport->tp_uart_base_addr = TI_UART2_BASE_ADDR; + port->port.closing_wait = msecs_to_jiffies(10 * closing_wait); + tport->tp_port = port; + tport->tp_tdev = usb_get_serial_data(port->serial); + tport->tp_uart_mode = 0; /* default is RS232 */ - kfree(tdev); + usb_set_serial_port_data(port, tport); + + port->port.drain_delay = 3; + + return 0; } +static int ti_port_remove(struct usb_serial_port *port) +{ + struct ti_port *tport; + + tport = usb_get_serial_port_data(port); + kfree(tport); + + return 0; +} static int ti_open(struct tty_struct *tty, struct usb_serial_port *port) { @@ -506,8 +400,6 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port) TI_PIPE_TIMEOUT_ENABLE | (TI_TRANSFER_TIMEOUT << 2)); - dbg("%s - port %d", __func__, port->number); - if (tport == NULL) return -ENODEV; @@ -518,48 +410,41 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port) if (mutex_lock_interruptible(&tdev->td_open_close_lock)) return -ERESTARTSYS; - port_number = port->number - port->serial->minor; - - memset(&(tport->tp_icount), 0x00, sizeof(tport->tp_icount)); + port_number = port->port_number; tport->tp_msr = 0; tport->tp_shadow_mcr |= (TI_MCR_RTS | TI_MCR_DTR); /* start interrupt urb the first time a port is opened on this device */ if (tdev->td_open_port_count == 0) { - dbg("%s - start interrupt in urb", __func__); + dev_dbg(&port->dev, "%s - start interrupt in urb\n", __func__); urb = tdev->td_serial->port[0]->interrupt_in_urb; if (!urb) { - dev_err(&port->dev, "%s - no interrupt urb\n", - __func__); + dev_err(&port->dev, "%s - no interrupt urb\n", __func__); status = -EINVAL; goto release_lock; } - urb->complete = ti_interrupt_callback; urb->context = tdev; - urb->dev = dev; status = usb_submit_urb(urb, GFP_KERNEL); if (status) { - dev_err(&port->dev, - "%s - submit interrupt urb failed, %d\n", - __func__, status); + dev_err(&port->dev, "%s - submit interrupt urb failed, %d\n", __func__, status); goto release_lock; } } if (tty) - ti_set_termios(tty, port, tty->termios); + ti_set_termios(tty, port, &tty->termios); - dbg("%s - sending TI_OPEN_PORT", __func__); + dev_dbg(&port->dev, "%s - sending TI_OPEN_PORT\n", __func__); status = ti_command_out_sync(tdev, TI_OPEN_PORT, (__u8)(TI_UART1_PORT + port_number), open_settings, NULL, 0); if (status) { dev_err(&port->dev, "%s - cannot send open command, %d\n", - __func__, status); + __func__, status); goto unlink_int_urb; } - dbg("%s - sending TI_START_PORT", __func__); + dev_dbg(&port->dev, "%s - sending TI_START_PORT\n", __func__); status = ti_command_out_sync(tdev, TI_START_PORT, (__u8)(TI_UART1_PORT + port_number), 0, NULL, 0); if (status) { @@ -568,7 +453,7 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port) goto unlink_int_urb; } - dbg("%s - sending TI_PURGE_PORT", __func__); + dev_dbg(&port->dev, "%s - sending TI_PURGE_PORT\n", __func__); status = ti_command_out_sync(tdev, TI_PURGE_PORT, (__u8)(TI_UART1_PORT + port_number), TI_PURGE_INPUT, NULL, 0); if (status) { @@ -590,9 +475,9 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port) usb_clear_halt(dev, port->read_urb->pipe); if (tty) - ti_set_termios(tty, port, tty->termios); + ti_set_termios(tty, port, &tty->termios); - dbg("%s - sending TI_OPEN_PORT (2)", __func__); + dev_dbg(&port->dev, "%s - sending TI_OPEN_PORT (2)\n", __func__); status = ti_command_out_sync(tdev, TI_OPEN_PORT, (__u8)(TI_UART1_PORT + port_number), open_settings, NULL, 0); if (status) { @@ -601,7 +486,7 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port) goto unlink_int_urb; } - dbg("%s - sending TI_START_PORT (2)", __func__); + dev_dbg(&port->dev, "%s - sending TI_START_PORT (2)\n", __func__); status = ti_command_out_sync(tdev, TI_START_PORT, (__u8)(TI_UART1_PORT + port_number), 0, NULL, 0); if (status) { @@ -611,7 +496,7 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port) } /* start read urb */ - dbg("%s - start read urb", __func__); + dev_dbg(&port->dev, "%s - start read urb\n", __func__); urb = port->read_urb; if (!urb) { dev_err(&port->dev, "%s - no read urb\n", __func__); @@ -619,9 +504,7 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port) goto unlink_int_urb; } tport->tp_read_urb_state = TI_READ_URB_RUNNING; - urb->complete = ti_bulk_in_callback; urb->context = tport; - urb->dev = dev; status = usb_submit_urb(urb, GFP_KERNEL); if (status) { dev_err(&port->dev, "%s - submit read urb failed, %d\n", @@ -639,7 +522,7 @@ unlink_int_urb: usb_kill_urb(port->serial->port[0]->interrupt_in_urb); release_lock: mutex_unlock(&tdev->td_open_close_lock); - dbg("%s - exit %d", __func__, status); + dev_dbg(&port->dev, "%s - exit %d\n", __func__, status); return status; } @@ -651,8 +534,7 @@ static void ti_close(struct usb_serial_port *port) int port_number; int status; int do_unlock; - - dbg("%s - port %d", __func__, port->number); + unsigned long flags; tdev = usb_get_serial_data(port->serial); tport = usb_get_serial_port_data(port); @@ -661,15 +543,16 @@ static void ti_close(struct usb_serial_port *port) tport->tp_is_open = 0; - ti_drain(tport, (tport->tp_closing_wait*HZ)/100, 1); - usb_kill_urb(port->read_urb); usb_kill_urb(port->write_urb); tport->tp_write_urb_in_use = 0; + spin_lock_irqsave(&tport->tp_lock, flags); + kfifo_reset_out(&port->write_fifo); + spin_unlock_irqrestore(&tport->tp_lock, flags); - port_number = port->number - port->serial->minor; + port_number = port->port_number; - dbg("%s - sending TI_CLOSE_PORT", __func__); + dev_dbg(&port->dev, "%s - sending TI_CLOSE_PORT\n", __func__); status = ti_command_out_sync(tdev, TI_CLOSE_PORT, (__u8)(TI_UART1_PORT + port_number), 0, NULL, 0); if (status) @@ -687,8 +570,6 @@ static void ti_close(struct usb_serial_port *port) } if (do_unlock) mutex_unlock(&tdev->td_open_close_lock); - - dbg("%s - exit", __func__); } @@ -697,17 +578,15 @@ static int ti_write(struct tty_struct *tty, struct usb_serial_port *port, { struct ti_port *tport = usb_get_serial_port_data(port); - dbg("%s - port %d", __func__, port->number); - if (count == 0) { - dbg("%s - write request of 0 bytes", __func__); + dev_dbg(&port->dev, "%s - write request of 0 bytes\n", __func__); return 0; } if (tport == NULL || !tport->tp_is_open) return -ENODEV; - count = kfifo_in_locked(&tport->write_fifo, data, count, + count = kfifo_in_locked(&port->write_fifo, data, count, &tport->tp_lock); ti_send(tport); @@ -722,16 +601,14 @@ static int ti_write_room(struct tty_struct *tty) int room = 0; unsigned long flags; - dbg("%s - port %d", __func__, port->number); - if (tport == NULL) return 0; spin_lock_irqsave(&tport->tp_lock, flags); - room = kfifo_avail(&tport->write_fifo); + room = kfifo_avail(&port->write_fifo); spin_unlock_irqrestore(&tport->tp_lock, flags); - dbg("%s - returns %d", __func__, room); + dev_dbg(&port->dev, "%s - returns %d\n", __func__, room); return room; } @@ -743,27 +620,35 @@ static int ti_chars_in_buffer(struct tty_struct *tty) int chars = 0; unsigned long flags; - dbg("%s - port %d", __func__, port->number); - if (tport == NULL) return 0; spin_lock_irqsave(&tport->tp_lock, flags); - chars = kfifo_len(&tport->write_fifo); + chars = kfifo_len(&port->write_fifo); spin_unlock_irqrestore(&tport->tp_lock, flags); - dbg("%s - returns %d", __func__, chars); + dev_dbg(&port->dev, "%s - returns %d\n", __func__, chars); return chars; } +static bool ti_tx_empty(struct usb_serial_port *port) +{ + struct ti_port *tport = usb_get_serial_port_data(port); + int ret; + u8 lsr; + + ret = ti_get_lsr(tport, &lsr); + if (!ret && !(lsr & TI_LSR_TX_EMPTY)) + return false; + + return true; +} static void ti_throttle(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; struct ti_port *tport = usb_get_serial_port_data(port); - dbg("%s - port %d", __func__, port->number); - if (tport == NULL) return; @@ -779,8 +664,6 @@ static void ti_unthrottle(struct tty_struct *tty) struct ti_port *tport = usb_get_serial_port_data(port); int status; - dbg("%s - port %d", __func__, port->number); - if (tport == NULL) return; @@ -792,73 +675,24 @@ static void ti_unthrottle(struct tty_struct *tty) } } -static int ti_get_icount(struct tty_struct *tty, - struct serial_icounter_struct *icount) -{ - struct usb_serial_port *port = tty->driver_data; - struct ti_port *tport = usb_get_serial_port_data(port); - struct async_icount cnow = tport->tp_icount; - - dbg("%s - (%d) TIOCGICOUNT RX=%d, TX=%d", - __func__, port->number, - cnow.rx, cnow.tx); - - icount->cts = cnow.cts; - icount->dsr = cnow.dsr; - icount->rng = cnow.rng; - icount->dcd = cnow.dcd; - icount->rx = cnow.rx; - icount->tx = cnow.tx; - icount->frame = cnow.frame; - icount->overrun = cnow.overrun; - icount->parity = cnow.parity; - icount->brk = cnow.brk; - icount->buf_overrun = cnow.buf_overrun; - - return 0; -} - -static int ti_ioctl(struct tty_struct *tty, struct file *file, +static int ti_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { struct usb_serial_port *port = tty->driver_data; struct ti_port *tport = usb_get_serial_port_data(port); - struct async_icount cnow; - struct async_icount cprev; - - dbg("%s - port %d, cmd = 0x%04X", __func__, port->number, cmd); if (tport == NULL) return -ENODEV; switch (cmd) { case TIOCGSERIAL: - dbg("%s - (%d) TIOCGSERIAL", __func__, port->number); + dev_dbg(&port->dev, "%s - TIOCGSERIAL\n", __func__); return ti_get_serial_info(tport, (struct serial_struct __user *)arg); case TIOCSSERIAL: - dbg("%s - (%d) TIOCSSERIAL", __func__, port->number); + dev_dbg(&port->dev, "%s - TIOCSSERIAL\n", __func__); return ti_set_serial_info(tty, tport, (struct serial_struct __user *)arg); - case TIOCMIWAIT: - dbg("%s - (%d) TIOCMIWAIT", __func__, port->number); - cprev = tport->tp_icount; - while (1) { - interruptible_sleep_on(&tport->tp_msr_wait); - if (signal_pending(current)) - return -ERESTARTSYS; - cnow = tport->tp_icount; - if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && - cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) - return -EIO; /* no change => error */ - if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || - ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || - ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || - ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) - return 0; - cprev = cnow; - } - break; } return -ENOIOCTLCMD; } @@ -872,26 +706,22 @@ static void ti_set_termios(struct tty_struct *tty, tcflag_t cflag, iflag; int baud; int status; - int port_number = port->number - port->serial->minor; + int port_number = port->port_number; unsigned int mcr; - dbg("%s - port %d", __func__, port->number); + cflag = tty->termios.c_cflag; + iflag = tty->termios.c_iflag; - cflag = tty->termios->c_cflag; - iflag = tty->termios->c_iflag; - - dbg("%s - cflag %08x, iflag %08x", __func__, cflag, iflag); - dbg("%s - old clfag %08x, old iflag %08x", __func__, - old_termios->c_cflag, old_termios->c_iflag); + dev_dbg(&port->dev, "%s - cflag %08x, iflag %08x\n", __func__, cflag, iflag); + dev_dbg(&port->dev, "%s - old clfag %08x, old iflag %08x\n", __func__, + old_termios->c_cflag, old_termios->c_iflag); if (tport == NULL) return; config = kmalloc(sizeof(*config), GFP_KERNEL); - if (!config) { - dev_err(&port->dev, "%s - out of memory\n", __func__); + if (!config) return; - } config->wFlags = 0; @@ -917,7 +747,7 @@ static void ti_set_termios(struct tty_struct *tty, } /* CMSPAR isn't supported by this driver */ - tty->termios->c_cflag &= ~CMSPAR; + tty->termios.c_cflag &= ~CMSPAR; if (cflag & PARENB) { if (cflag & PARODD) { @@ -972,8 +802,11 @@ static void ti_set_termios(struct tty_struct *tty, if ((cflag & CBAUD) != B0) tty_encode_baud_rate(tty, baud, baud); - dbg("%s - BaudRate=%d, wBaudRate=%d, wFlags=0x%04X, bDataBits=%d, bParity=%d, bStopBits=%d, cXon=%d, cXoff=%d, bUartMode=%d", - __func__, baud, config->wBaudRate, config->wFlags, config->bDataBits, config->bParity, config->bStopBits, config->cXon, config->cXoff, config->bUartMode); + dev_dbg(&port->dev, + "%s - BaudRate=%d, wBaudRate=%d, wFlags=0x%04X, bDataBits=%d, bParity=%d, bStopBits=%d, cXon=%d, cXoff=%d, bUartMode=%d\n", + __func__, baud, config->wBaudRate, config->wFlags, + config->bDataBits, config->bParity, config->bStopBits, + config->cXon, config->cXoff, config->bUartMode); cpu_to_be16s(&config->wBaudRate); cpu_to_be16s(&config->wFlags); @@ -1000,7 +833,7 @@ static void ti_set_termios(struct tty_struct *tty, } -static int ti_tiocmget(struct tty_struct *tty, struct file *file) +static int ti_tiocmget(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; struct ti_port *tport = usb_get_serial_port_data(port); @@ -1009,8 +842,6 @@ static int ti_tiocmget(struct tty_struct *tty, struct file *file) unsigned int mcr; unsigned long flags; - dbg("%s - port %d", __func__, port->number); - if (tport == NULL) return -ENODEV; @@ -1027,22 +858,20 @@ static int ti_tiocmget(struct tty_struct *tty, struct file *file) | ((msr & TI_MSR_RI) ? TIOCM_RI : 0) | ((msr & TI_MSR_DSR) ? TIOCM_DSR : 0); - dbg("%s - 0x%04X", __func__, result); + dev_dbg(&port->dev, "%s - 0x%04X\n", __func__, result); return result; } -static int ti_tiocmset(struct tty_struct *tty, struct file *file, - unsigned int set, unsigned int clear) +static int ti_tiocmset(struct tty_struct *tty, + unsigned int set, unsigned int clear) { struct usb_serial_port *port = tty->driver_data; struct ti_port *tport = usb_get_serial_port_data(port); unsigned int mcr; unsigned long flags; - dbg("%s - port %d", __func__, port->number); - if (tport == NULL) return -ENODEV; @@ -1074,19 +903,17 @@ static void ti_break(struct tty_struct *tty, int break_state) struct ti_port *tport = usb_get_serial_port_data(port); int status; - dbg("%s - state = %d", __func__, break_state); + dev_dbg(&port->dev, "%s - state = %d\n", __func__, break_state); if (tport == NULL) return; - ti_drain(tport, (tport->tp_closing_wait*HZ)/100, 0); - - status = ti_write_byte(tport->tp_tdev, + status = ti_write_byte(port, tport->tp_tdev, tport->tp_uart_base_addr + TI_UART_OFFSET_LCR, TI_LCR_BREAK, break_state == -1 ? TI_LCR_BREAK : 0); if (status) - dbg("%s - error setting break, %d", __func__, status); + dev_dbg(&port->dev, "%s - error setting break, %d\n", __func__, status); } @@ -1105,26 +932,23 @@ static void ti_interrupt_callback(struct urb *urb) int retval; __u8 msr; - dbg("%s", __func__); - switch (status) { case 0: break; case -ECONNRESET: case -ENOENT: case -ESHUTDOWN: - dbg("%s - urb shutting down, %d", __func__, status); + dev_dbg(dev, "%s - urb shutting down, %d\n", __func__, status); tdev->td_urb_error = 1; return; default: - dev_err(dev, "%s - nonzero urb status, %d\n", - __func__, status); + dev_err(dev, "%s - nonzero urb status, %d\n", __func__, status); tdev->td_urb_error = 1; goto exit; } if (length != 2) { - dbg("%s - bad packet size, %d", __func__, length); + dev_dbg(dev, "%s - bad packet size, %d\n", __func__, length); goto exit; } @@ -1136,8 +960,8 @@ static void ti_interrupt_callback(struct urb *urb) port_number = TI_GET_PORT_FROM_CODE(data[0]); function = TI_GET_FUNC_FROM_CODE(data[0]); - dbg("%s - port_number %d, function %d, data 0x%02X", - __func__, port_number, function, data[1]); + dev_dbg(dev, "%s - port_number %d, function %d, data 0x%02X\n", + __func__, port_number, function, data[1]); if (port_number >= serial->num_ports) { dev_err(dev, "%s - bad port number, %d\n", @@ -1154,12 +978,12 @@ static void ti_interrupt_callback(struct urb *urb) switch (function) { case TI_CODE_DATA_ERROR: dev_err(dev, "%s - DATA ERROR, port %d, data 0x%02X\n", - __func__, port_number, data[1]); + __func__, port_number, data[1]); break; case TI_CODE_MODEM_STATUS: msr = data[1]; - dbg("%s - port %d, msr 0x%02X", __func__, port_number, msr); + dev_dbg(dev, "%s - port %d, msr 0x%02X\n", __func__, port_number, msr); ti_handle_new_msr(tport, msr); break; @@ -1184,9 +1008,6 @@ static void ti_bulk_in_callback(struct urb *urb) struct device *dev = &urb->dev->dev; int status = urb->status; int retval = 0; - struct tty_struct *tty; - - dbg("%s", __func__); switch (status) { case 0: @@ -1194,15 +1015,13 @@ static void ti_bulk_in_callback(struct urb *urb) case -ECONNRESET: case -ENOENT: case -ESHUTDOWN: - dbg("%s - urb shutting down, %d", __func__, status); + dev_dbg(dev, "%s - urb shutting down, %d\n", __func__, status); tport->tp_tdev->td_urb_error = 1; - wake_up_interruptible(&tport->tp_write_wait); return; default: dev_err(dev, "%s - nonzero urb status, %d\n", __func__, status); tport->tp_tdev->td_urb_error = 1; - wake_up_interruptible(&tport->tp_write_wait); } if (status == -EPIPE) @@ -1213,35 +1032,28 @@ static void ti_bulk_in_callback(struct urb *urb) return; } - tty = tty_port_tty_get(&port->port); - if (tty) { - if (urb->actual_length) { - usb_serial_debug_data(debug, dev, __func__, - urb->actual_length, urb->transfer_buffer); + if (urb->actual_length) { + usb_serial_debug_data(dev, __func__, urb->actual_length, + urb->transfer_buffer); - if (!tport->tp_is_open) - dbg("%s - port closed, dropping data", - __func__); - else - ti_recv(&urb->dev->dev, tty, - urb->transfer_buffer, - urb->actual_length); - spin_lock(&tport->tp_lock); - tport->tp_icount.rx += urb->actual_length; - spin_unlock(&tport->tp_lock); - } - tty_kref_put(tty); + if (!tport->tp_is_open) + dev_dbg(dev, "%s - port closed, dropping data\n", + __func__); + else + ti_recv(port, urb->transfer_buffer, urb->actual_length); + spin_lock(&tport->tp_lock); + port->icount.rx += urb->actual_length; + spin_unlock(&tport->tp_lock); } exit: /* continue to read unless stopping */ spin_lock(&tport->tp_lock); - if (tport->tp_read_urb_state == TI_READ_URB_RUNNING) { - urb->dev = port->serial->dev; + if (tport->tp_read_urb_state == TI_READ_URB_RUNNING) retval = usb_submit_urb(urb, GFP_ATOMIC); - } else if (tport->tp_read_urb_state == TI_READ_URB_STOPPING) { + else if (tport->tp_read_urb_state == TI_READ_URB_STOPPING) tport->tp_read_urb_state = TI_READ_URB_STOPPED; - } + spin_unlock(&tport->tp_lock); if (retval) dev_err(dev, "%s - resubmit read urb failed, %d\n", @@ -1253,11 +1065,8 @@ static void ti_bulk_out_callback(struct urb *urb) { struct ti_port *tport = urb->context; struct usb_serial_port *port = tport->tp_port; - struct device *dev = &urb->dev->dev; int status = urb->status; - dbg("%s - port %d", __func__, port->number); - tport->tp_write_urb_in_use = 0; switch (status) { @@ -1266,15 +1075,13 @@ static void ti_bulk_out_callback(struct urb *urb) case -ECONNRESET: case -ENOENT: case -ESHUTDOWN: - dbg("%s - urb shutting down, %d", __func__, status); + dev_dbg(&port->dev, "%s - urb shutting down, %d\n", __func__, status); tport->tp_tdev->td_urb_error = 1; - wake_up_interruptible(&tport->tp_write_wait); return; default: - dev_err(dev, "%s - nonzero urb status, %d\n", + dev_err_console(port, "%s - nonzero urb status, %d\n", __func__, status); tport->tp_tdev->td_urb_error = 1; - wake_up_interruptible(&tport->tp_write_wait); } /* send any buffered data */ @@ -1282,24 +1089,23 @@ static void ti_bulk_out_callback(struct urb *urb) } -static void ti_recv(struct device *dev, struct tty_struct *tty, - unsigned char *data, int length) +static void ti_recv(struct usb_serial_port *port, unsigned char *data, + int length) { int cnt; do { - cnt = tty_insert_flip_string(tty, data, length); + cnt = tty_insert_flip_string(&port->port, data, length); if (cnt < length) { - dev_err(dev, "%s - dropping data, %d bytes lost\n", + dev_err(&port->dev, "%s - dropping data, %d bytes lost\n", __func__, length - cnt); if (cnt == 0) break; } - tty_flip_buffer_push(tty); + tty_flip_buffer_push(&port->port); data += cnt; length -= cnt; } while (length > 0); - } @@ -1307,18 +1113,14 @@ static void ti_send(struct ti_port *tport) { int count, result; struct usb_serial_port *port = tport->tp_port; - struct tty_struct *tty = tty_port_tty_get(&port->port); /* FIXME */ unsigned long flags; - - dbg("%s - port %d", __func__, port->number); - spin_lock_irqsave(&tport->tp_lock, flags); if (tport->tp_write_urb_in_use) goto unlock; - count = kfifo_out(&tport->write_fifo, + count = kfifo_out(&port->write_fifo, port->write_urb->transfer_buffer, port->bulk_out_size); @@ -1329,8 +1131,8 @@ static void ti_send(struct ti_port *tport) spin_unlock_irqrestore(&tport->tp_lock, flags); - usb_serial_debug_data(debug, &port->dev, __func__, count, - port->write_urb->transfer_buffer); + usb_serial_debug_data(&port->dev, __func__, count, + port->write_urb->transfer_buffer); usb_fill_bulk_urb(port->write_urb, port->serial->dev, usb_sndbulkpipe(port->serial->dev, @@ -1340,25 +1142,22 @@ static void ti_send(struct ti_port *tport) result = usb_submit_urb(port->write_urb, GFP_ATOMIC); if (result) { - dev_err(&port->dev, "%s - submit write urb failed, %d\n", + dev_err_console(port, "%s - submit write urb failed, %d\n", __func__, result); tport->tp_write_urb_in_use = 0; /* TODO: reschedule ti_send */ } else { spin_lock_irqsave(&tport->tp_lock, flags); - tport->tp_icount.tx += count; + port->icount.tx += count; spin_unlock_irqrestore(&tport->tp_lock, flags); } /* more room in the buffer for new writes, wakeup */ - if (tty) - tty_wakeup(tty); - tty_kref_put(tty); - wake_up_interruptible(&tport->tp_write_wait); + tty_port_tty_wakeup(&port->port); + return; unlock: spin_unlock_irqrestore(&tport->tp_lock, flags); - tty_kref_put(tty); return; } @@ -1368,7 +1167,7 @@ static int ti_set_mcr(struct ti_port *tport, unsigned int mcr) unsigned long flags; int status; - status = ti_write_byte(tport->tp_tdev, + status = ti_write_byte(tport->tp_port, tport->tp_tdev, tport->tp_uart_base_addr + TI_UART_OFFSET_MCR, TI_MCR_RTS | TI_MCR_DTR | TI_MCR_LOOP, mcr); @@ -1381,22 +1180,18 @@ static int ti_set_mcr(struct ti_port *tport, unsigned int mcr) } -static int ti_get_lsr(struct ti_port *tport) +static int ti_get_lsr(struct ti_port *tport, u8 *lsr) { int size, status; struct ti_device *tdev = tport->tp_tdev; struct usb_serial_port *port = tport->tp_port; - int port_number = port->number - port->serial->minor; + int port_number = port->port_number; struct ti_port_status *data; - dbg("%s - port %d", __func__, port->number); - size = sizeof(struct ti_port_status); data = kmalloc(size, GFP_KERNEL); - if (!data) { - dev_err(&port->dev, "%s - out of memory\n", __func__); + if (!data) return -ENOMEM; - } status = ti_command_in_sync(tdev, TI_GET_PORT_STATUS, (__u8)(TI_UART1_PORT+port_number), 0, (__u8 *)data, size); @@ -1407,9 +1202,9 @@ static int ti_get_lsr(struct ti_port *tport) goto free_data; } - dbg("%s - lsr 0x%02X", __func__, data->bLSR); + dev_dbg(&port->dev, "%s - lsr 0x%02X\n", __func__, data->bLSR); - tport->tp_lsr = data->bLSR; + *lsr = data->bLSR; free_data: kfree(data); @@ -1422,19 +1217,24 @@ static int ti_get_serial_info(struct ti_port *tport, { struct usb_serial_port *port = tport->tp_port; struct serial_struct ret_serial; + unsigned cwait; if (!ret_arg) return -EFAULT; + cwait = port->port.closing_wait; + if (cwait != ASYNC_CLOSING_WAIT_NONE) + cwait = jiffies_to_msecs(cwait) / 10; + memset(&ret_serial, 0, sizeof(ret_serial)); ret_serial.type = PORT_16550A; - ret_serial.line = port->serial->minor; - ret_serial.port = port->number - port->serial->minor; + ret_serial.line = port->minor; + ret_serial.port = port->port_number; ret_serial.flags = tport->tp_flags; - ret_serial.xmit_fifo_size = TI_WRITE_BUF_SIZE; + ret_serial.xmit_fifo_size = kfifo_size(&port->write_fifo); ret_serial.baud_base = tport->tp_tdev->td_is_3410 ? 921600 : 460800; - ret_serial.closing_wait = tport->tp_closing_wait; + ret_serial.closing_wait = cwait; if (copy_to_user(ret_arg, &ret_serial, sizeof(*ret_arg))) return -EFAULT; @@ -1447,12 +1247,17 @@ static int ti_set_serial_info(struct tty_struct *tty, struct ti_port *tport, struct serial_struct __user *new_arg) { struct serial_struct new_serial; + unsigned cwait; if (copy_from_user(&new_serial, new_arg, sizeof(new_serial))) return -EFAULT; + cwait = new_serial.closing_wait; + if (cwait != ASYNC_CLOSING_WAIT_NONE) + cwait = msecs_to_jiffies(10 * new_serial.closing_wait); + tport->tp_flags = new_serial.flags & TI_SET_SERIAL_FLAGS; - tport->tp_closing_wait = new_serial.closing_wait; + tport->tp_port->port.closing_wait = cwait; return 0; } @@ -1464,11 +1269,11 @@ static void ti_handle_new_msr(struct ti_port *tport, __u8 msr) struct tty_struct *tty; unsigned long flags; - dbg("%s - msr 0x%02X", __func__, msr); + dev_dbg(&tport->tp_port->dev, "%s - msr 0x%02X\n", __func__, msr); if (msr & TI_MSR_DELTA_MASK) { spin_lock_irqsave(&tport->tp_lock, flags); - icount = &tport->tp_icount; + icount = &tport->tp_port->icount; if (msr & TI_MSR_DELTA_CTS) icount->cts++; if (msr & TI_MSR_DELTA_DSR) @@ -1477,7 +1282,7 @@ static void ti_handle_new_msr(struct ti_port *tport, __u8 msr) icount->dcd++; if (msr & TI_MSR_DELTA_RI) icount->rng++; - wake_up_interruptible(&tport->tp_msr_wait); + wake_up_interruptible(&tport->tp_port->port.delta_msr_wait); spin_unlock_irqrestore(&tport->tp_lock, flags); } @@ -1497,58 +1302,6 @@ static void ti_handle_new_msr(struct ti_port *tport, __u8 msr) } -static void ti_drain(struct ti_port *tport, unsigned long timeout, int flush) -{ - struct ti_device *tdev = tport->tp_tdev; - struct usb_serial_port *port = tport->tp_port; - wait_queue_t wait; - - dbg("%s - port %d", __func__, port->number); - - spin_lock_irq(&tport->tp_lock); - - /* wait for data to drain from the buffer */ - tdev->td_urb_error = 0; - init_waitqueue_entry(&wait, current); - add_wait_queue(&tport->tp_write_wait, &wait); - for (;;) { - set_current_state(TASK_INTERRUPTIBLE); - if (kfifo_len(&tport->write_fifo) == 0 - || timeout == 0 || signal_pending(current) - || tdev->td_urb_error - || port->serial->disconnected) /* disconnect */ - break; - spin_unlock_irq(&tport->tp_lock); - timeout = schedule_timeout(timeout); - spin_lock_irq(&tport->tp_lock); - } - set_current_state(TASK_RUNNING); - remove_wait_queue(&tport->tp_write_wait, &wait); - - /* flush any remaining data in the buffer */ - if (flush) - kfifo_reset_out(&tport->write_fifo); - - spin_unlock_irq(&tport->tp_lock); - - mutex_lock(&port->serial->disc_mutex); - /* wait for data to drain from the device */ - /* wait for empty tx register, plus 20 ms */ - timeout += jiffies; - tport->tp_lsr &= ~TI_LSR_TX_EMPTY; - while ((long)(jiffies - timeout) < 0 && !signal_pending(current) - && !(tport->tp_lsr&TI_LSR_TX_EMPTY) && !tdev->td_urb_error - && !port->serial->disconnected) { - if (ti_get_lsr(tport)) - break; - mutex_unlock(&port->serial->disc_mutex); - msleep_interruptible(20); - mutex_lock(&port->serial->disc_mutex); - } - mutex_unlock(&port->serial->disc_mutex); -} - - static void ti_stop_read(struct ti_port *tport, struct tty_struct *tty) { unsigned long flags; @@ -1574,9 +1327,7 @@ static int ti_restart_read(struct ti_port *tport, struct tty_struct *tty) tport->tp_read_urb_state = TI_READ_URB_RUNNING; urb = tport->tp_port->read_urb; spin_unlock_irqrestore(&tport->tp_lock, flags); - urb->complete = ti_bulk_in_callback; urb->context = tport; - urb->dev = tport->tp_port->serial->dev; status = usb_submit_urb(urb, GFP_KERNEL); } else { tport->tp_read_urb_state = TI_READ_URB_RUNNING; @@ -1627,23 +1378,21 @@ static int ti_command_in_sync(struct ti_device *tdev, __u8 command, } -static int ti_write_byte(struct ti_device *tdev, unsigned long addr, - __u8 mask, __u8 byte) +static int ti_write_byte(struct usb_serial_port *port, + struct ti_device *tdev, unsigned long addr, + __u8 mask, __u8 byte) { int status; unsigned int size; struct ti_write_data_bytes *data; - struct device *dev = &tdev->td_serial->dev->dev; - dbg("%s - addr 0x%08lX, mask 0x%02X, byte 0x%02X", - __func__, addr, mask, byte); + dev_dbg(&port->dev, "%s - addr 0x%08lX, mask 0x%02X, byte 0x%02X\n", __func__, + addr, mask, byte); size = sizeof(struct ti_write_data_bytes) + 2; data = kmalloc(size, GFP_KERNEL); - if (!data) { - dev_err(dev, "%s - out of memory\n", __func__); + if (!data) return -ENOMEM; - } data->bAddrType = TI_RW_DATA_ADDR_XDATA; data->bDataType = TI_RW_DATA_BYTE; @@ -1657,7 +1406,7 @@ static int ti_write_byte(struct ti_device *tdev, unsigned long addr, (__u8 *)data, size); if (status < 0) - dev_err(dev, "%s - failed, %d\n", __func__, status); + dev_err(&port->dev, "%s - failed, %d\n", __func__, status); kfree(data); @@ -1682,7 +1431,7 @@ static int ti_do_download(struct usb_device *dev, int pipe, - sizeof(struct ti_firmware_header))); header->bCheckSum = cs; - dbg("%s - downloading firmware", __func__); + dev_dbg(&dev->dev, "%s - downloading firmware\n", __func__); for (pos = 0; pos < size; pos += done) { len = min(size - pos, TI_DOWNLOAD_MAX_PACKET_SIZE); status = usb_bulk_msg(dev, pipe, buffer + pos, len, @@ -1704,14 +1453,16 @@ static int ti_download_firmware(struct ti_device *tdev) const struct firmware *fw_p; char buf[32]; - dbg("%s\n", __func__); /* try ID specific firmware first, then try generic firmware */ - sprintf(buf, "ti_usb-v%04x-p%04x.fw", dev->descriptor.idVendor, - dev->descriptor.idProduct); - if ((status = request_firmware(&fw_p, buf, &dev->dev)) != 0) { + sprintf(buf, "ti_usb-v%04x-p%04x.fw", + le16_to_cpu(dev->descriptor.idVendor), + le16_to_cpu(dev->descriptor.idProduct)); + status = request_firmware(&fw_p, buf, &dev->dev); + + if (status != 0) { buf[0] = '\0'; - if (dev->descriptor.idVendor == MTS_VENDOR_ID) { - switch (dev->descriptor.idProduct) { + if (le16_to_cpu(dev->descriptor.idVendor) == MTS_VENDOR_ID) { + switch (le16_to_cpu(dev->descriptor.idProduct)) { case MTS_CDMA_PRODUCT_ID: strcpy(buf, "mts_cdma.fw"); break; @@ -1745,6 +1496,7 @@ static int ti_download_firmware(struct ti_device *tdev) } if (fw_p->size > TI_FIRMWARE_BUF_SIZE) { dev_err(&dev->dev, "%s - firmware too large %zu\n", __func__, fw_p->size); + release_firmware(fw_p); return -ENOENT; } @@ -1756,7 +1508,6 @@ static int ti_download_firmware(struct ti_device *tdev) status = ti_do_download(dev, pipe, buffer, fw_p->size); kfree(buffer); } else { - dbg("%s ENOMEM\n", __func__); status = -ENOMEM; } release_firmware(fw_p); @@ -1766,7 +1517,7 @@ static int ti_download_firmware(struct ti_device *tdev) return status; } - dbg("%s - download successful", __func__); + dev_dbg(&dev->dev, "%s - download successful\n", __func__); return 0; } diff --git a/drivers/usb/serial/ti_usb_3410_5052.h b/drivers/usb/serial/ti_usb_3410_5052.h index 2aac1953993..4a2423e84d5 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.h +++ b/drivers/usb/serial/ti_usb_3410_5052.h @@ -37,6 +37,7 @@ #define TI_5152_BOOT_PRODUCT_ID 0x5152 /* no EEPROM, no firmware */ #define TI_5052_EEPROM_PRODUCT_ID 0x505A /* EEPROM, no firmware */ #define TI_5052_FIRMWARE_PRODUCT_ID 0x505F /* firmware is running */ +#define FRI2_PRODUCT_ID 0x5053 /* Fish River Island II */ /* Multi-Tech vendor and product ids */ #define MTS_VENDOR_ID 0x06E0 @@ -49,6 +50,12 @@ #define MTS_MT9234ZBA_PRODUCT_ID 0xF115 #define MTS_MT9234ZBAOLD_PRODUCT_ID 0x0319 +/* Abbott Diabetics vendor and product ids */ +#define ABBOTT_VENDOR_ID 0x1a61 +#define ABBOTT_STEREO_PLUG_ID 0x3410 +#define ABBOTT_PRODUCT_ID ABBOTT_STEREO_PLUG_ID +#define ABBOTT_STRIP_PORT_ID 0x3420 + /* Commands */ #define TI_GET_VERSION 0x01 #define TI_GET_PORT_STATUS 0x02 diff --git a/drivers/usb/serial/usb-serial-simple.c b/drivers/usb/serial/usb-serial-simple.c new file mode 100644 index 00000000000..fb79775447b --- /dev/null +++ b/drivers/usb/serial/usb-serial-simple.c @@ -0,0 +1,110 @@ +/* + * USB Serial "Simple" driver + * + * Copyright (C) 2001-2006,2008,2013 Greg Kroah-Hartman <greg@kroah.com> + * Copyright (C) 2005 Arthur Huillet (ahuillet@users.sf.net) + * Copyright (C) 2005 Thomas Hergenhahn <thomas.hergenhahn@suse.de> + * Copyright (C) 2009 Outpost Embedded, LLC + * Copyright (C) 2010 Zilogic Systems <code@zilogic.com> + * Copyright (C) 2013 Wei Shuai <cpuwolf@gmail.com> + * Copyright (C) 2013 Linux Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + */ + +#include <linux/kernel.h> +#include <linux/tty.h> +#include <linux/module.h> +#include <linux/usb.h> +#include <linux/usb/serial.h> + +#define DEVICE(vendor, IDS) \ +static const struct usb_device_id vendor##_id_table[] = { \ + IDS(), \ + { }, \ +}; \ +static struct usb_serial_driver vendor##_device = { \ + .driver = { \ + .owner = THIS_MODULE, \ + .name = #vendor, \ + }, \ + .id_table = vendor##_id_table, \ + .num_ports = 1, \ +}; + + +/* ZIO Motherboard USB driver */ +#define ZIO_IDS() \ + { USB_DEVICE(0x1CBE, 0x0103) } +DEVICE(zio, ZIO_IDS); + +/* Funsoft Serial USB driver */ +#define FUNSOFT_IDS() \ + { USB_DEVICE(0x1404, 0xcddc) } +DEVICE(funsoft, FUNSOFT_IDS); + +/* Infineon Flashloader driver */ +#define FLASHLOADER_IDS() \ + { USB_DEVICE(0x8087, 0x0716) } +DEVICE(flashloader, FLASHLOADER_IDS); + +/* ViVOpay USB Serial Driver */ +#define VIVOPAY_IDS() \ + { USB_DEVICE(0x1d5f, 0x1004) } /* ViVOpay 8800 */ +DEVICE(vivopay, VIVOPAY_IDS); + +/* Motorola USB Phone driver */ +#define MOTO_IDS() \ + { USB_DEVICE(0x05c6, 0x3197) }, /* unknown Motorola phone */ \ + { USB_DEVICE(0x0c44, 0x0022) }, /* unknown Mororola phone */ \ + { USB_DEVICE(0x22b8, 0x2a64) }, /* Motorola KRZR K1m */ \ + { USB_DEVICE(0x22b8, 0x2c84) }, /* Motorola VE240 phone */ \ + { USB_DEVICE(0x22b8, 0x2c64) } /* Motorola V950 phone */ +DEVICE(moto_modem, MOTO_IDS); + +/* HP4x (48/49) Generic Serial driver */ +#define HP4X_IDS() \ + { USB_DEVICE(0x03f0, 0x0121) } +DEVICE(hp4x, HP4X_IDS); + +/* Suunto ANT+ USB Driver */ +#define SUUNTO_IDS() \ + { USB_DEVICE(0x0fcf, 0x1008) }, \ + { USB_DEVICE(0x0fcf, 0x1009) } /* Dynastream ANT USB-m Stick */ +DEVICE(suunto, SUUNTO_IDS); + +/* Siemens USB/MPI adapter */ +#define SIEMENS_IDS() \ + { USB_DEVICE(0x908, 0x0004) } +DEVICE(siemens_mpi, SIEMENS_IDS); + +/* All of the above structures mushed into two lists */ +static struct usb_serial_driver * const serial_drivers[] = { + &zio_device, + &funsoft_device, + &flashloader_device, + &vivopay_device, + &moto_modem_device, + &hp4x_device, + &suunto_device, + &siemens_mpi_device, + NULL +}; + +static const struct usb_device_id id_table[] = { + ZIO_IDS(), + FUNSOFT_IDS(), + FLASHLOADER_IDS(), + VIVOPAY_IDS(), + MOTO_IDS(), + HP4X_IDS(), + SUUNTO_IDS(), + SIEMENS_IDS(), + { }, +}; +MODULE_DEVICE_TABLE(usb, id_table); + +module_usb_serial_driver(serial_drivers, id_table); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index e64da74bdcc..02de3110fe9 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -1,7 +1,8 @@ /* * USB Serial Converter driver * - * Copyright (C) 1999 - 2005 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (C) 2009 - 2013 Johan Hovold (jhovold@gmail.com) + * Copyright (C) 1999 - 2012 Greg Kroah-Hartman (greg@kroah.com) * Copyright (C) 2000 Peter Berger (pberger@brimson.com) * Copyright (C) 2000 Al Borchers (borchers@steinerpoint.com) * @@ -14,14 +15,14 @@ * * See Documentation/usb/usb-serial.txt for more information on using this * driver - * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/kernel.h> #include <linux/errno.h> #include <linux/init.h> #include <linux/slab.h> -#include <linux/smp_lock.h> #include <linux/tty.h> #include <linux/tty_driver.h> #include <linux/tty_flip.h> @@ -36,23 +37,14 @@ #include <linux/usb.h> #include <linux/usb/serial.h> #include <linux/kfifo.h> +#include <linux/idr.h> #include "pl2303.h" -/* - * Version Information - */ -#define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux/" +#define DRIVER_AUTHOR "Greg Kroah-Hartman <gregkh@linuxfoundation.org>" #define DRIVER_DESC "USB Serial Driver core" -/* Driver structure we register with the USB core */ -static struct usb_driver usb_serial_driver = { - .name = "usbserial", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .suspend = usb_serial_suspend, - .resume = usb_serial_resume, - .no_dynamic_id = 1, -}; +#define USB_SERIAL_TTY_MAJOR 188 +#define USB_SERIAL_TTY_MINORS 512 /* should be enough for a while */ /* There is no MODULE_DEVICE_TABLE for usbserial.c. Instead the MODULE_DEVICE_TABLE declarations in each serial driver @@ -61,85 +53,75 @@ static struct usb_driver usb_serial_driver = { drivers depend on it. */ -static int debug; -/* initially all NULL */ -static struct usb_serial *serial_table[SERIAL_TTY_MINORS]; +static DEFINE_IDR(serial_minors); static DEFINE_MUTEX(table_lock); static LIST_HEAD(usb_serial_driver_list); /* - * Look up the serial structure. If it is found and it hasn't been - * disconnected, return with its disc_mutex held and its refcount - * incremented. Otherwise return NULL. + * Look up the serial port structure. If it is found and it hasn't been + * disconnected, return with the parent usb_serial structure's disc_mutex held + * and its refcount incremented. Otherwise return NULL. */ -struct usb_serial *usb_serial_get_by_index(unsigned index) +struct usb_serial_port *usb_serial_port_get_by_minor(unsigned minor) { struct usb_serial *serial; + struct usb_serial_port *port; mutex_lock(&table_lock); - serial = serial_table[index]; - - if (serial) { - mutex_lock(&serial->disc_mutex); - if (serial->disconnected) { - mutex_unlock(&serial->disc_mutex); - serial = NULL; - } else { - kref_get(&serial->kref); - } + port = idr_find(&serial_minors, minor); + if (!port) + goto exit; + + serial = port->serial; + mutex_lock(&serial->disc_mutex); + if (serial->disconnected) { + mutex_unlock(&serial->disc_mutex); + port = NULL; + } else { + kref_get(&serial->kref); } +exit: mutex_unlock(&table_lock); - return serial; + return port; } -static struct usb_serial *get_free_serial(struct usb_serial *serial, - int num_ports, unsigned int *minor) +static int allocate_minors(struct usb_serial *serial, int num_ports) { + struct usb_serial_port *port; unsigned int i, j; - int good_spot; + int minor; - dbg("%s %d", __func__, num_ports); + dev_dbg(&serial->interface->dev, "%s %d\n", __func__, num_ports); - *minor = 0; mutex_lock(&table_lock); - for (i = 0; i < SERIAL_TTY_MINORS; ++i) { - if (serial_table[i]) - continue; - - good_spot = 1; - for (j = 1; j <= num_ports-1; ++j) - if ((i+j >= SERIAL_TTY_MINORS) || (serial_table[i+j])) { - good_spot = 0; - i += j; - break; - } - if (good_spot == 0) - continue; - - *minor = i; - j = 0; - dbg("%s - minor base = %d", __func__, *minor); - for (i = *minor; (i < (*minor + num_ports)) && (i < SERIAL_TTY_MINORS); ++i) { - serial_table[i] = serial; - serial->port[j++]->number = i; - } - mutex_unlock(&table_lock); - return serial; + for (i = 0; i < num_ports; ++i) { + port = serial->port[i]; + minor = idr_alloc(&serial_minors, port, 0, 0, GFP_KERNEL); + if (minor < 0) + goto error; + port->minor = minor; + port->port_number = i; } + serial->minors_reserved = 1; mutex_unlock(&table_lock); - return NULL; + return 0; +error: + /* unwind the already allocated minors */ + for (j = 0; j < i; ++j) + idr_remove(&serial_minors, serial->port[j]->minor); + mutex_unlock(&table_lock); + return minor; } -static void return_serial(struct usb_serial *serial) +static void release_minors(struct usb_serial *serial) { int i; - dbg("%s", __func__); - mutex_lock(&table_lock); for (i = 0; i < serial->num_ports; ++i) - serial_table[serial->minor + i] = NULL; + idr_remove(&serial_minors, serial->port[i]->minor); mutex_unlock(&table_lock); + serial->minors_reserved = 0; } static void destroy_serial(struct kref *kref) @@ -150,13 +132,11 @@ static void destroy_serial(struct kref *kref) serial = to_usb_serial(kref); - dbg("%s - %s", __func__, serial->type->description); - /* return the minor range that this device had */ - if (serial->minor != SERIAL_TTY_NO_MINOR) - return_serial(serial); + if (serial->minors_reserved) + release_minors(serial); - if (serial->attached) + if (serial->attached && serial->type->release) serial->type->release(serial); /* Now that nothing is using the ports, they can be freed */ @@ -168,6 +148,7 @@ static void destroy_serial(struct kref *kref) } } + usb_put_intf(serial->interface); usb_put_dev(serial->dev); kfree(serial); } @@ -202,27 +183,22 @@ static int serial_install(struct tty_driver *driver, struct tty_struct *tty) struct usb_serial_port *port; int retval = -ENODEV; - dbg("%s", __func__); - - serial = usb_serial_get_by_index(idx); - if (!serial) + port = usb_serial_port_get_by_minor(idx); + if (!port) return retval; - port = serial->port[idx - serial->minor]; - if (!port) - goto error_no_port; + serial = port->serial; if (!try_module_get(serial->type->driver.owner)) goto error_module_get; - /* perform the standard setup */ - retval = tty_init_termios(tty); - if (retval) - goto error_init_termios; - retval = usb_autopm_get_interface(serial->interface); if (retval) goto error_get_interface; + retval = tty_port_install(&port->port, driver, tty); + if (retval) + goto error_init_termios; + mutex_unlock(&serial->disc_mutex); /* allow the driver to update the settings */ @@ -231,23 +207,19 @@ static int serial_install(struct tty_driver *driver, struct tty_struct *tty) tty->driver_data = port; - /* Final install (we use the default method) */ - tty_driver_kref_get(driver); - tty->count++; - driver->ttys[idx] = tty; return retval; - error_get_interface: error_init_termios: + usb_autopm_put_interface(serial->interface); + error_get_interface: module_put(serial->type->driver.owner); error_module_get: - error_no_port: usb_serial_put(serial); mutex_unlock(&serial->disc_mutex); return retval; } -static int serial_activate(struct tty_port *tport, struct tty_struct *tty) +static int serial_port_activate(struct tty_port *tport, struct tty_struct *tty) { struct usb_serial_port *port = container_of(tport, struct usb_serial_port, port); @@ -260,6 +232,10 @@ static int serial_activate(struct tty_port *tport, struct tty_struct *tty) else retval = port->serial->type->open(tty, port); mutex_unlock(&serial->disc_mutex); + + if (retval < 0) + retval = usb_translate_errors(retval); + return retval; } @@ -267,30 +243,27 @@ static int serial_open(struct tty_struct *tty, struct file *filp) { struct usb_serial_port *port = tty->driver_data; - dbg("%s - port %d", __func__, port->number); + dev_dbg(tty->dev, "%s\n", __func__); + return tty_port_open(&port->port, tty, filp); } /** - * serial_down - shut down hardware + * serial_port_shutdown - shut down hardware * @tport: tty port to shut down * - * Shut down a USB serial port unless it is the console. We never - * shut down the console hardware as it will always be in use. Serialized - * against activate by the tport mutex and kept to matching open/close pairs + * Shut down a USB serial port. Serialized against activate by the + * tport mutex and kept to matching open/close pairs * of calls by the ASYNCB_INITIALIZED flag. + * + * Not called if tty is console. */ -static void serial_down(struct tty_port *tport) +static void serial_port_shutdown(struct tty_port *tport) { struct usb_serial_port *port = container_of(tport, struct usb_serial_port, port); struct usb_serial_driver *drv = port->serial->type; - /* - * The console is magical. Do not hang up the console hardware - * or there will be tears. - */ - if (port->port.console) - return; + if (drv->close) drv->close(port); } @@ -298,14 +271,18 @@ static void serial_down(struct tty_port *tport) static void serial_hangup(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; - dbg("%s - port %d", __func__, port->number); + + dev_dbg(tty->dev, "%s\n", __func__); + tty_port_hangup(&port->port); } static void serial_close(struct tty_struct *tty, struct file *filp) { struct usb_serial_port *port = tty->driver_data; - dbg("%s - port %d", __func__, port->number); + + dev_dbg(tty->dev, "%s\n", __func__); + tty_port_close(&port->port, tty, filp); } @@ -316,8 +293,7 @@ static void serial_close(struct tty_struct *tty, struct file *filp) * Do the resource freeing and refcount dropping for the port. * Avoid freeing the console. * - * Called asynchronously after the last tty kref is dropped, - * and the tty layer has already done the tty_shutdown(tty); + * Called asynchronously after the last tty kref is dropped. */ static void serial_cleanup(struct tty_struct *tty) { @@ -325,14 +301,14 @@ static void serial_cleanup(struct tty_struct *tty) struct usb_serial *serial; struct module *owner; + dev_dbg(tty->dev, "%s\n", __func__); + /* The console is magical. Do not hang up the console hardware * or there will be tears. */ if (port->port.console) return; - dbg("%s - port %d", __func__, port->number); - tty->driver_data = NULL; serial = port->serial; @@ -356,11 +332,11 @@ static int serial_write(struct tty_struct *tty, const unsigned char *buf, if (port->serial->dev->state == USB_STATE_NOTATTACHED) goto exit; - dbg("%s - port %d, %d byte(s)", __func__, port->number, count); + dev_dbg(tty->dev, "%s - %d byte(s)\n", __func__, count); - /* pass on to the driver specific version of this function */ retval = port->serial->type->write(tty, port, buf, count); - + if (retval < 0) + retval = usb_translate_errors(retval); exit: return retval; } @@ -368,30 +344,47 @@ exit: static int serial_write_room(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; - dbg("%s - port %d", __func__, port->number); - /* pass on to the driver specific version of this function */ + + dev_dbg(tty->dev, "%s\n", __func__); + return port->serial->type->write_room(tty); } static int serial_chars_in_buffer(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; - dbg("%s - port %d", __func__, port->number); + struct usb_serial *serial = port->serial; + + dev_dbg(tty->dev, "%s\n", __func__); - /* if the device was unplugged then any remaining characters - fell out of the connector ;) */ - if (port->serial->disconnected) + if (serial->disconnected) return 0; - /* pass on to the driver specific version of this function */ - return port->serial->type->chars_in_buffer(tty); + + return serial->type->chars_in_buffer(tty); +} + +static void serial_wait_until_sent(struct tty_struct *tty, int timeout) +{ + struct usb_serial_port *port = tty->driver_data; + struct usb_serial *serial = port->serial; + + dev_dbg(tty->dev, "%s\n", __func__); + + if (!port->serial->type->wait_until_sent) + return; + + mutex_lock(&serial->disc_mutex); + if (!serial->disconnected) + port->serial->type->wait_until_sent(tty, timeout); + mutex_unlock(&serial->disc_mutex); } static void serial_throttle(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; - dbg("%s - port %d", __func__, port->number); - /* pass on to the driver specific version of this function */ + dev_dbg(tty->dev, "%s\n", __func__); + if (port->serial->type->throttle) port->serial->type->throttle(tty); } @@ -399,68 +392,71 @@ static void serial_throttle(struct tty_struct *tty) static void serial_unthrottle(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; - dbg("%s - port %d", __func__, port->number); - /* pass on to the driver specific version of this function */ + dev_dbg(tty->dev, "%s\n", __func__); + if (port->serial->type->unthrottle) port->serial->type->unthrottle(tty); } -static int serial_ioctl(struct tty_struct *tty, struct file *file, +static int serial_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { struct usb_serial_port *port = tty->driver_data; - int retval = -ENODEV; - - dbg("%s - port %d, cmd 0x%.4x", __func__, port->number, cmd); + int retval = -ENOIOCTLCMD; + + dev_dbg(tty->dev, "%s - cmd 0x%04x\n", __func__, cmd); + + switch (cmd) { + case TIOCMIWAIT: + if (port->serial->type->tiocmiwait) + retval = port->serial->type->tiocmiwait(tty, arg); + break; + default: + if (port->serial->type->ioctl) + retval = port->serial->type->ioctl(tty, cmd, arg); + } - /* pass on to the driver specific version of this function - if it is available */ - if (port->serial->type->ioctl) { - retval = port->serial->type->ioctl(tty, file, cmd, arg); - } else - retval = -ENOIOCTLCMD; return retval; } static void serial_set_termios(struct tty_struct *tty, struct ktermios *old) { struct usb_serial_port *port = tty->driver_data; - dbg("%s - port %d", __func__, port->number); - /* pass on to the driver specific version of this function - if it is available */ + dev_dbg(tty->dev, "%s\n", __func__); + if (port->serial->type->set_termios) port->serial->type->set_termios(tty, port, old); else - tty_termios_copy_hw(tty->termios, old); + tty_termios_copy_hw(&tty->termios, old); } static int serial_break(struct tty_struct *tty, int break_state) { struct usb_serial_port *port = tty->driver_data; - dbg("%s - port %d", __func__, port->number); + dev_dbg(tty->dev, "%s\n", __func__); - /* pass on to the driver specific version of this function - if it is available */ if (port->serial->type->break_ctl) port->serial->type->break_ctl(tty, break_state); + return 0; } static int serial_proc_show(struct seq_file *m, void *v) { struct usb_serial *serial; + struct usb_serial_port *port; int i; char tmp[40]; - dbg("%s", __func__); seq_puts(m, "usbserinfo:1.0 driver:2.0\n"); - for (i = 0; i < SERIAL_TTY_MINORS; ++i) { - serial = usb_serial_get_by_index(i); - if (serial == NULL) + for (i = 0; i < USB_SERIAL_TTY_MINORS; ++i) { + port = usb_serial_port_get_by_minor(i); + if (port == NULL) continue; + serial = port->serial; seq_printf(m, "%d:", i); if (serial->type->driver.owner) @@ -472,7 +468,7 @@ static int serial_proc_show(struct seq_file *m, void *v) le16_to_cpu(serial->dev->descriptor.idVendor), le16_to_cpu(serial->dev->descriptor.idProduct)); seq_printf(m, " num_ports:%d", serial->num_ports); - seq_printf(m, " port:%d", i - serial->minor + 1); + seq_printf(m, " port:%d", port->port_number); usb_make_path(serial->dev, tmp, sizeof(tmp)); seq_printf(m, " path:%s", tmp); @@ -496,26 +492,26 @@ static const struct file_operations serial_proc_fops = { .release = single_release, }; -static int serial_tiocmget(struct tty_struct *tty, struct file *file) +static int serial_tiocmget(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; - dbg("%s - port %d", __func__, port->number); + dev_dbg(tty->dev, "%s\n", __func__); if (port->serial->type->tiocmget) - return port->serial->type->tiocmget(tty, file); + return port->serial->type->tiocmget(tty); return -EINVAL; } -static int serial_tiocmset(struct tty_struct *tty, struct file *file, +static int serial_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) { struct usb_serial_port *port = tty->driver_data; - dbg("%s - port %d", __func__, port->number); + dev_dbg(tty->dev, "%s\n", __func__); if (port->serial->type->tiocmset) - return port->serial->type->tiocmset(tty, file, set, clear); + return port->serial->type->tiocmset(tty, set, clear); return -EINVAL; } @@ -524,7 +520,7 @@ static int serial_get_icount(struct tty_struct *tty, { struct usb_serial_port *port = tty->driver_data; - dbg("%s - port %d", __func__, port->number); + dev_dbg(tty->dev, "%s\n", __func__); if (port->serial->type->get_icount) return port->serial->type->get_icount(tty, icount); @@ -546,68 +542,57 @@ static void usb_serial_port_work(struct work_struct *work) { struct usb_serial_port *port = container_of(work, struct usb_serial_port, work); - struct tty_struct *tty; - dbg("%s - port %d", __func__, port->number); + tty_port_tty_wakeup(&port->port); +} - tty = tty_port_tty_get(&port->port); - if (!tty) - return; +static void usb_serial_port_poison_urbs(struct usb_serial_port *port) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) + usb_poison_urb(port->read_urbs[i]); + for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) + usb_poison_urb(port->write_urbs[i]); - tty_wakeup(tty); - tty_kref_put(tty); + usb_poison_urb(port->interrupt_in_urb); + usb_poison_urb(port->interrupt_out_urb); } -static void kill_traffic(struct usb_serial_port *port) +static void usb_serial_port_unpoison_urbs(struct usb_serial_port *port) { int i; - usb_kill_urb(port->read_urb); - usb_kill_urb(port->write_urb); + for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) + usb_unpoison_urb(port->read_urbs[i]); for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) - usb_kill_urb(port->write_urbs[i]); - /* - * This is tricky. - * Some drivers submit the read_urb in the - * handler for the write_urb or vice versa - * this order determines the order in which - * usb_kill_urb() must be used to reliably - * kill the URBs. As it is unknown here, - * both orders must be used in turn. - * The call below is not redundant. - */ - usb_kill_urb(port->read_urb); - usb_kill_urb(port->interrupt_in_urb); - usb_kill_urb(port->interrupt_out_urb); + usb_unpoison_urb(port->write_urbs[i]); + + usb_unpoison_urb(port->interrupt_in_urb); + usb_unpoison_urb(port->interrupt_out_urb); } -static void port_release(struct device *dev) +static void usb_serial_port_release(struct device *dev) { struct usb_serial_port *port = to_usb_serial_port(dev); int i; - dbg ("%s - %s", __func__, dev_name(dev)); - - /* - * Stop all the traffic before cancelling the work, so that - * nobody will restart it by calling usb_serial_port_softint. - */ - kill_traffic(port); - cancel_work_sync(&port->work); + dev_dbg(dev, "%s\n", __func__); - usb_free_urb(port->read_urb); - usb_free_urb(port->write_urb); usb_free_urb(port->interrupt_in_urb); usb_free_urb(port->interrupt_out_urb); + for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) { + usb_free_urb(port->read_urbs[i]); + kfree(port->bulk_in_buffers[i]); + } for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) { usb_free_urb(port->write_urbs[i]); kfree(port->bulk_out_buffers[i]); } kfifo_free(&port->write_fifo); - kfree(port->bulk_in_buffer); - kfree(port->bulk_out_buffer); kfree(port->interrupt_in_buffer); kfree(port->interrupt_out_buffer); + tty_port_destroy(&port->port); kfree(port); } @@ -618,16 +603,14 @@ static struct usb_serial *create_serial(struct usb_device *dev, struct usb_serial *serial; serial = kzalloc(sizeof(*serial), GFP_KERNEL); - if (!serial) { - dev_err(&dev->dev, "%s - out of memory\n", __func__); + if (!serial) return NULL; - } serial->dev = usb_get_dev(dev); serial->type = driver; - serial->interface = interface; + serial->interface = usb_get_intf(interface); kref_init(&serial->kref); mutex_init(&serial->disc_mutex); - serial->minor = SERIAL_TTY_NO_MINOR; + serial->minors_reserved = 0; return serial; } @@ -655,12 +638,12 @@ static const struct usb_device_id *get_iface_id(struct usb_serial_driver *drv, id = usb_match_id(intf, drv->id_table); if (id) { - dbg("static descriptor matches"); + dev_dbg(&intf->dev, "static descriptor matches\n"); goto exit; } id = match_dynamic_id(intf, drv); if (id) - dbg("dynamic descriptor matches"); + dev_dbg(&intf->dev, "dynamic descriptor matches\n"); exit: return id; } @@ -669,12 +652,14 @@ exit: static struct usb_serial_driver *search_serial_device( struct usb_interface *iface) { - const struct usb_device_id *id; + const struct usb_device_id *id = NULL; struct usb_serial_driver *drv; + struct usb_driver *driver = to_usb_driver(iface->dev.driver); /* Check if the usb id matches a known device */ list_for_each_entry(drv, &usb_serial_driver_list, driver_list) { - id = get_iface_id(drv, iface); + if (drv->usb_driver == driver) + id = get_iface_id(drv, iface); if (id) return drv; } @@ -682,34 +667,37 @@ static struct usb_serial_driver *search_serial_device( return NULL; } -static int serial_carrier_raised(struct tty_port *port) +static int serial_port_carrier_raised(struct tty_port *port) { struct usb_serial_port *p = container_of(port, struct usb_serial_port, port); struct usb_serial_driver *drv = p->serial->type; + if (drv->carrier_raised) return drv->carrier_raised(p); /* No carrier control - don't block */ - return 1; + return 1; } -static void serial_dtr_rts(struct tty_port *port, int on) +static void serial_port_dtr_rts(struct tty_port *port, int on) { struct usb_serial_port *p = container_of(port, struct usb_serial_port, port); struct usb_serial_driver *drv = p->serial->type; + if (drv->dtr_rts) drv->dtr_rts(p, on); } static const struct tty_port_operations serial_port_ops = { - .carrier_raised = serial_carrier_raised, - .dtr_rts = serial_dtr_rts, - .activate = serial_activate, - .shutdown = serial_down, + .carrier_raised = serial_port_carrier_raised, + .dtr_rts = serial_port_dtr_rts, + .activate = serial_port_activate, + .shutdown = serial_port_shutdown, }; -int usb_serial_probe(struct usb_interface *interface, +static int usb_serial_probe(struct usb_interface *interface, const struct usb_device_id *id) { + struct device *ddev = &interface->dev; struct usb_device *dev = interface_to_usbdev(interface); struct usb_serial *serial = NULL; struct usb_serial_port *port; @@ -721,9 +709,9 @@ int usb_serial_probe(struct usb_interface *interface, struct usb_endpoint_descriptor *bulk_out_endpoint[MAX_NUM_PORTS]; struct usb_serial_driver *type = NULL; int retval; - unsigned int minor; int buffer_size; int i; + int j; int num_interrupt_in = 0; int num_interrupt_out = 0; int num_bulk_in = 0; @@ -735,13 +723,13 @@ int usb_serial_probe(struct usb_interface *interface, type = search_serial_device(interface); if (!type) { mutex_unlock(&table_lock); - dbg("none matched"); + dev_dbg(ddev, "none matched\n"); return -ENODEV; } if (!try_module_get(type->driver.owner)) { mutex_unlock(&table_lock); - dev_err(&interface->dev, "module get failed, exiting\n"); + dev_err(ddev, "module get failed, exiting\n"); return -EIO; } mutex_unlock(&table_lock); @@ -749,7 +737,6 @@ int usb_serial_probe(struct usb_interface *interface, serial = create_serial(dev, interface, type); if (!serial) { module_put(type->driver.owner); - dev_err(&interface->dev, "%s - out of memory\n", __func__); return -ENOMEM; } @@ -761,8 +748,8 @@ int usb_serial_probe(struct usb_interface *interface, retval = type->probe(serial, id); if (retval) { - dbg("sub driver rejected device"); - kfree(serial); + dev_dbg(ddev, "sub driver rejected device\n"); + usb_serial_put(serial); module_put(type->driver.owner); return retval; } @@ -776,28 +763,28 @@ int usb_serial_probe(struct usb_interface *interface, if (usb_endpoint_is_bulk_in(endpoint)) { /* we found a bulk in endpoint */ - dbg("found bulk in on endpoint %d", i); + dev_dbg(ddev, "found bulk in on endpoint %d\n", i); bulk_in_endpoint[num_bulk_in] = endpoint; ++num_bulk_in; } if (usb_endpoint_is_bulk_out(endpoint)) { /* we found a bulk out endpoint */ - dbg("found bulk out on endpoint %d", i); + dev_dbg(ddev, "found bulk out on endpoint %d\n", i); bulk_out_endpoint[num_bulk_out] = endpoint; ++num_bulk_out; } if (usb_endpoint_is_int_in(endpoint)) { /* we found a interrupt in endpoint */ - dbg("found interrupt in on endpoint %d", i); + dev_dbg(ddev, "found interrupt in on endpoint %d\n", i); interrupt_in_endpoint[num_interrupt_in] = endpoint; ++num_interrupt_in; } if (usb_endpoint_is_int_out(endpoint)) { /* we found an interrupt out endpoint */ - dbg("found interrupt out on endpoint %d", i); + dev_dbg(ddev, "found interrupt out on endpoint %d\n", i); interrupt_out_endpoint[num_interrupt_out] = endpoint; ++num_interrupt_out; } @@ -821,7 +808,7 @@ int usb_serial_probe(struct usb_interface *interface, endpoint = &iface_desc->endpoint[i].desc; if (usb_endpoint_is_int_in(endpoint)) { /* we found a interrupt in endpoint */ - dbg("found interrupt in for Prolific device on separate interface"); + dev_dbg(ddev, "found interrupt in for Prolific device on separate interface\n"); interrupt_in_endpoint[num_interrupt_in] = endpoint; ++num_interrupt_in; } @@ -833,8 +820,8 @@ int usb_serial_probe(struct usb_interface *interface, * properly during a later invocation of usb_serial_probe */ if (num_bulk_in == 0 || num_bulk_out == 0) { - dev_info(&interface->dev, "PL-2303 hack: descriptors matched but endpoints did not\n"); - kfree(serial); + dev_info(ddev, "PL-2303 hack: descriptors matched but endpoints did not\n"); + usb_serial_put(serial); module_put(type->driver.owner); return -ENODEV; } @@ -846,12 +833,13 @@ int usb_serial_probe(struct usb_interface *interface, if (type == &usb_serial_generic_device) { num_ports = num_bulk_out; if (num_ports == 0) { - dev_err(&interface->dev, - "Generic device with no bulk out, not allowed.\n"); - kfree(serial); + dev_err(ddev, "Generic device with no bulk out, not allowed.\n"); + usb_serial_put(serial); module_put(type->driver.owner); return -EIO; } + dev_info(ddev, "The \"generic\" usb-serial driver is only for testing and one-off prototypes.\n"); + dev_info(ddev, "Tell linux-usb@vger.kernel.org to add your device to a proper driver.\n"); } #endif if (!num_ports) { @@ -869,8 +857,7 @@ int usb_serial_probe(struct usb_interface *interface, serial->num_interrupt_out = num_interrupt_out; /* found all that we need */ - dev_info(&interface->dev, "%s converter detected\n", - type->description); + dev_info(ddev, "%s converter detected\n", type->description); /* create our ports, we need as many as the max endpoints */ /* we don't use num_ports here because some devices have more @@ -881,8 +868,7 @@ int usb_serial_probe(struct usb_interface *interface, max_endpoints = max(max_endpoints, (int)serial->num_ports); serial->num_port_pointers = max_endpoints; - dbg("%s - setting up %d port structures for this device", - __func__, max_endpoints); + dev_dbg(ddev, "setting up %d port structure(s)\n", max_endpoints); for (i = 0; i < max_endpoints; ++i) { port = kzalloc(sizeof(struct usb_serial_port), GFP_KERNEL); if (!port) @@ -898,7 +884,7 @@ int usb_serial_probe(struct usb_interface *interface, port->dev.parent = &interface->dev; port->dev.driver = NULL; port->dev.bus = &usb_serial_bus_type; - port->dev.release = &port_release; + port->dev.release = &usb_serial_port_release; device_initialize(&port->dev); } @@ -906,72 +892,51 @@ int usb_serial_probe(struct usb_interface *interface, for (i = 0; i < num_bulk_in; ++i) { endpoint = bulk_in_endpoint[i]; port = serial->port[i]; - port->read_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!port->read_urb) { - dev_err(&interface->dev, "No free urbs available\n"); - goto probe_error; - } - buffer_size = serial->type->bulk_in_size; - if (!buffer_size) - buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); + buffer_size = max_t(int, serial->type->bulk_in_size, + usb_endpoint_maxp(endpoint)); port->bulk_in_size = buffer_size; port->bulk_in_endpointAddress = endpoint->bEndpointAddress; - port->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL); - if (!port->bulk_in_buffer) { - dev_err(&interface->dev, - "Couldn't allocate bulk_in_buffer\n"); - goto probe_error; - } - usb_fill_bulk_urb(port->read_urb, dev, - usb_rcvbulkpipe(dev, + + for (j = 0; j < ARRAY_SIZE(port->read_urbs); ++j) { + set_bit(j, &port->read_urbs_free); + port->read_urbs[j] = usb_alloc_urb(0, GFP_KERNEL); + if (!port->read_urbs[j]) + goto probe_error; + port->bulk_in_buffers[j] = kmalloc(buffer_size, + GFP_KERNEL); + if (!port->bulk_in_buffers[j]) + goto probe_error; + usb_fill_bulk_urb(port->read_urbs[j], dev, + usb_rcvbulkpipe(dev, endpoint->bEndpointAddress), - port->bulk_in_buffer, buffer_size, - serial->type->read_bulk_callback, port); + port->bulk_in_buffers[j], buffer_size, + serial->type->read_bulk_callback, + port); + } + + port->read_urb = port->read_urbs[0]; + port->bulk_in_buffer = port->bulk_in_buffers[0]; } for (i = 0; i < num_bulk_out; ++i) { - int j; - endpoint = bulk_out_endpoint[i]; port = serial->port[i]; - port->write_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!port->write_urb) { - dev_err(&interface->dev, "No free urbs available\n"); - goto probe_error; - } if (kfifo_alloc(&port->write_fifo, PAGE_SIZE, GFP_KERNEL)) goto probe_error; - buffer_size = serial->type->bulk_out_size; - if (!buffer_size) - buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); + buffer_size = max_t(int, serial->type->bulk_out_size, + usb_endpoint_maxp(endpoint)); port->bulk_out_size = buffer_size; port->bulk_out_endpointAddress = endpoint->bEndpointAddress; - port->bulk_out_buffer = kmalloc(buffer_size, GFP_KERNEL); - if (!port->bulk_out_buffer) { - dev_err(&interface->dev, - "Couldn't allocate bulk_out_buffer\n"); - goto probe_error; - } - usb_fill_bulk_urb(port->write_urb, dev, - usb_sndbulkpipe(dev, - endpoint->bEndpointAddress), - port->bulk_out_buffer, buffer_size, - serial->type->write_bulk_callback, port); + for (j = 0; j < ARRAY_SIZE(port->write_urbs); ++j) { set_bit(j, &port->write_urbs_free); port->write_urbs[j] = usb_alloc_urb(0, GFP_KERNEL); - if (!port->write_urbs[j]) { - dev_err(&interface->dev, - "No free urbs available\n"); + if (!port->write_urbs[j]) goto probe_error; - } port->bulk_out_buffers[j] = kmalloc(buffer_size, GFP_KERNEL); - if (!port->bulk_out_buffers[j]) { - dev_err(&interface->dev, - "Couldn't allocate bulk_out_buffer\n"); + if (!port->bulk_out_buffers[j]) goto probe_error; - } usb_fill_bulk_urb(port->write_urbs[j], dev, usb_sndbulkpipe(dev, endpoint->bEndpointAddress), @@ -979,6 +944,9 @@ int usb_serial_probe(struct usb_interface *interface, serial->type->write_bulk_callback, port); } + + port->write_urb = port->write_urbs[0]; + port->bulk_out_buffer = port->bulk_out_buffers[0]; } if (serial->type->read_int_callback) { @@ -986,21 +954,15 @@ int usb_serial_probe(struct usb_interface *interface, endpoint = interrupt_in_endpoint[i]; port = serial->port[i]; port->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!port->interrupt_in_urb) { - dev_err(&interface->dev, - "No free urbs available\n"); + if (!port->interrupt_in_urb) goto probe_error; - } - buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); + buffer_size = usb_endpoint_maxp(endpoint); port->interrupt_in_endpointAddress = endpoint->bEndpointAddress; port->interrupt_in_buffer = kmalloc(buffer_size, GFP_KERNEL); - if (!port->interrupt_in_buffer) { - dev_err(&interface->dev, - "Couldn't allocate interrupt_in_buffer\n"); + if (!port->interrupt_in_buffer) goto probe_error; - } usb_fill_int_urb(port->interrupt_in_urb, dev, usb_rcvintpipe(dev, endpoint->bEndpointAddress), @@ -1009,7 +971,7 @@ int usb_serial_probe(struct usb_interface *interface, endpoint->bInterval); } } else if (num_interrupt_in) { - dbg("the device claims to support interrupt in transfers, but read_int_callback is not defined"); + dev_dbg(ddev, "The device claims to support interrupt in transfers, but read_int_callback is not defined\n"); } if (serial->type->write_int_callback) { @@ -1017,22 +979,16 @@ int usb_serial_probe(struct usb_interface *interface, endpoint = interrupt_out_endpoint[i]; port = serial->port[i]; port->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!port->interrupt_out_urb) { - dev_err(&interface->dev, - "No free urbs available\n"); + if (!port->interrupt_out_urb) goto probe_error; - } - buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); + buffer_size = usb_endpoint_maxp(endpoint); port->interrupt_out_size = buffer_size; port->interrupt_out_endpointAddress = endpoint->bEndpointAddress; port->interrupt_out_buffer = kmalloc(buffer_size, GFP_KERNEL); - if (!port->interrupt_out_buffer) { - dev_err(&interface->dev, - "Couldn't allocate interrupt_out_buffer\n"); + if (!port->interrupt_out_buffer) goto probe_error; - } usb_fill_int_urb(port->interrupt_out_urb, dev, usb_sndintpipe(dev, endpoint->bEndpointAddress), @@ -1041,9 +997,11 @@ int usb_serial_probe(struct usb_interface *interface, endpoint->bInterval); } } else if (num_interrupt_out) { - dbg("the device claims to support interrupt out transfers, but write_int_callback is not defined"); + dev_dbg(ddev, "The device claims to support interrupt out transfers, but write_int_callback is not defined\n"); } + usb_set_intfdata(interface, serial); + /* if this device type has an attach function, call it */ if (type->attach) { retval = type->attach(serial); @@ -1060,35 +1018,33 @@ int usb_serial_probe(struct usb_interface *interface, serial->attached = 1; } - if (get_free_serial(serial, num_ports, &minor) == NULL) { - dev_err(&interface->dev, "No more free serial devices\n"); + /* Avoid race with tty_open and serial_install by setting the + * disconnected flag and not clearing it until all ports have been + * registered. + */ + serial->disconnected = 1; + + if (allocate_minors(serial, num_ports)) { + dev_err(ddev, "No more free serial minor numbers\n"); goto probe_error; } - serial->minor = minor; /* register all of the individual ports with the driver core */ for (i = 0; i < num_ports; ++i) { port = serial->port[i]; - dev_set_name(&port->dev, "ttyUSB%d", port->number); - dbg ("%s - registering %s", __func__, dev_name(&port->dev)); - port->dev_state = PORT_REGISTERING; + dev_set_name(&port->dev, "ttyUSB%d", port->minor); + dev_dbg(ddev, "registering %s\n", dev_name(&port->dev)); device_enable_async_suspend(&port->dev); retval = device_add(&port->dev); - if (retval) { - dev_err(&port->dev, "Error registering port device, " - "continuing\n"); - port->dev_state = PORT_UNREGISTERED; - } else { - port->dev_state = PORT_REGISTERED; - } + if (retval) + dev_err(ddev, "Error registering port device, continuing\n"); } - usb_serial_console_init(debug, minor); + serial->disconnected = 0; + usb_serial_console_init(serial->port[0]->minor); exit: - /* success */ - usb_set_intfdata(interface, serial); module_put(type->driver.owner); return 0; @@ -1097,68 +1053,55 @@ probe_error: module_put(type->driver.owner); return -EIO; } -EXPORT_SYMBOL_GPL(usb_serial_probe); -void usb_serial_disconnect(struct usb_interface *interface) +static void usb_serial_disconnect(struct usb_interface *interface) { int i; struct usb_serial *serial = usb_get_intfdata(interface); struct device *dev = &interface->dev; struct usb_serial_port *port; + struct tty_struct *tty; usb_serial_console_disconnect(serial); - dbg("%s", __func__); mutex_lock(&serial->disc_mutex); - usb_set_intfdata(interface, NULL); /* must set a flag, to signal subdrivers */ serial->disconnected = 1; mutex_unlock(&serial->disc_mutex); for (i = 0; i < serial->num_ports; ++i) { port = serial->port[i]; - if (port) { - struct tty_struct *tty = tty_port_tty_get(&port->port); - if (tty) { - tty_vhangup(tty); - tty_kref_put(tty); - } - kill_traffic(port); - cancel_work_sync(&port->work); - if (port->dev_state == PORT_REGISTERED) { - - /* Make sure the port is bound so that the - * driver's port_remove method is called. - */ - if (!port->dev.driver) { - int rc; - - port->dev.driver = - &serial->type->driver; - rc = device_bind_driver(&port->dev); - } - port->dev_state = PORT_UNREGISTERING; - device_del(&port->dev); - port->dev_state = PORT_UNREGISTERED; - } + tty = tty_port_tty_get(&port->port); + if (tty) { + tty_vhangup(tty); + tty_kref_put(tty); } + usb_serial_port_poison_urbs(port); + wake_up_interruptible(&port->port.delta_msr_wait); + cancel_work_sync(&port->work); + if (device_is_registered(&port->dev)) + device_del(&port->dev); } - serial->type->disconnect(serial); + if (serial->type->disconnect) + serial->type->disconnect(serial); /* let the last holder of this object cause it to be cleaned up */ usb_serial_put(serial); dev_info(dev, "device disconnected\n"); } -EXPORT_SYMBOL_GPL(usb_serial_disconnect); int usb_serial_suspend(struct usb_interface *intf, pm_message_t message) { struct usb_serial *serial = usb_get_intfdata(intf); - struct usb_serial_port *port; int i, r = 0; serial->suspending = 1; + /* + * serial->type->suspend() MUST return 0 in system sleep context, + * otherwise, the resume callback has to recover device from + * previous suspend failure. + */ if (serial->type->suspend) { r = serial->type->suspend(serial, message); if (r < 0) { @@ -1167,22 +1110,28 @@ int usb_serial_suspend(struct usb_interface *intf, pm_message_t message) } } - for (i = 0; i < serial->num_ports; ++i) { - port = serial->port[i]; - if (port) - kill_traffic(port); - } - + for (i = 0; i < serial->num_ports; ++i) + usb_serial_port_poison_urbs(serial->port[i]); err_out: return r; } EXPORT_SYMBOL(usb_serial_suspend); +static void usb_serial_unpoison_port_urbs(struct usb_serial *serial) +{ + int i; + + for (i = 0; i < serial->num_ports; ++i) + usb_serial_port_unpoison_urbs(serial->port[i]); +} + int usb_serial_resume(struct usb_interface *intf) { struct usb_serial *serial = usb_get_intfdata(intf); int rv; + usb_serial_unpoison_port_urbs(serial); + serial->suspending = 0; if (serial->type->resume) rv = serial->type->resume(serial); @@ -1193,11 +1142,29 @@ int usb_serial_resume(struct usb_interface *intf) } EXPORT_SYMBOL(usb_serial_resume); +static int usb_serial_reset_resume(struct usb_interface *intf) +{ + struct usb_serial *serial = usb_get_intfdata(intf); + int rv; + + usb_serial_unpoison_port_urbs(serial); + + serial->suspending = 0; + if (serial->type->reset_resume) { + rv = serial->type->reset_resume(serial); + } else { + rv = -EOPNOTSUPP; + intf->needs_binding = 1; + } + + return rv; +} + static const struct tty_operations serial_ops = { .open = serial_open, .close = serial_close, .write = serial_write, - .hangup = serial_hangup, + .hangup = serial_hangup, .write_room = serial_write_room, .ioctl = serial_ioctl, .set_termios = serial_set_termios, @@ -1205,41 +1172,47 @@ static const struct tty_operations serial_ops = { .unthrottle = serial_unthrottle, .break_ctl = serial_break, .chars_in_buffer = serial_chars_in_buffer, + .wait_until_sent = serial_wait_until_sent, .tiocmget = serial_tiocmget, .tiocmset = serial_tiocmset, - .get_icount = serial_get_icount, - .cleanup = serial_cleanup, - .install = serial_install, + .get_icount = serial_get_icount, + .cleanup = serial_cleanup, + .install = serial_install, .proc_fops = &serial_proc_fops, }; struct tty_driver *usb_serial_tty_driver; +/* Driver structure we register with the USB core */ +static struct usb_driver usb_serial_driver = { + .name = "usbserial", + .probe = usb_serial_probe, + .disconnect = usb_serial_disconnect, + .suspend = usb_serial_suspend, + .resume = usb_serial_resume, + .no_dynamic_id = 1, + .supports_autosuspend = 1, +}; + static int __init usb_serial_init(void) { - int i; int result; - usb_serial_tty_driver = alloc_tty_driver(SERIAL_TTY_MINORS); + usb_serial_tty_driver = alloc_tty_driver(USB_SERIAL_TTY_MINORS); if (!usb_serial_tty_driver) return -ENOMEM; /* Initialize our global data */ - for (i = 0; i < SERIAL_TTY_MINORS; ++i) - serial_table[i] = NULL; - result = bus_register(&usb_serial_bus_type); if (result) { - printk(KERN_ERR "usb-serial: %s - registering bus driver " - "failed\n", __func__); + pr_err("%s - registering bus driver failed\n", __func__); goto exit_bus; } - usb_serial_tty_driver->owner = THIS_MODULE; usb_serial_tty_driver->driver_name = "usbserial"; - usb_serial_tty_driver->name = "ttyUSB"; - usb_serial_tty_driver->major = SERIAL_TTY_MAJOR; + usb_serial_tty_driver->name = "ttyUSB"; + usb_serial_tty_driver->major = USB_SERIAL_TTY_MAJOR; usb_serial_tty_driver->minor_start = 0; usb_serial_tty_driver->type = TTY_DRIVER_TYPE_SERIAL; usb_serial_tty_driver->subtype = SERIAL_TYPE_NORMAL; @@ -1253,29 +1226,24 @@ static int __init usb_serial_init(void) tty_set_operations(usb_serial_tty_driver, &serial_ops); result = tty_register_driver(usb_serial_tty_driver); if (result) { - printk(KERN_ERR "usb-serial: %s - tty_register_driver failed\n", - __func__); + pr_err("%s - tty_register_driver failed\n", __func__); goto exit_reg_driver; } /* register the USB driver */ result = usb_register(&usb_serial_driver); if (result < 0) { - printk(KERN_ERR "usb-serial: %s - usb_register failed\n", - __func__); + pr_err("%s - usb_register failed\n", __func__); goto exit_tty; } /* register the generic driver, if we should */ - result = usb_serial_generic_register(debug); + result = usb_serial_generic_register(); if (result < 0) { - printk(KERN_ERR "usb-serial: %s - registering generic " - "driver failed\n", __func__); + pr_err("%s - registering generic driver failed\n", __func__); goto exit_generic; } - printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n"); - return result; exit_generic: @@ -1288,8 +1256,7 @@ exit_reg_driver: bus_unregister(&usb_serial_bus_type); exit_bus: - printk(KERN_ERR "usb-serial: %s - returning with error %d\n", - __func__, result); + pr_err("%s - returning with error %d\n", __func__, result); put_tty_driver(usb_serial_tty_driver); return result; } @@ -1315,38 +1282,42 @@ module_exit(usb_serial_exit); do { \ if (!type->function) { \ type->function = usb_serial_generic_##function; \ - dbg("Had to override the " #function \ - " usb serial operation with the generic one.");\ - } \ + pr_debug("%s: using generic " #function "\n", \ + type->driver.name); \ + } \ } while (0) -static void fixup_generic(struct usb_serial_driver *device) +static void usb_serial_operations_init(struct usb_serial_driver *device) { set_to_generic_if_null(device, open); set_to_generic_if_null(device, write); set_to_generic_if_null(device, close); set_to_generic_if_null(device, write_room); set_to_generic_if_null(device, chars_in_buffer); + if (device->tx_empty) + set_to_generic_if_null(device, wait_until_sent); set_to_generic_if_null(device, read_bulk_callback); set_to_generic_if_null(device, write_bulk_callback); - set_to_generic_if_null(device, disconnect); - set_to_generic_if_null(device, release); set_to_generic_if_null(device, process_read_urb); set_to_generic_if_null(device, prepare_write_buffer); } -int usb_serial_register(struct usb_serial_driver *driver) +static int usb_serial_register(struct usb_serial_driver *driver) { - /* must be called with BKL held */ int retval; if (usb_disabled()) return -ENODEV; - fixup_generic(driver); - if (!driver->description) driver->description = driver->driver.name; + if (!driver->usb_driver) { + WARN(1, "Serial driver %s has no usb_driver\n", + driver->description); + return -EINVAL; + } + + usb_serial_operations_init(driver); /* Add this device to our list of devices */ mutex_lock(&table_lock); @@ -1354,35 +1325,119 @@ int usb_serial_register(struct usb_serial_driver *driver) retval = usb_serial_bus_register(driver); if (retval) { - printk(KERN_ERR "usb-serial: problem %d when registering " - "driver %s\n", retval, driver->description); + pr_err("problem %d when registering driver %s\n", retval, driver->description); list_del(&driver->driver_list); - } else - printk(KERN_INFO "USB Serial support registered for %s\n", - driver->description); - + } else { + pr_info("USB Serial support registered for %s\n", driver->description); + } mutex_unlock(&table_lock); return retval; } -EXPORT_SYMBOL_GPL(usb_serial_register); - -void usb_serial_deregister(struct usb_serial_driver *device) +static void usb_serial_deregister(struct usb_serial_driver *device) { - /* must be called with BKL held */ - printk(KERN_INFO "USB Serial deregistering driver %s\n", - device->description); + pr_info("USB Serial deregistering driver %s\n", device->description); + mutex_lock(&table_lock); list_del(&device->driver_list); - usb_serial_bus_deregister(device); mutex_unlock(&table_lock); + + usb_serial_bus_deregister(device); +} + +/** + * usb_serial_register_drivers - register drivers for a usb-serial module + * @serial_drivers: NULL-terminated array of pointers to drivers to be registered + * @name: name of the usb_driver for this set of @serial_drivers + * @id_table: list of all devices this @serial_drivers set binds to + * + * Registers all the drivers in the @serial_drivers array, and dynamically + * creates a struct usb_driver with the name @name and id_table of @id_table. + */ +int usb_serial_register_drivers(struct usb_serial_driver *const serial_drivers[], + const char *name, + const struct usb_device_id *id_table) +{ + int rc; + struct usb_driver *udriver; + struct usb_serial_driver * const *sd; + + /* + * udriver must be registered before any of the serial drivers, + * because the store_new_id() routine for the serial drivers (in + * bus.c) probes udriver. + * + * Performance hack: We don't want udriver to be probed until + * the serial drivers are registered, because the probe would + * simply fail for lack of a matching serial driver. + * So we leave udriver's id_table set to NULL until we are all set. + * + * Suspend/resume support is implemented in the usb-serial core, + * so fill in the PM-related fields in udriver. + */ + udriver = kzalloc(sizeof(*udriver), GFP_KERNEL); + if (!udriver) + return -ENOMEM; + + udriver->name = name; + udriver->no_dynamic_id = 1; + udriver->supports_autosuspend = 1; + udriver->suspend = usb_serial_suspend; + udriver->resume = usb_serial_resume; + udriver->probe = usb_serial_probe; + udriver->disconnect = usb_serial_disconnect; + + /* we only set the reset_resume field if the serial_driver has one */ + for (sd = serial_drivers; *sd; ++sd) { + if ((*sd)->reset_resume) { + udriver->reset_resume = usb_serial_reset_resume; + break; + } + } + + rc = usb_register(udriver); + if (rc) + return rc; + + for (sd = serial_drivers; *sd; ++sd) { + (*sd)->usb_driver = udriver; + rc = usb_serial_register(*sd); + if (rc) + goto failed; + } + + /* Now set udriver's id_table and look for matches */ + udriver->id_table = id_table; + rc = driver_attach(&udriver->drvwrap.driver); + return 0; + + failed: + while (sd-- > serial_drivers) + usb_serial_deregister(*sd); + usb_deregister(udriver); + return rc; +} +EXPORT_SYMBOL_GPL(usb_serial_register_drivers); + +/** + * usb_serial_deregister_drivers - deregister drivers for a usb-serial module + * @serial_drivers: NULL-terminated array of pointers to drivers to be deregistered + * + * Deregisters all the drivers in the @serial_drivers array and deregisters and + * frees the struct usb_driver that was created by the call to + * usb_serial_register_drivers(). + */ +void usb_serial_deregister_drivers(struct usb_serial_driver *const serial_drivers[]) +{ + struct usb_driver *udriver = (*serial_drivers)->usb_driver; + + for (; *serial_drivers; ++serial_drivers) + usb_serial_deregister(*serial_drivers); + usb_deregister(udriver); + kfree(udriver); } -EXPORT_SYMBOL_GPL(usb_serial_deregister); +EXPORT_SYMBOL_GPL(usb_serial_deregister_drivers); -/* Module information */ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/drivers/usb/serial/usb-wwan.h b/drivers/usb/serial/usb-wwan.h index 2be298a1305..f22dff58b58 100644 --- a/drivers/usb/serial/usb-wwan.h +++ b/drivers/usb/serial/usb-wwan.h @@ -8,17 +8,14 @@ extern void usb_wwan_dtr_rts(struct usb_serial_port *port, int on); extern int usb_wwan_open(struct tty_struct *tty, struct usb_serial_port *port); extern void usb_wwan_close(struct usb_serial_port *port); -extern int usb_wwan_startup(struct usb_serial *serial); -extern void usb_wwan_disconnect(struct usb_serial *serial); -extern void usb_wwan_release(struct usb_serial *serial); +extern int usb_wwan_port_probe(struct usb_serial_port *port); +extern int usb_wwan_port_remove(struct usb_serial_port *port); extern int usb_wwan_write_room(struct tty_struct *tty); -extern void usb_wwan_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, - struct ktermios *old); -extern int usb_wwan_tiocmget(struct tty_struct *tty, struct file *file); -extern int usb_wwan_tiocmset(struct tty_struct *tty, struct file *file, +extern int usb_wwan_tiocmget(struct tty_struct *tty); +extern int usb_wwan_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear); -extern int usb_wwan_send_setup(struct usb_serial_port *port); +extern int usb_wwan_ioctl(struct tty_struct *tty, + unsigned int cmd, unsigned long arg); extern int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count); extern int usb_wwan_chars_in_buffer(struct tty_struct *tty); @@ -38,6 +35,7 @@ struct usb_wwan_intf_private { spinlock_t susp_lock; unsigned int suspended:1; int in_flight; + unsigned int open_ports; int (*send_setup) (struct usb_serial_port *port); void *private; }; @@ -50,7 +48,6 @@ struct usb_wwan_port_private { struct urb *out_urbs[N_OUT_URB]; u8 *out_buffer[N_OUT_URB]; unsigned long out_busy; /* Bit vector of URBs in use */ - int opened; struct usb_anchor delayed; /* Settings for the port */ diff --git a/drivers/usb/serial/usb_debug.c b/drivers/usb/serial/usb_debug.c index f2ed6a31be7..ca2fa5bbe17 100644 --- a/drivers/usb/serial/usb_debug.c +++ b/drivers/usb/serial/usb_debug.c @@ -10,7 +10,6 @@ #include <linux/gfp.h> #include <linux/kernel.h> -#include <linux/init.h> #include <linux/tty.h> #include <linux/module.h> #include <linux/usb.h> @@ -35,14 +34,6 @@ static const struct usb_device_id id_table[] = { }; MODULE_DEVICE_TABLE(usb, id_table); -static struct usb_driver debug_driver = { - .name = "debug", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, - .no_dynamic_id = 1, -}; - /* This HW really does not support a serial break, so one will be * emulated when ever the break state is set to true. */ @@ -54,19 +45,18 @@ static void usb_debug_break_ctl(struct tty_struct *tty, int break_state) usb_serial_generic_write(tty, port, USB_DEBUG_BRK, USB_DEBUG_BRK_SIZE); } -static void usb_debug_read_bulk_callback(struct urb *urb) +static void usb_debug_process_read_urb(struct urb *urb) { struct usb_serial_port *port = urb->context; if (urb->actual_length == USB_DEBUG_BRK_SIZE && - memcmp(urb->transfer_buffer, USB_DEBUG_BRK, - USB_DEBUG_BRK_SIZE) == 0) { + memcmp(urb->transfer_buffer, USB_DEBUG_BRK, + USB_DEBUG_BRK_SIZE) == 0) { usb_serial_handle_break(port); - usb_serial_generic_submit_read_urb(port, GFP_ATOMIC); return; } - usb_serial_generic_read_bulk_callback(urb); + usb_serial_generic_process_read_urb(urb); } static struct usb_serial_driver debug_device = { @@ -78,28 +68,12 @@ static struct usb_serial_driver debug_device = { .num_ports = 1, .bulk_out_size = USB_DEBUG_MAX_PACKET_SIZE, .break_ctl = usb_debug_break_ctl, - .read_bulk_callback = usb_debug_read_bulk_callback, + .process_read_urb = usb_debug_process_read_urb, }; -static int __init debug_init(void) -{ - int retval; - - retval = usb_serial_register(&debug_device); - if (retval) - return retval; - retval = usb_register(&debug_driver); - if (retval) - usb_serial_deregister(&debug_device); - return retval; -} - -static void __exit debug_exit(void) -{ - usb_deregister(&debug_driver); - usb_serial_deregister(&debug_device); -} +static struct usb_serial_driver * const serial_drivers[] = { + &debug_device, NULL +}; -module_init(debug_init); -module_exit(debug_exit); +module_usb_serial_driver(serial_drivers, id_table); MODULE_LICENSE("GPL"); diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c index fbc94679780..2f805cb386a 100644 --- a/drivers/usb/serial/usb_wwan.c +++ b/drivers/usb/serial/usb_wwan.c @@ -19,7 +19,6 @@ - controlling the baud rate doesn't make sense */ -#define DRIVER_VERSION "v0.7.2" #define DRIVER_AUTHOR "Matthias Urlichs <smurf@smurf.noris.de>" #define DRIVER_DESC "USB Driver for GSM modems" @@ -31,53 +30,32 @@ #include <linux/tty_flip.h> #include <linux/module.h> #include <linux/bitops.h> +#include <linux/uaccess.h> #include <linux/usb.h> #include <linux/usb/serial.h> +#include <linux/serial.h> #include "usb-wwan.h" -static int debug; - void usb_wwan_dtr_rts(struct usb_serial_port *port, int on) { - struct usb_serial *serial = port->serial; struct usb_wwan_port_private *portdata; - struct usb_wwan_intf_private *intfdata; - dbg("%s", __func__); - - intfdata = port->serial->private; + intfdata = usb_get_serial_data(port->serial); if (!intfdata->send_setup) return; portdata = usb_get_serial_port_data(port); - mutex_lock(&serial->disc_mutex); + /* FIXME: locking */ portdata->rts_state = on; portdata->dtr_state = on; - if (serial->dev) - intfdata->send_setup(port); - mutex_unlock(&serial->disc_mutex); -} -EXPORT_SYMBOL(usb_wwan_dtr_rts); -void usb_wwan_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, - struct ktermios *old_termios) -{ - struct usb_wwan_intf_private *intfdata = port->serial->private; - - dbg("%s", __func__); - - /* Doesn't support option setting */ - tty_termios_copy_hw(tty->termios, old_termios); - - if (intfdata->send_setup) - intfdata->send_setup(port); + intfdata->send_setup(port); } -EXPORT_SYMBOL(usb_wwan_set_termios); +EXPORT_SYMBOL(usb_wwan_dtr_rts); -int usb_wwan_tiocmget(struct tty_struct *tty, struct file *file) +int usb_wwan_tiocmget(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; unsigned int value; @@ -96,7 +74,7 @@ int usb_wwan_tiocmget(struct tty_struct *tty, struct file *file) } EXPORT_SYMBOL(usb_wwan_tiocmget); -int usb_wwan_tiocmset(struct tty_struct *tty, struct file *file, +int usb_wwan_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) { struct usb_serial_port *port = tty->driver_data; @@ -104,7 +82,7 @@ int usb_wwan_tiocmset(struct tty_struct *tty, struct file *file, struct usb_wwan_intf_private *intfdata; portdata = usb_get_serial_port_data(port); - intfdata = port->serial->private; + intfdata = usb_get_serial_data(port->serial); if (!intfdata->send_setup) return -EINVAL; @@ -123,7 +101,83 @@ int usb_wwan_tiocmset(struct tty_struct *tty, struct file *file, } EXPORT_SYMBOL(usb_wwan_tiocmset); -/* Write */ +static int get_serial_info(struct usb_serial_port *port, + struct serial_struct __user *retinfo) +{ + struct serial_struct tmp; + + if (!retinfo) + return -EFAULT; + + memset(&tmp, 0, sizeof(tmp)); + tmp.line = port->minor; + tmp.port = port->port_number; + tmp.baud_base = tty_get_baud_rate(port->port.tty); + tmp.close_delay = port->port.close_delay / 10; + tmp.closing_wait = port->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ? + ASYNC_CLOSING_WAIT_NONE : + port->port.closing_wait / 10; + + if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) + return -EFAULT; + return 0; +} + +static int set_serial_info(struct usb_serial_port *port, + struct serial_struct __user *newinfo) +{ + struct serial_struct new_serial; + unsigned int closing_wait, close_delay; + int retval = 0; + + if (copy_from_user(&new_serial, newinfo, sizeof(new_serial))) + return -EFAULT; + + close_delay = new_serial.close_delay * 10; + closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ? + ASYNC_CLOSING_WAIT_NONE : new_serial.closing_wait * 10; + + mutex_lock(&port->port.mutex); + + if (!capable(CAP_SYS_ADMIN)) { + if ((close_delay != port->port.close_delay) || + (closing_wait != port->port.closing_wait)) + retval = -EPERM; + else + retval = -EOPNOTSUPP; + } else { + port->port.close_delay = close_delay; + port->port.closing_wait = closing_wait; + } + + mutex_unlock(&port->port.mutex); + return retval; +} + +int usb_wwan_ioctl(struct tty_struct *tty, + unsigned int cmd, unsigned long arg) +{ + struct usb_serial_port *port = tty->driver_data; + + dev_dbg(&port->dev, "%s cmd 0x%04x\n", __func__, cmd); + + switch (cmd) { + case TIOCGSERIAL: + return get_serial_info(port, + (struct serial_struct __user *) arg); + case TIOCSSERIAL: + return set_serial_info(port, + (struct serial_struct __user *) arg); + default: + break; + } + + dev_dbg(&port->dev, "%s arg not supported\n", __func__); + + return -ENOIOCTLCMD; +} +EXPORT_SYMBOL(usb_wwan_ioctl); + int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count) { @@ -136,9 +190,9 @@ int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port, unsigned long flags; portdata = usb_get_serial_port_data(port); - intfdata = port->serial->private; + intfdata = usb_get_serial_data(port->serial); - dbg("%s: write (%d chars)", __func__, count); + dev_dbg(&port->dev, "%s: write (%d chars)\n", __func__, count); i = 0; left = count; @@ -155,12 +209,14 @@ int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port, usb_unlink_urb(this_urb); continue; } - dbg("%s: endpoint %d buf %d", __func__, - usb_pipeendpoint(this_urb->pipe), i); + dev_dbg(&port->dev, "%s: endpoint %d buf %d\n", __func__, + usb_pipeendpoint(this_urb->pipe), i); err = usb_autopm_get_interface_async(port->serial->interface); - if (err < 0) + if (err < 0) { + clear_bit(i, &portdata->out_busy); break; + } /* send the data */ memcpy(this_urb->transfer_buffer, buf, todo); @@ -175,14 +231,16 @@ int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port, spin_unlock_irqrestore(&intfdata->susp_lock, flags); err = usb_submit_urb(this_urb, GFP_ATOMIC); if (err) { - dbg("usb_submit_urb %p (write bulk) failed " - "(%d)", this_urb, err); + dev_err(&port->dev, + "%s: submit urb %d failed: %d\n", + __func__, i, err); clear_bit(i, &portdata->out_busy); spin_lock_irqsave(&intfdata->susp_lock, flags); intfdata->in_flight--; spin_unlock_irqrestore(&intfdata->susp_lock, flags); - continue; + usb_autopm_put_interface_async(port->serial->interface); + break; } } @@ -192,7 +250,7 @@ int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port, } count -= left; - dbg("%s: wrote (did %d)", __func__, count); + dev_dbg(&port->dev, "%s: wrote (did %d)\n", __func__, count); return count; } EXPORT_SYMBOL(usb_wwan_write); @@ -202,37 +260,36 @@ static void usb_wwan_indat_callback(struct urb *urb) int err; int endpoint; struct usb_serial_port *port; - struct tty_struct *tty; + struct device *dev; unsigned char *data = urb->transfer_buffer; int status = urb->status; - dbg("%s: %p", __func__, urb); - endpoint = usb_pipeendpoint(urb->pipe); port = urb->context; + dev = &port->dev; if (status) { - dbg("%s: nonzero status: %d on endpoint %02x.", - __func__, status, endpoint); + dev_dbg(dev, "%s: nonzero status: %d on endpoint %02x.\n", + __func__, status, endpoint); } else { - tty = tty_port_tty_get(&port->port); if (urb->actual_length) { - tty_insert_flip_string(tty, data, urb->actual_length); - tty_flip_buffer_push(tty); + tty_insert_flip_string(&port->port, data, + urb->actual_length); + tty_flip_buffer_push(&port->port); } else - dbg("%s: empty read urb received", __func__); - tty_kref_put(tty); - - /* Resubmit urb so we continue receiving */ - if (status != -ESHUTDOWN) { - err = usb_submit_urb(urb, GFP_ATOMIC); - if (err && err != -EPERM) - printk(KERN_ERR "%s: resubmit read urb failed. " - "(%d)", __func__, err); - else - usb_mark_last_busy(port->serial->dev); + dev_dbg(dev, "%s: empty read urb received\n", __func__); + } + /* Resubmit urb so we continue receiving */ + err = usb_submit_urb(urb, GFP_ATOMIC); + if (err) { + if (err != -EPERM) { + dev_err(dev, "%s: resubmit read urb failed. (%d)\n", + __func__, err); + /* busy also in error unless we are killed */ + usb_mark_last_busy(port->serial->dev); } - + } else { + usb_mark_last_busy(port->serial->dev); } } @@ -243,10 +300,8 @@ static void usb_wwan_outdat_callback(struct urb *urb) struct usb_wwan_intf_private *intfdata; int i; - dbg("%s", __func__); - port = urb->context; - intfdata = port->serial->private; + intfdata = usb_get_serial_data(port->serial); usb_serial_port_softint(port); usb_autopm_put_interface_async(port->serial->interface); @@ -257,7 +312,7 @@ static void usb_wwan_outdat_callback(struct urb *urb) for (i = 0; i < N_OUT_URB; ++i) { if (portdata->out_urbs[i] == urb) { - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); clear_bit(i, &portdata->out_busy); break; } @@ -280,7 +335,7 @@ int usb_wwan_write_room(struct tty_struct *tty) data_len += OUT_BUFLEN; } - dbg("%s: %d", __func__, data_len); + dev_dbg(&port->dev, "%s: %d\n", __func__, data_len); return data_len; } EXPORT_SYMBOL(usb_wwan_write_room); @@ -302,7 +357,7 @@ int usb_wwan_chars_in_buffer(struct tty_struct *tty) if (this_urb && test_bit(i, &portdata->out_busy)) data_len += this_urb->transfer_buffer_length; } - dbg("%s: %d", __func__, data_len); + dev_dbg(&port->dev, "%s: %d\n", __func__, data_len); return data_len; } EXPORT_SYMBOL(usb_wwan_chars_in_buffer); @@ -316,9 +371,15 @@ int usb_wwan_open(struct tty_struct *tty, struct usb_serial_port *port) struct urb *urb; portdata = usb_get_serial_port_data(port); - intfdata = serial->private; + intfdata = usb_get_serial_data(serial); - dbg("%s", __func__); + if (port->interrupt_in_urb) { + err = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); + if (err) { + dev_err(&port->dev, "%s: submit int urb failed: %d\n", + __func__, err); + } + } /* Start reading from the IN endpoint */ for (i = 0; i < N_IN_URB; i++) { @@ -327,67 +388,85 @@ int usb_wwan_open(struct tty_struct *tty, struct usb_serial_port *port) continue; err = usb_submit_urb(urb, GFP_KERNEL); if (err) { - dbg("%s: submit urb %d failed (%d) %d", - __func__, i, err, urb->transfer_buffer_length); + dev_err(&port->dev, + "%s: submit read urb %d failed: %d\n", + __func__, i, err); } } - if (intfdata->send_setup) - intfdata->send_setup(port); - - serial->interface->needs_remote_wakeup = 1; spin_lock_irq(&intfdata->susp_lock); - portdata->opened = 1; + if (++intfdata->open_ports == 1) + serial->interface->needs_remote_wakeup = 1; spin_unlock_irq(&intfdata->susp_lock); + /* this balances a get in the generic USB serial code */ usb_autopm_put_interface(serial->interface); return 0; } EXPORT_SYMBOL(usb_wwan_open); +static void unbusy_queued_urb(struct urb *urb, + struct usb_wwan_port_private *portdata) +{ + int i; + + for (i = 0; i < N_OUT_URB; i++) { + if (urb == portdata->out_urbs[i]) { + clear_bit(i, &portdata->out_busy); + break; + } + } +} + void usb_wwan_close(struct usb_serial_port *port) { int i; struct usb_serial *serial = port->serial; struct usb_wwan_port_private *portdata; - struct usb_wwan_intf_private *intfdata = port->serial->private; + struct usb_wwan_intf_private *intfdata = usb_get_serial_data(serial); + struct urb *urb; - dbg("%s", __func__); portdata = usb_get_serial_port_data(port); - if (serial->dev) { - /* Stop reading/writing urbs */ - spin_lock_irq(&intfdata->susp_lock); - portdata->opened = 0; - spin_unlock_irq(&intfdata->susp_lock); - - for (i = 0; i < N_IN_URB; i++) - usb_kill_urb(portdata->in_urbs[i]); - for (i = 0; i < N_OUT_URB; i++) - usb_kill_urb(portdata->out_urbs[i]); - usb_autopm_get_interface(serial->interface); + /* + * Need to take susp_lock to make sure port is not already being + * resumed, but no need to hold it due to ASYNC_INITIALIZED. + */ + spin_lock_irq(&intfdata->susp_lock); + if (--intfdata->open_ports == 0) serial->interface->needs_remote_wakeup = 0; + spin_unlock_irq(&intfdata->susp_lock); + + for (;;) { + urb = usb_get_from_anchor(&portdata->delayed); + if (!urb) + break; + unbusy_queued_urb(urb, portdata); + usb_autopm_put_interface_async(serial->interface); } + + for (i = 0; i < N_IN_URB; i++) + usb_kill_urb(portdata->in_urbs[i]); + for (i = 0; i < N_OUT_URB; i++) + usb_kill_urb(portdata->out_urbs[i]); + usb_kill_urb(port->interrupt_in_urb); + + usb_autopm_get_interface_no_resume(serial->interface); } EXPORT_SYMBOL(usb_wwan_close); -/* Helper functions used by usb_wwan_setup_urbs */ -static struct urb *usb_wwan_setup_urb(struct usb_serial *serial, int endpoint, +static struct urb *usb_wwan_setup_urb(struct usb_serial_port *port, + int endpoint, int dir, void *ctx, char *buf, int len, void (*callback) (struct urb *)) { + struct usb_serial *serial = port->serial; struct urb *urb; - if (endpoint == -1) - return NULL; /* endpoint not needed */ - urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */ - if (urb == NULL) { - dbg("%s: alloc for endpoint %d failed.", __func__, endpoint); + if (!urb) return NULL; - } - /* Fill URB using supplied data. */ usb_fill_bulk_urb(urb, serial->dev, usb_sndbulkpipe(serial->dev, endpoint) | dir, buf, len, callback, ctx); @@ -395,270 +474,222 @@ static struct urb *usb_wwan_setup_urb(struct usb_serial *serial, int endpoint, return urb; } -/* Setup urbs */ -static void usb_wwan_setup_urbs(struct usb_serial *serial) +int usb_wwan_port_probe(struct usb_serial_port *port) { - int i, j; - struct usb_serial_port *port; struct usb_wwan_port_private *portdata; + struct urb *urb; + u8 *buffer; + int i; - dbg("%s", __func__); + if (!port->bulk_in_size || !port->bulk_out_size) + return -ENODEV; - for (i = 0; i < serial->num_ports; i++) { - port = serial->port[i]; - portdata = usb_get_serial_port_data(port); + portdata = kzalloc(sizeof(*portdata), GFP_KERNEL); + if (!portdata) + return -ENOMEM; - /* Do indat endpoints first */ - for (j = 0; j < N_IN_URB; ++j) { - portdata->in_urbs[j] = usb_wwan_setup_urb(serial, - port-> - bulk_in_endpointAddress, - USB_DIR_IN, - port, - portdata-> - in_buffer[j], - IN_BUFLEN, - usb_wwan_indat_callback); - } + init_usb_anchor(&portdata->delayed); - /* outdat endpoints */ - for (j = 0; j < N_OUT_URB; ++j) { - portdata->out_urbs[j] = usb_wwan_setup_urb(serial, - port-> - bulk_out_endpointAddress, - USB_DIR_OUT, - port, - portdata-> - out_buffer - [j], - OUT_BUFLEN, - usb_wwan_outdat_callback); - } + for (i = 0; i < N_IN_URB; i++) { + buffer = (u8 *)__get_free_page(GFP_KERNEL); + if (!buffer) + goto bail_out_error; + portdata->in_buffer[i] = buffer; + + urb = usb_wwan_setup_urb(port, port->bulk_in_endpointAddress, + USB_DIR_IN, port, + buffer, IN_BUFLEN, + usb_wwan_indat_callback); + portdata->in_urbs[i] = urb; } -} -int usb_wwan_startup(struct usb_serial *serial) -{ - int i, j, err; - struct usb_serial_port *port; - struct usb_wwan_port_private *portdata; - u8 *buffer; - - dbg("%s", __func__); - - /* Now setup per port private data */ - for (i = 0; i < serial->num_ports; i++) { - port = serial->port[i]; - portdata = kzalloc(sizeof(*portdata), GFP_KERNEL); - if (!portdata) { - dbg("%s: kmalloc for usb_wwan_port_private (%d) failed!.", - __func__, i); - return 1; - } - init_usb_anchor(&portdata->delayed); - - for (j = 0; j < N_IN_URB; j++) { - buffer = (u8 *) __get_free_page(GFP_KERNEL); - if (!buffer) - goto bail_out_error; - portdata->in_buffer[j] = buffer; - } - - for (j = 0; j < N_OUT_URB; j++) { - buffer = kmalloc(OUT_BUFLEN, GFP_KERNEL); - if (!buffer) - goto bail_out_error2; - portdata->out_buffer[j] = buffer; - } + for (i = 0; i < N_OUT_URB; i++) { + buffer = kmalloc(OUT_BUFLEN, GFP_KERNEL); + if (!buffer) + goto bail_out_error2; + portdata->out_buffer[i] = buffer; + + urb = usb_wwan_setup_urb(port, port->bulk_out_endpointAddress, + USB_DIR_OUT, port, + buffer, OUT_BUFLEN, + usb_wwan_outdat_callback); + portdata->out_urbs[i] = urb; + } - usb_set_serial_port_data(port, portdata); + usb_set_serial_port_data(port, portdata); - if (!port->interrupt_in_urb) - continue; - err = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); - if (err) - dbg("%s: submit irq_in urb failed %d", __func__, err); - } - usb_wwan_setup_urbs(serial); return 0; bail_out_error2: - for (j = 0; j < N_OUT_URB; j++) - kfree(portdata->out_buffer[j]); + for (i = 0; i < N_OUT_URB; i++) { + usb_free_urb(portdata->out_urbs[i]); + kfree(portdata->out_buffer[i]); + } bail_out_error: - for (j = 0; j < N_IN_URB; j++) - if (portdata->in_buffer[j]) - free_page((unsigned long)portdata->in_buffer[j]); + for (i = 0; i < N_IN_URB; i++) { + usb_free_urb(portdata->in_urbs[i]); + free_page((unsigned long)portdata->in_buffer[i]); + } kfree(portdata); - return 1; + + return -ENOMEM; } -EXPORT_SYMBOL(usb_wwan_startup); +EXPORT_SYMBOL_GPL(usb_wwan_port_probe); -static void stop_read_write_urbs(struct usb_serial *serial) +int usb_wwan_port_remove(struct usb_serial_port *port) { - int i, j; - struct usb_serial_port *port; + int i; struct usb_wwan_port_private *portdata; - /* Stop reading/writing urbs */ - for (i = 0; i < serial->num_ports; ++i) { - port = serial->port[i]; - portdata = usb_get_serial_port_data(port); - for (j = 0; j < N_IN_URB; j++) - usb_kill_urb(portdata->in_urbs[j]); - for (j = 0; j < N_OUT_URB; j++) - usb_kill_urb(portdata->out_urbs[j]); + portdata = usb_get_serial_port_data(port); + usb_set_serial_port_data(port, NULL); + + for (i = 0; i < N_IN_URB; i++) { + usb_free_urb(portdata->in_urbs[i]); + free_page((unsigned long)portdata->in_buffer[i]); + } + for (i = 0; i < N_OUT_URB; i++) { + usb_free_urb(portdata->out_urbs[i]); + kfree(portdata->out_buffer[i]); } -} -void usb_wwan_disconnect(struct usb_serial *serial) -{ - dbg("%s", __func__); + kfree(portdata); - stop_read_write_urbs(serial); + return 0; } -EXPORT_SYMBOL(usb_wwan_disconnect); +EXPORT_SYMBOL(usb_wwan_port_remove); -void usb_wwan_release(struct usb_serial *serial) +#ifdef CONFIG_PM +static void stop_urbs(struct usb_serial *serial) { int i, j; struct usb_serial_port *port; struct usb_wwan_port_private *portdata; - dbg("%s", __func__); - - /* Now free them */ for (i = 0; i < serial->num_ports; ++i) { port = serial->port[i]; portdata = usb_get_serial_port_data(port); - - for (j = 0; j < N_IN_URB; j++) { - usb_free_urb(portdata->in_urbs[j]); - free_page((unsigned long) - portdata->in_buffer[j]); - portdata->in_urbs[j] = NULL; - } - for (j = 0; j < N_OUT_URB; j++) { - usb_free_urb(portdata->out_urbs[j]); - kfree(portdata->out_buffer[j]); - portdata->out_urbs[j] = NULL; - } - } - - /* Now free per port private data */ - for (i = 0; i < serial->num_ports; i++) { - port = serial->port[i]; - kfree(usb_get_serial_port_data(port)); + if (!portdata) + continue; + for (j = 0; j < N_IN_URB; j++) + usb_kill_urb(portdata->in_urbs[j]); + for (j = 0; j < N_OUT_URB; j++) + usb_kill_urb(portdata->out_urbs[j]); + usb_kill_urb(port->interrupt_in_urb); } } -EXPORT_SYMBOL(usb_wwan_release); -#ifdef CONFIG_PM int usb_wwan_suspend(struct usb_serial *serial, pm_message_t message) { - struct usb_wwan_intf_private *intfdata = serial->private; - int b; + struct usb_wwan_intf_private *intfdata = usb_get_serial_data(serial); - dbg("%s entered", __func__); - - if (message.event & PM_EVENT_AUTO) { - spin_lock_irq(&intfdata->susp_lock); - b = intfdata->in_flight; - spin_unlock_irq(&intfdata->susp_lock); - - if (b) + spin_lock_irq(&intfdata->susp_lock); + if (PMSG_IS_AUTO(message)) { + if (intfdata->in_flight) { + spin_unlock_irq(&intfdata->susp_lock); return -EBUSY; + } } - - spin_lock_irq(&intfdata->susp_lock); intfdata->suspended = 1; spin_unlock_irq(&intfdata->susp_lock); - stop_read_write_urbs(serial); + + stop_urbs(serial); return 0; } EXPORT_SYMBOL(usb_wwan_suspend); -static void play_delayed(struct usb_serial_port *port) +/* Caller must hold susp_lock. */ +static int usb_wwan_submit_delayed_urbs(struct usb_serial_port *port) { - struct usb_wwan_intf_private *data; + struct usb_serial *serial = port->serial; + struct usb_wwan_intf_private *data = usb_get_serial_data(serial); struct usb_wwan_port_private *portdata; struct urb *urb; + int err_count = 0; int err; portdata = usb_get_serial_port_data(port); - data = port->serial->private; - while ((urb = usb_get_from_anchor(&portdata->delayed))) { + + for (;;) { + urb = usb_get_from_anchor(&portdata->delayed); + if (!urb) + break; + err = usb_submit_urb(urb, GFP_ATOMIC); - if (!err) - data->in_flight++; + if (err) { + dev_err(&port->dev, "%s: submit urb failed: %d\n", + __func__, err); + err_count++; + unbusy_queued_urb(urb, portdata); + usb_autopm_put_interface_async(serial->interface); + continue; + } + data->in_flight++; } + + if (err_count) + return -EIO; + + return 0; } int usb_wwan_resume(struct usb_serial *serial) { int i, j; struct usb_serial_port *port; - struct usb_wwan_intf_private *intfdata = serial->private; + struct usb_wwan_intf_private *intfdata = usb_get_serial_data(serial); struct usb_wwan_port_private *portdata; struct urb *urb; - int err = 0; + int err; + int err_count = 0; - dbg("%s entered", __func__); - /* get the interrupt URBs resubmitted unconditionally */ + spin_lock_irq(&intfdata->susp_lock); for (i = 0; i < serial->num_ports; i++) { port = serial->port[i]; - if (!port->interrupt_in_urb) { - dbg("%s: No interrupt URB for port %d", __func__, i); + + if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags)) continue; - } - err = usb_submit_urb(port->interrupt_in_urb, GFP_NOIO); - dbg("Submitted interrupt URB for port %d (result %d)", i, err); - if (err < 0) { - err("%s: Error %d for interrupt URB of port%d", - __func__, err, i); - goto err_out; - } - } - for (i = 0; i < serial->num_ports; i++) { - /* walk all ports */ - port = serial->port[i]; portdata = usb_get_serial_port_data(port); - /* skip closed ports */ - spin_lock_irq(&intfdata->susp_lock); - if (!portdata->opened) { - spin_unlock_irq(&intfdata->susp_lock); - continue; + if (port->interrupt_in_urb) { + err = usb_submit_urb(port->interrupt_in_urb, + GFP_ATOMIC); + if (err) { + dev_err(&port->dev, + "%s: submit int urb failed: %d\n", + __func__, err); + err_count++; + } } + err = usb_wwan_submit_delayed_urbs(port); + if (err) + err_count++; + for (j = 0; j < N_IN_URB; j++) { urb = portdata->in_urbs[j]; err = usb_submit_urb(urb, GFP_ATOMIC); if (err < 0) { - err("%s: Error %d for bulk URB %d", - __func__, err, i); - spin_unlock_irq(&intfdata->susp_lock); - goto err_out; + dev_err(&port->dev, + "%s: submit read urb %d failed: %d\n", + __func__, i, err); + err_count++; } } - play_delayed(port); - spin_unlock_irq(&intfdata->susp_lock); } - spin_lock_irq(&intfdata->susp_lock); intfdata->suspended = 0; spin_unlock_irq(&intfdata->susp_lock); -err_out: - return err; + + if (err_count) + return -EIO; + + return 0; } EXPORT_SYMBOL(usb_wwan_resume); #endif MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_VERSION(DRIVER_VERSION); MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug messages"); diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index 15a5d89b7f3..bf2bd40e5f2 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -16,7 +16,6 @@ #include <linux/kernel.h> #include <linux/errno.h> -#include <linux/init.h> #include <linux/slab.h> #include <linux/tty.h> #include <linux/tty_driver.h> @@ -27,6 +26,7 @@ #include <linux/uaccess.h> #include <linux/usb.h> #include <linux/usb/serial.h> +#include <linux/usb/cdc.h> #include "visor.h" /* @@ -50,12 +50,7 @@ static int palm_os_3_probe(struct usb_serial *serial, static int palm_os_4_probe(struct usb_serial *serial, const struct usb_device_id *id); -/* Parameters that may be passed into the module. */ -static int debug; -static __u16 vendor; -static __u16 product; - -static struct usb_device_id id_table [] = { +static const struct usb_device_id id_table[] = { { USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_VISOR_ID), .driver_info = (kernel_ulong_t)&palm_os_3_probe }, { USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_TREO_ID), @@ -114,23 +109,21 @@ static struct usb_device_id id_table [] = { .driver_info = (kernel_ulong_t)&palm_os_4_probe }, { USB_DEVICE(FOSSIL_VENDOR_ID, FOSSIL_ABACUS_ID), .driver_info = (kernel_ulong_t)&palm_os_4_probe }, - { }, /* optional parameter entry */ { } /* Terminating entry */ }; -static struct usb_device_id clie_id_5_table [] = { +static const struct usb_device_id clie_id_5_table[] = { { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_UX50_ID), .driver_info = (kernel_ulong_t)&palm_os_4_probe }, - { }, /* optional parameter entry */ { } /* Terminating entry */ }; -static struct usb_device_id clie_id_3_5_table [] = { +static const struct usb_device_id clie_id_3_5_table[] = { { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_3_5_ID) }, { } /* Terminating entry */ }; -static struct usb_device_id id_table_combined [] = { +static const struct usb_device_id id_table_combined[] = { { USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_VISOR_ID) }, { USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_TREO_ID) }, { USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_TREO600_ID) }, @@ -161,20 +154,11 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(ACEECA_VENDOR_ID, ACEECA_MEZ1000_ID) }, { USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_7135_ID) }, { USB_DEVICE(FOSSIL_VENDOR_ID, FOSSIL_ABACUS_ID) }, - { }, /* optional parameter entry */ { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, id_table_combined); -static struct usb_driver visor_driver = { - .name = "visor", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table_combined, - .no_dynamic_id = 1, -}; - /* All of the device info needed for the Handspring Visor, and Palm 4.0 devices */ static struct usb_serial_driver handspring_device = { @@ -183,7 +167,6 @@ static struct usb_serial_driver handspring_device = { .name = "visor", }, .description = "Handspring Visor / Palm OS", - .usb_driver = &visor_driver, .id_table = id_table, .num_ports = 2, .bulk_out_size = 256, @@ -204,7 +187,6 @@ static struct usb_serial_driver clie_5_device = { .name = "clie_5", }, .description = "Sony Clie 5.0", - .usb_driver = &visor_driver, .id_table = clie_id_5_table, .num_ports = 2, .bulk_out_size = 256, @@ -225,7 +207,6 @@ static struct usb_serial_driver clie_3_5_device = { .name = "clie_3.5", }, .description = "Sony Clie 3.5", - .usb_driver = &visor_driver, .id_table = clie_id_3_5_table, .num_ports = 1, .bulk_out_size = 256, @@ -236,6 +217,10 @@ static struct usb_serial_driver clie_3_5_device = { .attach = clie_3_5_startup, }; +static struct usb_serial_driver * const serial_drivers[] = { + &handspring_device, &clie_5_device, &clie_3_5_device, NULL +}; + /****************************************************************************** * Handspring Visor specific driver functions ******************************************************************************/ @@ -243,8 +228,6 @@ static int visor_open(struct tty_struct *tty, struct usb_serial_port *port) { int result = 0; - dbg("%s - port %d", __func__, port->number); - if (!port->read_urb) { /* this is needed for some brain dead Sony devices */ dev_err(&port->dev, "Device lied about number of ports, please use a lower one.\n"); @@ -257,7 +240,7 @@ static int visor_open(struct tty_struct *tty, struct usb_serial_port *port) goto exit; if (port->interrupt_in_urb) { - dbg("%s - adding interrupt input for treo", __func__); + dev_dbg(&port->dev, "adding interrupt input for treo\n"); result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); if (result) dev_err(&port->dev, @@ -273,26 +256,18 @@ static void visor_close(struct usb_serial_port *port) { unsigned char *transfer_buffer; - dbg("%s - port %d", __func__, port->number); - - /* shutdown our urbs */ usb_serial_generic_close(port); usb_kill_urb(port->interrupt_in_urb); - mutex_lock(&port->serial->disc_mutex); - if (!port->serial->disconnected) { - /* Try to send shutdown message, unless the device is gone */ - transfer_buffer = kmalloc(0x12, GFP_KERNEL); - if (transfer_buffer) { - usb_control_msg(port->serial->dev, + transfer_buffer = kmalloc(0x12, GFP_KERNEL); + if (!transfer_buffer) + return; + usb_control_msg(port->serial->dev, usb_rcvctrlpipe(port->serial->dev, 0), VISOR_CLOSE_NOTIFICATION, 0xc2, 0x0000, 0x0000, transfer_buffer, 0x12, 300); - kfree(transfer_buffer); - } - } - mutex_unlock(&port->serial->disc_mutex); + kfree(transfer_buffer); } static void visor_read_int_callback(struct urb *urb) @@ -309,12 +284,12 @@ static void visor_read_int_callback(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", - __func__, status); + dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n", + __func__, status); return; default: - dbg("%s - nonzero urb status received: %d", - __func__, status); + dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n", + __func__, status); goto exit; } @@ -325,8 +300,8 @@ static void visor_read_int_callback(struct urb *urb) * Rumor has it this endpoint is used to notify when data * is ready to be read from the bulk ones. */ - usb_serial_debug_data(debug, &port->dev, __func__, - urb->actual_length, urb->transfer_buffer); + usb_serial_debug_data(&port->dev, __func__, urb->actual_length, + urb->transfer_buffer); exit: result = usb_submit_urb(urb, GFP_ATOMIC); @@ -347,14 +322,9 @@ static int palm_os_3_probe(struct usb_serial *serial, int i; int num_ports = 0; - dbg("%s", __func__); - transfer_buffer = kmalloc(sizeof(*connection_info), GFP_KERNEL); - if (!transfer_buffer) { - dev_err(dev, "%s - kmalloc(%Zd) failed.\n", __func__, - sizeof(*connection_info)); + if (!transfer_buffer) return -ENOMEM; - } /* send a get connection info request */ retval = usb_control_msg(serial->dev, @@ -444,14 +414,9 @@ static int palm_os_4_probe(struct usb_serial *serial, unsigned char *transfer_buffer; int retval; - dbg("%s", __func__); - transfer_buffer = kmalloc(sizeof(*connection_info), GFP_KERNEL); - if (!transfer_buffer) { - dev_err(dev, "%s - kmalloc(%Zd) failed.\n", __func__, - sizeof(*connection_info)); + if (!transfer_buffer) return -ENOMEM; - } retval = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), @@ -462,8 +427,7 @@ static int palm_os_4_probe(struct usb_serial *serial, dev_err(dev, "%s - error %d getting connection info\n", __func__, retval); else - usb_serial_debug_data(debug, &serial->dev->dev, __func__, - retval, transfer_buffer); + usb_serial_debug_data(dev, __func__, retval, transfer_buffer); kfree(transfer_buffer); return 0; @@ -477,7 +441,16 @@ static int visor_probe(struct usb_serial *serial, int (*startup)(struct usb_serial *serial, const struct usb_device_id *id); - dbg("%s", __func__); + /* + * some Samsung Android phones in modem mode have the same ID + * as SPH-I500, but they are ACM devices, so dont bind to them + */ + if (id->idVendor == SAMSUNG_VENDOR_ID && + id->idProduct == SAMSUNG_SPH_I500_ID && + serial->dev->descriptor.bDeviceClass == USB_CLASS_COMM && + serial->dev->descriptor.bDeviceSubClass == + USB_CDC_SUBCLASS_ACM) + return -ENODEV; if (serial->dev->actconfig->desc.bConfigurationValue != 1) { dev_err(&serial->dev->dev, "active config #%d != 1 ??\n", @@ -509,8 +482,6 @@ static int clie_3_5_startup(struct usb_serial *serial) int result; u8 *data; - dbg("%s", __func__); - data = kmalloc(1, GFP_KERNEL); if (!data) return -ENOMEM; @@ -573,8 +544,6 @@ static int treo_attach(struct usb_serial *serial) (serial->num_interrupt_in == 0)) return 0; - dbg("%s", __func__); - /* * It appears that Treos and Kyoceras want to use the * 1st bulk in endpoint to communicate with the 2nd bulk out endpoint, @@ -584,10 +553,19 @@ static int treo_attach(struct usb_serial *serial) */ #define COPY_PORT(dest, src) \ do { \ + int i; \ + \ + for (i = 0; i < ARRAY_SIZE(src->read_urbs); ++i) { \ + dest->read_urbs[i] = src->read_urbs[i]; \ + dest->read_urbs[i]->context = dest; \ + dest->bulk_in_buffers[i] = src->bulk_in_buffers[i]; \ + } \ dest->read_urb = src->read_urb; \ dest->bulk_in_endpointAddress = src->bulk_in_endpointAddress;\ dest->bulk_in_buffer = src->bulk_in_buffer; \ + dest->bulk_in_size = src->bulk_in_size; \ dest->interrupt_in_urb = src->interrupt_in_urb; \ + dest->interrupt_in_urb->context = dest; \ dest->interrupt_in_endpointAddress = \ src->interrupt_in_endpointAddress;\ dest->interrupt_in_buffer = src->interrupt_in_buffer; \ @@ -610,8 +588,6 @@ static int clie_5_attach(struct usb_serial *serial) unsigned int pipe; int j; - dbg("%s", __func__); - /* TH55 registers 2 ports. Communication in from the UX50/TH55 uses bulk_in_endpointAddress from port 0. Communication out to the UX50/TH55 uses @@ -636,90 +612,8 @@ static int clie_5_attach(struct usb_serial *serial) return 0; } -static int __init visor_init(void) -{ - int i, retval; - /* Only if parameters were passed to us */ - if (vendor > 0 && product > 0) { - struct usb_device_id usb_dev_temp[] = { - { - USB_DEVICE(vendor, product), - .driver_info = - (kernel_ulong_t) &palm_os_4_probe - } - }; - - /* Find the last entry in id_table */ - for (i = 0;; i++) { - if (id_table[i].idVendor == 0) { - id_table[i] = usb_dev_temp[0]; - break; - } - } - /* Find the last entry in id_table_combined */ - for (i = 0;; i++) { - if (id_table_combined[i].idVendor == 0) { - id_table_combined[i] = usb_dev_temp[0]; - break; - } - } - printk(KERN_INFO KBUILD_MODNAME - ": Untested USB device specified at time of module insertion\n"); - printk(KERN_INFO KBUILD_MODNAME - ": Warning: This is not guaranteed to work\n"); - printk(KERN_INFO KBUILD_MODNAME - ": Using a newer kernel is preferred to this method\n"); - printk(KERN_INFO KBUILD_MODNAME - ": Adding Palm OS protocol 4.x support for unknown device: 0x%x/0x%x\n", - vendor, product); - } - retval = usb_serial_register(&handspring_device); - if (retval) - goto failed_handspring_register; - retval = usb_serial_register(&clie_3_5_device); - if (retval) - goto failed_clie_3_5_register; - retval = usb_serial_register(&clie_5_device); - if (retval) - goto failed_clie_5_register; - retval = usb_register(&visor_driver); - if (retval) - goto failed_usb_register; - printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n"); - - return 0; -failed_usb_register: - usb_serial_deregister(&clie_5_device); -failed_clie_5_register: - usb_serial_deregister(&clie_3_5_device); -failed_clie_3_5_register: - usb_serial_deregister(&handspring_device); -failed_handspring_register: - return retval; -} - - -static void __exit visor_exit (void) -{ - usb_deregister(&visor_driver); - usb_serial_deregister(&handspring_device); - usb_serial_deregister(&clie_3_5_device); - usb_serial_deregister(&clie_5_device); -} - - -module_init(visor_init); -module_exit(visor_exit); +module_usb_serial_driver(serial_drivers, id_table_combined); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); - -module_param(vendor, ushort, 0); -MODULE_PARM_DESC(vendor, "User specified vendor ID"); -module_param(product, ushort, 0); -MODULE_PARM_DESC(product, "User specified product ID"); - diff --git a/drivers/usb/serial/visor.h b/drivers/usb/serial/visor.h index 88db4d06aef..4c456dd69ce 100644 --- a/drivers/usb/serial/visor.h +++ b/drivers/usb/serial/visor.h @@ -136,7 +136,7 @@ struct visor_connection_info { * connections.end_point_info is non-zero. If value is 0, then * connections.port contains the endpoint number, which is the same for in * and out. - * @port_function_id: contains the creator id of the applicaton that opened + * @port_function_id: contains the creator id of the application that opened * this connection. * @port: contains the in/out endpoint number. Is 0 if in and out endpoint * numbers are different. diff --git a/drivers/usb/serial/vivopay-serial.c b/drivers/usb/serial/vivopay-serial.c deleted file mode 100644 index f719d00972f..00000000000 --- a/drivers/usb/serial/vivopay-serial.c +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (C) 2001-2005 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (C) 2009 Outpost Embedded, LLC - */ - -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/tty.h> -#include <linux/module.h> -#include <linux/usb.h> -#include <linux/usb/serial.h> - - -#define DRIVER_VERSION "v1.0" -#define DRIVER_DESC "ViVOpay USB Serial Driver" - -#define VIVOPAY_VENDOR_ID 0x1d5f - - -static struct usb_device_id id_table [] = { - /* ViVOpay 8800 */ - { USB_DEVICE(VIVOPAY_VENDOR_ID, 0x1004) }, - { }, -}; - -MODULE_DEVICE_TABLE(usb, id_table); - -static struct usb_driver vivopay_serial_driver = { - .name = "vivopay-serial", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, - .no_dynamic_id = 1, -}; - -static struct usb_serial_driver vivopay_serial_device = { - .driver = { - .owner = THIS_MODULE, - .name = "vivopay-serial", - }, - .id_table = id_table, - .usb_driver = &vivopay_serial_driver, - .num_ports = 1, -}; - -static int __init vivopay_serial_init(void) -{ - int retval; - retval = usb_serial_register(&vivopay_serial_device); - if (retval) - goto failed_usb_serial_register; - retval = usb_register(&vivopay_serial_driver); - if (retval) - goto failed_usb_register; - printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" - DRIVER_DESC "\n"); - return 0; -failed_usb_register: - usb_serial_deregister(&vivopay_serial_device); -failed_usb_serial_register: - return retval; -} - -static void __exit vivopay_serial_exit(void) -{ - usb_deregister(&vivopay_serial_driver); - usb_serial_deregister(&vivopay_serial_device); -} - -module_init(vivopay_serial_init); -module_exit(vivopay_serial_exit); - -MODULE_AUTHOR("Forest Bond <forest.bond@outpostembedded.com>"); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_VERSION(DRIVER_VERSION); -MODULE_LICENSE("GPL"); diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index 3f9ac88d588..e62f2dff8b7 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c @@ -14,62 +14,10 @@ * * See Documentation/usb/usb-serial.txt for more information on using this * driver - * - * (10/09/2002) Stuart MacDonald (stuartm@connecttech.com) - * Upgrade to full working driver - * - * (05/30/2001) gkh - * switched from using spinlock to a semaphore, which fixes lots of - * problems. - * - * (04/08/2001) gb - * Identify version on module load. - * - * 2001_Mar_19 gkh - * Fixed MOD_INC and MOD_DEC logic, the ability to open a port more - * than once, and the got the proper usb_device_id table entries so - * the driver works again. - * - * (11/01/2000) Adam J. Richter - * usb_device_id table support - * - * (10/05/2000) gkh - * Fixed bug with urb->dev not being set properly, now that the usb - * core needs it. - * - * (10/03/2000) smd - * firmware is improved to guard against crap sent to device - * firmware now replies CMD_FAILURE on bad things - * read_callback fix you provided for private info struct - * command_finished now indicates success or fail - * setup_port struct now packed to avoid gcc padding - * firmware uses 1 based port numbering, driver now handles that - * - * (09/11/2000) gkh - * Removed DEBUG #ifdefs with call to usb_serial_debug_data - * - * (07/19/2000) gkh - * Added module_init and module_exit functions to handle the fact that this - * driver is a loadable module now. - * Fixed bug with port->minor that was found by Al Borchers - * - * (07/04/2000) gkh - * Added support for port settings. Baud rate can now be changed. Line - * signals are not transferred to and from the tty layer yet, but things - * seem to be working well now. - * - * (05/04/2000) gkh - * First cut at open and close commands. Data can flow through the ports at - * default speeds now. - * - * (03/26/2000) gkh - * Split driver up into device specific pieces. - * */ #include <linux/kernel.h> #include <linux/errno.h> -#include <linux/init.h> #include <linux/slab.h> #include <linux/tty.h> #include <linux/tty_driver.h> @@ -83,12 +31,9 @@ #include <linux/serial_reg.h> #include <linux/serial.h> #include <linux/usb/serial.h> -#include <linux/firmware.h> -#include <linux/ihex.h> +#include <linux/usb/ezusb.h> #include "whiteheat.h" /* WhiteHEAT specific commands */ -static int debug; - #ifndef CMSPAR #define CMSPAR 0 #endif @@ -96,7 +41,6 @@ static int debug; /* * Version Information */ -#define DRIVER_VERSION "v2.0" #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Stuart MacDonald <stuartm@connecttech.com>" #define DRIVER_DESC "USB ConnectTech WhiteHEAT driver" @@ -129,13 +73,6 @@ static const struct usb_device_id id_table_combined[] = { MODULE_DEVICE_TABLE(usb, id_table_combined); -static struct usb_driver whiteheat_driver = { - .name = "whiteheat", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table_combined, - .no_dynamic_id = 1, -}; /* function prototypes for the Connect Tech WhiteHEAT prerenumeration device */ static int whiteheat_firmware_download(struct usb_serial *serial, @@ -145,26 +82,19 @@ static int whiteheat_firmware_attach(struct usb_serial *serial); /* function prototypes for the Connect Tech WhiteHEAT serial converter */ static int whiteheat_attach(struct usb_serial *serial); static void whiteheat_release(struct usb_serial *serial); +static int whiteheat_port_probe(struct usb_serial_port *port); +static int whiteheat_port_remove(struct usb_serial_port *port); static int whiteheat_open(struct tty_struct *tty, struct usb_serial_port *port); static void whiteheat_close(struct usb_serial_port *port); -static int whiteheat_write(struct tty_struct *tty, - struct usb_serial_port *port, - const unsigned char *buf, int count); -static int whiteheat_write_room(struct tty_struct *tty); -static int whiteheat_ioctl(struct tty_struct *tty, struct file *file, +static int whiteheat_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg); static void whiteheat_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old); -static int whiteheat_tiocmget(struct tty_struct *tty, struct file *file); -static int whiteheat_tiocmset(struct tty_struct *tty, struct file *file, +static int whiteheat_tiocmget(struct tty_struct *tty); +static int whiteheat_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear); static void whiteheat_break_ctl(struct tty_struct *tty, int break_state); -static int whiteheat_chars_in_buffer(struct tty_struct *tty); -static void whiteheat_throttle(struct tty_struct *tty); -static void whiteheat_unthrottle(struct tty_struct *tty); -static void whiteheat_read_callback(struct urb *urb); -static void whiteheat_write_callback(struct urb *urb); static struct usb_serial_driver whiteheat_fake_device = { .driver = { @@ -172,7 +102,6 @@ static struct usb_serial_driver whiteheat_fake_device = { .name = "whiteheatnofirm", }, .description = "Connect Tech - WhiteHEAT - (prerenumeration)", - .usb_driver = &whiteheat_driver, .id_table = id_table_prerenumeration, .num_ports = 1, .probe = whiteheat_firmware_download, @@ -185,27 +114,26 @@ static struct usb_serial_driver whiteheat_device = { .name = "whiteheat", }, .description = "Connect Tech - WhiteHEAT", - .usb_driver = &whiteheat_driver, .id_table = id_table_std, .num_ports = 4, .attach = whiteheat_attach, .release = whiteheat_release, + .port_probe = whiteheat_port_probe, + .port_remove = whiteheat_port_remove, .open = whiteheat_open, .close = whiteheat_close, - .write = whiteheat_write, - .write_room = whiteheat_write_room, .ioctl = whiteheat_ioctl, .set_termios = whiteheat_set_termios, .break_ctl = whiteheat_break_ctl, .tiocmget = whiteheat_tiocmget, .tiocmset = whiteheat_tiocmset, - .chars_in_buffer = whiteheat_chars_in_buffer, - .throttle = whiteheat_throttle, - .unthrottle = whiteheat_unthrottle, - .read_bulk_callback = whiteheat_read_callback, - .write_bulk_callback = whiteheat_write_callback, + .throttle = usb_serial_generic_throttle, + .unthrottle = usb_serial_generic_unthrottle, }; +static struct usb_serial_driver * const serial_drivers[] = { + &whiteheat_fake_device, &whiteheat_device, NULL +}; struct whiteheat_command_private { struct mutex mutex; @@ -217,29 +145,8 @@ struct whiteheat_command_private { __u8 result_buffer[64]; }; - -#define THROTTLED 0x01 -#define ACTUALLY_THROTTLED 0x02 - -static int urb_pool_size = 8; - -struct whiteheat_urb_wrap { - struct list_head list; - struct urb *urb; -}; - struct whiteheat_private { - spinlock_t lock; - __u8 flags; __u8 mcr; /* FIXME: no locking on mcr */ - struct list_head rx_urbs_free; - struct list_head rx_urbs_submitted; - struct list_head rx_urb_q; - struct work_struct rx_work; - struct usb_serial_port *port; - struct list_head tx_urbs_free; - struct list_head tx_urbs_submitted; - struct mutex deathwarrant; }; @@ -249,12 +156,6 @@ static void stop_command_port(struct usb_serial *serial); static void command_port_write_callback(struct urb *urb); static void command_port_read_callback(struct urb *urb); -static int start_port_read(struct usb_serial_port *port); -static struct whiteheat_urb_wrap *urb_to_wrap(struct urb *urb, - struct list_head *head); -static struct list_head *list_first(struct list_head *head); -static void rx_data_softint(struct work_struct *work); - static int firm_send_command(struct usb_serial_port *port, __u8 command, __u8 *data, __u8 datasize); static int firm_open(struct usb_serial_port *port); @@ -294,86 +195,15 @@ static int firm_report_tx_done(struct usb_serial_port *port); static int whiteheat_firmware_download(struct usb_serial *serial, const struct usb_device_id *id) { - int response, ret = -ENOENT; - const struct firmware *loader_fw = NULL, *firmware_fw = NULL; - const struct ihex_binrec *record; - - dbg("%s", __func__); + int response; - if (request_ihex_firmware(&firmware_fw, "whiteheat.fw", - &serial->dev->dev)) { - dev_err(&serial->dev->dev, - "%s - request \"whiteheat.fw\" failed\n", __func__); - goto out; + response = ezusb_fx1_ihex_firmware_download(serial->dev, "whiteheat_loader.fw"); + if (response >= 0) { + response = ezusb_fx1_ihex_firmware_download(serial->dev, "whiteheat.fw"); + if (response >= 0) + return 0; } - if (request_ihex_firmware(&loader_fw, "whiteheat_loader.fw", - &serial->dev->dev)) { - dev_err(&serial->dev->dev, - "%s - request \"whiteheat_loader.fw\" failed\n", - __func__); - goto out; - } - ret = 0; - response = ezusb_set_reset (serial, 1); - - record = (const struct ihex_binrec *)loader_fw->data; - while (record) { - response = ezusb_writememory (serial, be32_to_cpu(record->addr), - (unsigned char *)record->data, - be16_to_cpu(record->len), 0xa0); - if (response < 0) { - dev_err(&serial->dev->dev, "%s - ezusb_writememory " - "failed for loader (%d %04X %p %d)\n", - __func__, response, be32_to_cpu(record->addr), - record->data, be16_to_cpu(record->len)); - break; - } - record = ihex_next_binrec(record); - } - - response = ezusb_set_reset(serial, 0); - - record = (const struct ihex_binrec *)firmware_fw->data; - while (record && be32_to_cpu(record->addr) < 0x1b40) - record = ihex_next_binrec(record); - while (record) { - response = ezusb_writememory (serial, be32_to_cpu(record->addr), - (unsigned char *)record->data, - be16_to_cpu(record->len), 0xa3); - if (response < 0) { - dev_err(&serial->dev->dev, "%s - ezusb_writememory " - "failed for first firmware step " - "(%d %04X %p %d)\n", __func__, response, - be32_to_cpu(record->addr), record->data, - be16_to_cpu(record->len)); - break; - } - ++record; - } - - response = ezusb_set_reset(serial, 1); - - record = (const struct ihex_binrec *)firmware_fw->data; - while (record && be32_to_cpu(record->addr) < 0x1b40) { - response = ezusb_writememory (serial, be32_to_cpu(record->addr), - (unsigned char *)record->data, - be16_to_cpu(record->len), 0xa0); - if (response < 0) { - dev_err(&serial->dev->dev, "%s - ezusb_writememory " - "failed for second firmware step " - "(%d %04X %p %d)\n", __func__, response, - be32_to_cpu(record->addr), record->data, - be16_to_cpu(record->len)); - break; - } - ++record; - } - ret = 0; - response = ezusb_set_reset (serial, 0); - out: - release_firmware(loader_fw); - release_firmware(firmware_fw); - return ret; + return -ENOENT; } @@ -391,20 +221,12 @@ static int whiteheat_attach(struct usb_serial *serial) { struct usb_serial_port *command_port; struct whiteheat_command_private *command_info; - struct usb_serial_port *port; - struct whiteheat_private *info; struct whiteheat_hw_info *hw_info; int pipe; int ret; int alen; __u8 *command; __u8 *result; - int i; - int j; - struct urb *urb; - int buf_size; - struct whiteheat_urb_wrap *wrap; - struct list_head *tmp; command_port = serial->port[COMMAND_PORT]; @@ -459,99 +281,14 @@ static int whiteheat_attach(struct usb_serial *serial) hw_info = (struct whiteheat_hw_info *)&result[1]; - dev_info(&serial->dev->dev, "%s: Driver %s: Firmware v%d.%02d\n", - serial->type->description, DRIVER_VERSION, + dev_info(&serial->dev->dev, "%s: Firmware v%d.%02d\n", + serial->type->description, hw_info->sw_major_rev, hw_info->sw_minor_rev); - for (i = 0; i < serial->num_ports; i++) { - port = serial->port[i]; - - info = kmalloc(sizeof(struct whiteheat_private), GFP_KERNEL); - if (info == NULL) { - dev_err(&port->dev, - "%s: Out of memory for port structures\n", - serial->type->description); - goto no_private; - } - - spin_lock_init(&info->lock); - mutex_init(&info->deathwarrant); - info->flags = 0; - info->mcr = 0; - INIT_WORK(&info->rx_work, rx_data_softint); - info->port = port; - - INIT_LIST_HEAD(&info->rx_urbs_free); - INIT_LIST_HEAD(&info->rx_urbs_submitted); - INIT_LIST_HEAD(&info->rx_urb_q); - INIT_LIST_HEAD(&info->tx_urbs_free); - INIT_LIST_HEAD(&info->tx_urbs_submitted); - - for (j = 0; j < urb_pool_size; j++) { - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) { - dev_err(&port->dev, "No free urbs available\n"); - goto no_rx_urb; - } - buf_size = port->read_urb->transfer_buffer_length; - urb->transfer_buffer = kmalloc(buf_size, GFP_KERNEL); - if (!urb->transfer_buffer) { - dev_err(&port->dev, - "Couldn't allocate urb buffer\n"); - goto no_rx_buf; - } - wrap = kmalloc(sizeof(*wrap), GFP_KERNEL); - if (!wrap) { - dev_err(&port->dev, - "Couldn't allocate urb wrapper\n"); - goto no_rx_wrap; - } - usb_fill_bulk_urb(urb, serial->dev, - usb_rcvbulkpipe(serial->dev, - port->bulk_in_endpointAddress), - urb->transfer_buffer, buf_size, - whiteheat_read_callback, port); - wrap->urb = urb; - list_add(&wrap->list, &info->rx_urbs_free); - - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) { - dev_err(&port->dev, "No free urbs available\n"); - goto no_tx_urb; - } - buf_size = port->write_urb->transfer_buffer_length; - urb->transfer_buffer = kmalloc(buf_size, GFP_KERNEL); - if (!urb->transfer_buffer) { - dev_err(&port->dev, - "Couldn't allocate urb buffer\n"); - goto no_tx_buf; - } - wrap = kmalloc(sizeof(*wrap), GFP_KERNEL); - if (!wrap) { - dev_err(&port->dev, - "Couldn't allocate urb wrapper\n"); - goto no_tx_wrap; - } - usb_fill_bulk_urb(urb, serial->dev, - usb_sndbulkpipe(serial->dev, - port->bulk_out_endpointAddress), - urb->transfer_buffer, buf_size, - whiteheat_write_callback, port); - wrap->urb = urb; - list_add(&wrap->list, &info->tx_urbs_free); - } - - usb_set_serial_port_data(port, info); - } - command_info = kmalloc(sizeof(struct whiteheat_command_private), GFP_KERNEL); - if (command_info == NULL) { - dev_err(&serial->dev->dev, - "%s: Out of memory for port structures\n", - serial->type->description); + if (!command_info) goto no_command_private; - } mutex_init(&command_info->mutex); command_info->port_running = 0; @@ -576,39 +313,10 @@ no_firmware: "%s: please contact support@connecttech.com\n", serial->type->description); kfree(result); + kfree(command); return -ENODEV; no_command_private: - for (i = serial->num_ports - 1; i >= 0; i--) { - port = serial->port[i]; - info = usb_get_serial_port_data(port); - for (j = urb_pool_size - 1; j >= 0; j--) { - tmp = list_first(&info->tx_urbs_free); - list_del(tmp); - wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); - urb = wrap->urb; - kfree(wrap); -no_tx_wrap: - kfree(urb->transfer_buffer); -no_tx_buf: - usb_free_urb(urb); -no_tx_urb: - tmp = list_first(&info->rx_urbs_free); - list_del(tmp); - wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); - urb = wrap->urb; - kfree(wrap); -no_rx_wrap: - kfree(urb->transfer_buffer); -no_rx_buf: - usb_free_urb(urb); -no_rx_urb: - ; - } - kfree(info); -no_private: - ; - } kfree(result); no_result_buffer: kfree(command); @@ -616,60 +324,46 @@ no_command_buffer: return -ENOMEM; } - static void whiteheat_release(struct usb_serial *serial) { struct usb_serial_port *command_port; - struct usb_serial_port *port; - struct whiteheat_private *info; - struct whiteheat_urb_wrap *wrap; - struct urb *urb; - struct list_head *tmp; - struct list_head *tmp2; - int i; - - dbg("%s", __func__); /* free up our private data for our command port */ command_port = serial->port[COMMAND_PORT]; kfree(usb_get_serial_port_data(command_port)); +} - for (i = 0; i < serial->num_ports; i++) { - port = serial->port[i]; - info = usb_get_serial_port_data(port); - list_for_each_safe(tmp, tmp2, &info->rx_urbs_free) { - list_del(tmp); - wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); - urb = wrap->urb; - kfree(wrap); - kfree(urb->transfer_buffer); - usb_free_urb(urb); - } - list_for_each_safe(tmp, tmp2, &info->tx_urbs_free) { - list_del(tmp); - wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); - urb = wrap->urb; - kfree(wrap); - kfree(urb->transfer_buffer); - usb_free_urb(urb); - } - kfree(info); - } +static int whiteheat_port_probe(struct usb_serial_port *port) +{ + struct whiteheat_private *info; + + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + usb_set_serial_port_data(port, info); + + return 0; } -static int whiteheat_open(struct tty_struct *tty, struct usb_serial_port *port) +static int whiteheat_port_remove(struct usb_serial_port *port) { - int retval = 0; + struct whiteheat_private *info; + + info = usb_get_serial_port_data(port); + kfree(info); + + return 0; +} - dbg("%s - port %d", __func__, port->number); +static int whiteheat_open(struct tty_struct *tty, struct usb_serial_port *port) +{ + int retval; retval = start_command_port(port->serial); if (retval) goto exit; - if (tty) - tty->low_latency = 1; - /* send an open port command */ retval = firm_open(port); if (retval) { @@ -691,156 +385,33 @@ static int whiteheat_open(struct tty_struct *tty, struct usb_serial_port *port) usb_clear_halt(port->serial->dev, port->read_urb->pipe); usb_clear_halt(port->serial->dev, port->write_urb->pipe); - /* Start reading from the device */ - retval = start_port_read(port); + retval = usb_serial_generic_open(tty, port); if (retval) { - dev_err(&port->dev, - "%s - failed submitting read urb, error %d\n", - __func__, retval); firm_close(port); stop_command_port(port->serial); goto exit; } - exit: - dbg("%s - exit, retval = %d", __func__, retval); return retval; } static void whiteheat_close(struct usb_serial_port *port) { - struct whiteheat_private *info = usb_get_serial_port_data(port); - struct whiteheat_urb_wrap *wrap; - struct urb *urb; - struct list_head *tmp; - struct list_head *tmp2; - - dbg("%s - port %d", __func__, port->number); - firm_report_tx_done(port); firm_close(port); - /* shutdown our bulk reads and writes */ - mutex_lock(&info->deathwarrant); - spin_lock_irq(&info->lock); - list_for_each_safe(tmp, tmp2, &info->rx_urbs_submitted) { - wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); - urb = wrap->urb; - list_del(tmp); - spin_unlock_irq(&info->lock); - usb_kill_urb(urb); - spin_lock_irq(&info->lock); - list_add(tmp, &info->rx_urbs_free); - } - list_for_each_safe(tmp, tmp2, &info->rx_urb_q) - list_move(tmp, &info->rx_urbs_free); - list_for_each_safe(tmp, tmp2, &info->tx_urbs_submitted) { - wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); - urb = wrap->urb; - list_del(tmp); - spin_unlock_irq(&info->lock); - usb_kill_urb(urb); - spin_lock_irq(&info->lock); - list_add(tmp, &info->tx_urbs_free); - } - spin_unlock_irq(&info->lock); - mutex_unlock(&info->deathwarrant); - stop_command_port(port->serial); -} - - -static int whiteheat_write(struct tty_struct *tty, - struct usb_serial_port *port, const unsigned char *buf, int count) -{ - struct usb_serial *serial = port->serial; - struct whiteheat_private *info = usb_get_serial_port_data(port); - struct whiteheat_urb_wrap *wrap; - struct urb *urb; - int result; - int bytes; - int sent = 0; - unsigned long flags; - struct list_head *tmp; - - dbg("%s - port %d", __func__, port->number); + usb_serial_generic_close(port); - if (count == 0) { - dbg("%s - write request of 0 bytes", __func__); - return (0); - } - - while (count) { - spin_lock_irqsave(&info->lock, flags); - if (list_empty(&info->tx_urbs_free)) { - spin_unlock_irqrestore(&info->lock, flags); - break; - } - tmp = list_first(&info->tx_urbs_free); - list_del(tmp); - spin_unlock_irqrestore(&info->lock, flags); - - wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); - urb = wrap->urb; - bytes = (count > port->bulk_out_size) ? - port->bulk_out_size : count; - memcpy(urb->transfer_buffer, buf + sent, bytes); - - usb_serial_debug_data(debug, &port->dev, - __func__, bytes, urb->transfer_buffer); - - urb->dev = serial->dev; - urb->transfer_buffer_length = bytes; - result = usb_submit_urb(urb, GFP_ATOMIC); - if (result) { - dev_err(&port->dev, - "%s - failed submitting write urb, error %d\n", - __func__, result); - sent = result; - spin_lock_irqsave(&info->lock, flags); - list_add(tmp, &info->tx_urbs_free); - spin_unlock_irqrestore(&info->lock, flags); - break; - } else { - sent += bytes; - count -= bytes; - spin_lock_irqsave(&info->lock, flags); - list_add(tmp, &info->tx_urbs_submitted); - spin_unlock_irqrestore(&info->lock, flags); - } - } - - return sent; -} - -static int whiteheat_write_room(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct whiteheat_private *info = usb_get_serial_port_data(port); - struct list_head *tmp; - int room = 0; - unsigned long flags; - - dbg("%s - port %d", __func__, port->number); - - spin_lock_irqsave(&info->lock, flags); - list_for_each(tmp, &info->tx_urbs_free) - room++; - spin_unlock_irqrestore(&info->lock, flags); - room *= port->bulk_out_size; - - dbg("%s - returns %d", __func__, room); - return (room); + stop_command_port(port->serial); } -static int whiteheat_tiocmget(struct tty_struct *tty, struct file *file) +static int whiteheat_tiocmget(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; struct whiteheat_private *info = usb_get_serial_port_data(port); unsigned int modem_signals = 0; - dbg("%s - port %d", __func__, port->number); - firm_get_dtr_rts(port); if (info->mcr & UART_MCR_DTR) modem_signals |= TIOCM_DTR; @@ -850,14 +421,12 @@ static int whiteheat_tiocmget(struct tty_struct *tty, struct file *file) return modem_signals; } -static int whiteheat_tiocmset(struct tty_struct *tty, struct file *file, +static int whiteheat_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) { struct usb_serial_port *port = tty->driver_data; struct whiteheat_private *info = usb_get_serial_port_data(port); - dbg("%s - port %d", __func__, port->number); - if (set & TIOCM_RTS) info->mcr |= UART_MCR_RTS; if (set & TIOCM_DTR) @@ -874,23 +443,21 @@ static int whiteheat_tiocmset(struct tty_struct *tty, struct file *file, } -static int whiteheat_ioctl(struct tty_struct *tty, struct file *file, +static int whiteheat_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { struct usb_serial_port *port = tty->driver_data; struct serial_struct serstruct; void __user *user_arg = (void __user *)arg; - dbg("%s - port %d, cmd 0x%.4x", __func__, port->number, cmd); - switch (cmd) { case TIOCGSERIAL: memset(&serstruct, 0, sizeof(serstruct)); serstruct.type = PORT_16654; - serstruct.line = port->serial->minor; - serstruct.port = port->number; + serstruct.line = port->minor; + serstruct.port = port->port_number; serstruct.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ; - serstruct.xmit_fifo_size = port->bulk_out_size; + serstruct.xmit_fifo_size = kfifo_size(&port->write_fifo); serstruct.custom_divisor = 0; serstruct.baud_base = 460800; serstruct.close_delay = CLOSING_DELAY; @@ -920,60 +487,6 @@ static void whiteheat_break_ctl(struct tty_struct *tty, int break_state) } -static int whiteheat_chars_in_buffer(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct whiteheat_private *info = usb_get_serial_port_data(port); - struct list_head *tmp; - struct whiteheat_urb_wrap *wrap; - int chars = 0; - unsigned long flags; - - dbg("%s - port %d", __func__, port->number); - - spin_lock_irqsave(&info->lock, flags); - list_for_each(tmp, &info->tx_urbs_submitted) { - wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); - chars += wrap->urb->transfer_buffer_length; - } - spin_unlock_irqrestore(&info->lock, flags); - - dbg("%s - returns %d", __func__, chars); - return chars; -} - - -static void whiteheat_throttle(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct whiteheat_private *info = usb_get_serial_port_data(port); - - dbg("%s - port %d", __func__, port->number); - - spin_lock_irq(&info->lock); - info->flags |= THROTTLED; - spin_unlock_irq(&info->lock); -} - - -static void whiteheat_unthrottle(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct whiteheat_private *info = usb_get_serial_port_data(port); - int actually_throttled; - - dbg("%s - port %d", __func__, port->number); - - spin_lock_irq(&info->lock); - actually_throttled = info->flags & ACTUALLY_THROTTLED; - info->flags &= ~(THROTTLED | ACTUALLY_THROTTLED); - spin_unlock_irq(&info->lock); - - if (actually_throttled) - rx_data_softint(&info->rx_work); -} - - /***************************************************************************** * Connect Tech's White Heat callback routines *****************************************************************************/ @@ -981,10 +494,8 @@ static void command_port_write_callback(struct urb *urb) { int status = urb->status; - dbg("%s", __func__); - if (status) { - dbg("nonzero urb status: %d", status); + dev_dbg(&urb->dev->dev, "nonzero urb status: %d\n", status); return; } } @@ -998,23 +509,20 @@ static void command_port_read_callback(struct urb *urb) unsigned char *data = urb->transfer_buffer; int result; - dbg("%s", __func__); - command_info = usb_get_serial_port_data(command_port); if (!command_info) { - dbg("%s - command_info is NULL, exiting.", __func__); + dev_dbg(&urb->dev->dev, "%s - command_info is NULL, exiting.\n", __func__); return; } if (status) { - dbg("%s - nonzero urb status: %d", __func__, status); + dev_dbg(&urb->dev->dev, "%s - nonzero urb status: %d\n", __func__, status); if (status != -ENOENT) command_info->command_finished = WHITEHEAT_CMD_FAILURE; wake_up(&command_info->wait_command); return; } - usb_serial_debug_data(debug, &command_port->dev, - __func__, urb->actual_length, data); + usb_serial_debug_data(&command_port->dev, __func__, urb->actual_length, data); if (data[0] == WHITEHEAT_CMD_COMPLETE) { command_info->command_finished = WHITEHEAT_CMD_COMPLETE; @@ -1025,98 +533,23 @@ static void command_port_read_callback(struct urb *urb) } else if (data[0] == WHITEHEAT_EVENT) { /* These are unsolicited reports from the firmware, hence no waiting command to wakeup */ - dbg("%s - event received", __func__); + dev_dbg(&urb->dev->dev, "%s - event received\n", __func__); } else if (data[0] == WHITEHEAT_GET_DTR_RTS) { memcpy(command_info->result_buffer, &data[1], urb->actual_length - 1); command_info->command_finished = WHITEHEAT_CMD_COMPLETE; wake_up(&command_info->wait_command); } else - dbg("%s - bad reply from firmware", __func__); + dev_dbg(&urb->dev->dev, "%s - bad reply from firmware\n", __func__); /* Continue trying to always read */ - command_port->read_urb->dev = command_port->serial->dev; result = usb_submit_urb(command_port->read_urb, GFP_ATOMIC); if (result) - dbg("%s - failed resubmitting read urb, error %d", + dev_dbg(&urb->dev->dev, "%s - failed resubmitting read urb, error %d\n", __func__, result); } -static void whiteheat_read_callback(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - struct whiteheat_urb_wrap *wrap; - unsigned char *data = urb->transfer_buffer; - struct whiteheat_private *info = usb_get_serial_port_data(port); - int status = urb->status; - - dbg("%s - port %d", __func__, port->number); - - spin_lock(&info->lock); - wrap = urb_to_wrap(urb, &info->rx_urbs_submitted); - if (!wrap) { - spin_unlock(&info->lock); - dev_err(&port->dev, "%s - Not my urb!\n", __func__); - return; - } - list_del(&wrap->list); - spin_unlock(&info->lock); - - if (status) { - dbg("%s - nonzero read bulk status received: %d", - __func__, status); - spin_lock(&info->lock); - list_add(&wrap->list, &info->rx_urbs_free); - spin_unlock(&info->lock); - return; - } - - usb_serial_debug_data(debug, &port->dev, - __func__, urb->actual_length, data); - - spin_lock(&info->lock); - list_add_tail(&wrap->list, &info->rx_urb_q); - if (info->flags & THROTTLED) { - info->flags |= ACTUALLY_THROTTLED; - spin_unlock(&info->lock); - return; - } - spin_unlock(&info->lock); - - schedule_work(&info->rx_work); -} - - -static void whiteheat_write_callback(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - struct whiteheat_private *info = usb_get_serial_port_data(port); - struct whiteheat_urb_wrap *wrap; - int status = urb->status; - - dbg("%s - port %d", __func__, port->number); - - spin_lock(&info->lock); - wrap = urb_to_wrap(urb, &info->tx_urbs_submitted); - if (!wrap) { - spin_unlock(&info->lock); - dev_err(&port->dev, "%s - Not my urb!\n", __func__); - return; - } - list_move(&wrap->list, &info->tx_urbs_free); - spin_unlock(&info->lock); - - if (status) { - dbg("%s - nonzero write bulk status received: %d", - __func__, status); - return; - } - - usb_serial_port_softint(port); -} - - /***************************************************************************** * Connect Tech's White Heat firmware interface *****************************************************************************/ @@ -1126,11 +559,12 @@ static int firm_send_command(struct usb_serial_port *port, __u8 command, struct usb_serial_port *command_port; struct whiteheat_command_private *command_info; struct whiteheat_private *info; + struct device *dev = &port->dev; __u8 *transfer_buffer; int retval = 0; int t; - dbg("%s - command %d", __func__, command); + dev_dbg(dev, "%s - command %d\n", __func__, command); command_port = port->serial->port[COMMAND_PORT]; command_info = usb_get_serial_port_data(command_port); @@ -1141,10 +575,9 @@ static int firm_send_command(struct usb_serial_port *port, __u8 command, transfer_buffer[0] = command; memcpy(&transfer_buffer[1], data, datasize); command_port->write_urb->transfer_buffer_length = datasize + 1; - command_port->write_urb->dev = port->serial->dev; retval = usb_submit_urb(command_port->write_urb, GFP_NOIO); if (retval) { - dbg("%s - submit urb failed", __func__); + dev_dbg(dev, "%s - submit urb failed\n", __func__); goto exit; } @@ -1155,19 +588,19 @@ static int firm_send_command(struct usb_serial_port *port, __u8 command, usb_kill_urb(command_port->write_urb); if (command_info->command_finished == false) { - dbg("%s - command timed out.", __func__); + dev_dbg(dev, "%s - command timed out.\n", __func__); retval = -ETIMEDOUT; goto exit; } if (command_info->command_finished == WHITEHEAT_CMD_FAILURE) { - dbg("%s - command failed.", __func__); + dev_dbg(dev, "%s - command failed.\n", __func__); retval = -EIO; goto exit; } if (command_info->command_finished == WHITEHEAT_CMD_COMPLETE) { - dbg("%s - command completed.", __func__); + dev_dbg(dev, "%s - command completed.\n", __func__); switch (command) { case WHITEHEAT_GET_DTR_RTS: info = usb_get_serial_port_data(port); @@ -1186,7 +619,7 @@ static int firm_open(struct usb_serial_port *port) { struct whiteheat_simple open_command; - open_command.port = port->number - port->serial->minor + 1; + open_command.port = port->port_number + 1; return firm_send_command(port, WHITEHEAT_OPEN, (__u8 *)&open_command, sizeof(open_command)); } @@ -1196,7 +629,7 @@ static int firm_close(struct usb_serial_port *port) { struct whiteheat_simple close_command; - close_command.port = port->number - port->serial->minor + 1; + close_command.port = port->port_number + 1; return firm_send_command(port, WHITEHEAT_CLOSE, (__u8 *)&close_command, sizeof(close_command)); } @@ -1205,10 +638,11 @@ static int firm_close(struct usb_serial_port *port) static void firm_setup_port(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; + struct device *dev = &port->dev; struct whiteheat_port_settings port_settings; - unsigned int cflag = tty->termios->c_cflag; + unsigned int cflag = tty->termios.c_cflag; - port_settings.port = port->number + 1; + port_settings.port = port->port_number + 1; /* get the byte size */ switch (cflag & CSIZE) { @@ -1218,7 +652,7 @@ static void firm_setup_port(struct tty_struct *tty) default: case CS8: port_settings.bits = 8; break; } - dbg("%s - data bits = %d", __func__, port_settings.bits); + dev_dbg(dev, "%s - data bits = %d\n", __func__, port_settings.bits); /* determine the parity */ if (cflag & PARENB) @@ -1234,14 +668,14 @@ static void firm_setup_port(struct tty_struct *tty) port_settings.parity = WHITEHEAT_PAR_EVEN; else port_settings.parity = WHITEHEAT_PAR_NONE; - dbg("%s - parity = %c", __func__, port_settings.parity); + dev_dbg(dev, "%s - parity = %c\n", __func__, port_settings.parity); /* figure out the stop bits requested */ if (cflag & CSTOPB) port_settings.stop = 2; else port_settings.stop = 1; - dbg("%s - stop bits = %d", __func__, port_settings.stop); + dev_dbg(dev, "%s - stop bits = %d\n", __func__, port_settings.stop); /* figure out the flow control settings */ if (cflag & CRTSCTS) @@ -1249,7 +683,7 @@ static void firm_setup_port(struct tty_struct *tty) WHITEHEAT_HFLOW_RTS); else port_settings.hflow = WHITEHEAT_HFLOW_NONE; - dbg("%s - hardware flow control = %s %s %s %s", __func__, + dev_dbg(dev, "%s - hardware flow control = %s %s %s %s\n", __func__, (port_settings.hflow & WHITEHEAT_HFLOW_CTS) ? "CTS" : "", (port_settings.hflow & WHITEHEAT_HFLOW_RTS) ? "RTS" : "", (port_settings.hflow & WHITEHEAT_HFLOW_DSR) ? "DSR" : "", @@ -1260,16 +694,15 @@ static void firm_setup_port(struct tty_struct *tty) port_settings.sflow = WHITEHEAT_SFLOW_RXTX; else port_settings.sflow = WHITEHEAT_SFLOW_NONE; - dbg("%s - software flow control = %c", __func__, port_settings.sflow); + dev_dbg(dev, "%s - software flow control = %c\n", __func__, port_settings.sflow); port_settings.xon = START_CHAR(tty); port_settings.xoff = STOP_CHAR(tty); - dbg("%s - XON = %2x, XOFF = %2x", - __func__, port_settings.xon, port_settings.xoff); + dev_dbg(dev, "%s - XON = %2x, XOFF = %2x\n", __func__, port_settings.xon, port_settings.xoff); /* get the baud rate wanted */ port_settings.baud = tty_get_baud_rate(tty); - dbg("%s - baud rate = %d", __func__, port_settings.baud); + dev_dbg(dev, "%s - baud rate = %d\n", __func__, port_settings.baud); /* fixme: should set validated settings */ tty_encode_baud_rate(tty, port_settings.baud, port_settings.baud); @@ -1286,7 +719,7 @@ static int firm_set_rts(struct usb_serial_port *port, __u8 onoff) { struct whiteheat_set_rdb rts_command; - rts_command.port = port->number - port->serial->minor + 1; + rts_command.port = port->port_number + 1; rts_command.state = onoff; return firm_send_command(port, WHITEHEAT_SET_RTS, (__u8 *)&rts_command, sizeof(rts_command)); @@ -1297,7 +730,7 @@ static int firm_set_dtr(struct usb_serial_port *port, __u8 onoff) { struct whiteheat_set_rdb dtr_command; - dtr_command.port = port->number - port->serial->minor + 1; + dtr_command.port = port->port_number + 1; dtr_command.state = onoff; return firm_send_command(port, WHITEHEAT_SET_DTR, (__u8 *)&dtr_command, sizeof(dtr_command)); @@ -1308,7 +741,7 @@ static int firm_set_break(struct usb_serial_port *port, __u8 onoff) { struct whiteheat_set_rdb break_command; - break_command.port = port->number - port->serial->minor + 1; + break_command.port = port->port_number + 1; break_command.state = onoff; return firm_send_command(port, WHITEHEAT_SET_BREAK, (__u8 *)&break_command, sizeof(break_command)); @@ -1319,7 +752,7 @@ static int firm_purge(struct usb_serial_port *port, __u8 rxtx) { struct whiteheat_purge purge_command; - purge_command.port = port->number - port->serial->minor + 1; + purge_command.port = port->port_number + 1; purge_command.what = rxtx; return firm_send_command(port, WHITEHEAT_PURGE, (__u8 *)&purge_command, sizeof(purge_command)); @@ -1330,7 +763,7 @@ static int firm_get_dtr_rts(struct usb_serial_port *port) { struct whiteheat_simple get_dr_command; - get_dr_command.port = port->number - port->serial->minor + 1; + get_dr_command.port = port->port_number + 1; return firm_send_command(port, WHITEHEAT_GET_DTR_RTS, (__u8 *)&get_dr_command, sizeof(get_dr_command)); } @@ -1340,7 +773,7 @@ static int firm_report_tx_done(struct usb_serial_port *port) { struct whiteheat_simple close_command; - close_command.port = port->number - port->serial->minor + 1; + close_command.port = port->port_number + 1; return firm_send_command(port, WHITEHEAT_REPORT_TX_DONE, (__u8 *)&close_command, sizeof(close_command)); } @@ -1362,7 +795,6 @@ static int start_command_port(struct usb_serial *serial) /* Work around HCD bugs */ usb_clear_halt(serial->dev, command_port->read_urb->pipe); - command_port->read_urb->dev = serial->dev; retval = usb_submit_urb(command_port->read_urb, GFP_KERNEL); if (retval) { dev_err(&serial->dev->dev, @@ -1393,163 +825,7 @@ static void stop_command_port(struct usb_serial *serial) mutex_unlock(&command_info->mutex); } - -static int start_port_read(struct usb_serial_port *port) -{ - struct whiteheat_private *info = usb_get_serial_port_data(port); - struct whiteheat_urb_wrap *wrap; - struct urb *urb; - int retval = 0; - unsigned long flags; - struct list_head *tmp; - struct list_head *tmp2; - - spin_lock_irqsave(&info->lock, flags); - - list_for_each_safe(tmp, tmp2, &info->rx_urbs_free) { - list_del(tmp); - wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); - urb = wrap->urb; - urb->dev = port->serial->dev; - spin_unlock_irqrestore(&info->lock, flags); - retval = usb_submit_urb(urb, GFP_KERNEL); - if (retval) { - spin_lock_irqsave(&info->lock, flags); - list_add(tmp, &info->rx_urbs_free); - list_for_each_safe(tmp, tmp2, &info->rx_urbs_submitted) { - wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); - urb = wrap->urb; - list_del(tmp); - spin_unlock_irqrestore(&info->lock, flags); - usb_kill_urb(urb); - spin_lock_irqsave(&info->lock, flags); - list_add(tmp, &info->rx_urbs_free); - } - break; - } - spin_lock_irqsave(&info->lock, flags); - list_add(tmp, &info->rx_urbs_submitted); - } - - spin_unlock_irqrestore(&info->lock, flags); - - return retval; -} - - -static struct whiteheat_urb_wrap *urb_to_wrap(struct urb *urb, - struct list_head *head) -{ - struct whiteheat_urb_wrap *wrap; - struct list_head *tmp; - - list_for_each(tmp, head) { - wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); - if (wrap->urb == urb) - return wrap; - } - - return NULL; -} - - -static struct list_head *list_first(struct list_head *head) -{ - return head->next; -} - - -static void rx_data_softint(struct work_struct *work) -{ - struct whiteheat_private *info = - container_of(work, struct whiteheat_private, rx_work); - struct usb_serial_port *port = info->port; - struct tty_struct *tty = tty_port_tty_get(&port->port); - struct whiteheat_urb_wrap *wrap; - struct urb *urb; - unsigned long flags; - struct list_head *tmp; - struct list_head *tmp2; - int result; - int sent = 0; - - spin_lock_irqsave(&info->lock, flags); - if (info->flags & THROTTLED) { - spin_unlock_irqrestore(&info->lock, flags); - goto out; - } - - list_for_each_safe(tmp, tmp2, &info->rx_urb_q) { - list_del(tmp); - spin_unlock_irqrestore(&info->lock, flags); - - wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); - urb = wrap->urb; - - if (tty && urb->actual_length) - sent += tty_insert_flip_string(tty, - urb->transfer_buffer, urb->actual_length); - - urb->dev = port->serial->dev; - result = usb_submit_urb(urb, GFP_ATOMIC); - if (result) { - dev_err(&port->dev, - "%s - failed resubmitting read urb, error %d\n", - __func__, result); - spin_lock_irqsave(&info->lock, flags); - list_add(tmp, &info->rx_urbs_free); - continue; - } - - spin_lock_irqsave(&info->lock, flags); - list_add(tmp, &info->rx_urbs_submitted); - } - spin_unlock_irqrestore(&info->lock, flags); - - if (sent) - tty_flip_buffer_push(tty); -out: - tty_kref_put(tty); -} - - -/***************************************************************************** - * Connect Tech's White Heat module functions - *****************************************************************************/ -static int __init whiteheat_init(void) -{ - int retval; - retval = usb_serial_register(&whiteheat_fake_device); - if (retval) - goto failed_fake_register; - retval = usb_serial_register(&whiteheat_device); - if (retval) - goto failed_device_register; - retval = usb_register(&whiteheat_driver); - if (retval) - goto failed_usb_register; - printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" - DRIVER_DESC "\n"); - return 0; -failed_usb_register: - usb_serial_deregister(&whiteheat_device); -failed_device_register: - usb_serial_deregister(&whiteheat_fake_device); -failed_fake_register: - return retval; -} - - -static void __exit whiteheat_exit(void) -{ - usb_deregister(&whiteheat_driver); - usb_serial_deregister(&whiteheat_fake_device); - usb_serial_deregister(&whiteheat_device); -} - - -module_init(whiteheat_init); -module_exit(whiteheat_exit); +module_usb_serial_driver(serial_drivers, id_table_combined); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); @@ -1557,9 +833,3 @@ MODULE_LICENSE("GPL"); MODULE_FIRMWARE("whiteheat.fw"); MODULE_FIRMWARE("whiteheat_loader.fw"); - -module_param(urb_pool_size, int, 0); -MODULE_PARM_DESC(urb_pool_size, "Number of urbs to use for buffering"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/drivers/usb/serial/wishbone-serial.c b/drivers/usb/serial/wishbone-serial.c new file mode 100644 index 00000000000..4fed4a0bd70 --- /dev/null +++ b/drivers/usb/serial/wishbone-serial.c @@ -0,0 +1,94 @@ +/* + * USB Wishbone-Serial adapter driver + * + * Copyright (C) 2013 Wesley W. Terpstra <w.terpstra@gsi.de> + * Copyright (C) 2013 GSI Helmholtz Centre for Heavy Ion Research GmbH + * + * 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. + */ + +#include <linux/kernel.h> +#include <linux/tty.h> +#include <linux/module.h> +#include <linux/usb.h> +#include <linux/usb/serial.h> +#include <linux/uaccess.h> + +#define GSI_VENDOR_OPENCLOSE 0xB0 + +static const struct usb_device_id id_table[] = { + { USB_DEVICE_AND_INTERFACE_INFO(0x1D50, 0x6062, 0xFF, 0xFF, 0xFF) }, + { }, +}; +MODULE_DEVICE_TABLE(usb, id_table); + +/* + * Etherbone must be told that a new stream has begun before data arrives. + * This is necessary to restart the negotiation of Wishbone bus parameters. + * Similarly, when the stream ends, Etherbone must be told so that the cycle + * line can be driven low in the case that userspace failed to do so. + */ +static int usb_gsi_openclose(struct usb_serial_port *port, int value) +{ + struct usb_device *dev = port->serial->dev; + + return usb_control_msg( + dev, + usb_sndctrlpipe(dev, 0), /* Send to EP0OUT */ + GSI_VENDOR_OPENCLOSE, + USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_INTERFACE, + value, /* wValue = device is open(1) or closed(0) */ + port->serial->interface->cur_altsetting->desc.bInterfaceNumber, + NULL, 0, /* There is no data stage */ + 5000); /* Timeout till operation fails */ +} + +static int wishbone_serial_open(struct tty_struct *tty, + struct usb_serial_port *port) +{ + int retval; + + retval = usb_gsi_openclose(port, 1); + if (retval) { + dev_err(&port->serial->dev->dev, + "Could not mark device as open (%d)\n", + retval); + return retval; + } + + retval = usb_serial_generic_open(tty, port); + if (retval) + usb_gsi_openclose(port, 0); + + return retval; +} + +static void wishbone_serial_close(struct usb_serial_port *port) +{ + usb_serial_generic_close(port); + usb_gsi_openclose(port, 0); +} + +static struct usb_serial_driver wishbone_serial_device = { + .driver = { + .owner = THIS_MODULE, + .name = "wishbone_serial", + }, + .id_table = id_table, + .num_ports = 1, + .open = &wishbone_serial_open, + .close = &wishbone_serial_close, +}; + +static struct usb_serial_driver * const serial_drivers[] = { + &wishbone_serial_device, NULL +}; + +module_usb_serial_driver(serial_drivers, id_table); + +MODULE_AUTHOR("Wesley W. Terpstra <w.terpstra@gsi.de>"); +MODULE_DESCRIPTION("USB Wishbone-Serial adapter"); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/serial/xsens_mt.c b/drivers/usb/serial/xsens_mt.c new file mode 100644 index 00000000000..4841fb57400 --- /dev/null +++ b/drivers/usb/serial/xsens_mt.c @@ -0,0 +1,85 @@ +/* + * Xsens MT USB driver + * + * Copyright (C) 2013 Xsens <info@xsens.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + */ + +#include <linux/kernel.h> +#include <linux/tty.h> +#include <linux/module.h> +#include <linux/usb.h> +#include <linux/usb/serial.h> +#include <linux/uaccess.h> + +#define XSENS_VID 0x2639 + +#define MTi_10_IMU_PID 0x0001 +#define MTi_20_VRU_PID 0x0002 +#define MTi_30_AHRS_PID 0x0003 + +#define MTi_100_IMU_PID 0x0011 +#define MTi_200_VRU_PID 0x0012 +#define MTi_300_AHRS_PID 0x0013 + +#define MTi_G_700_GPS_INS_PID 0x0017 + +static const struct usb_device_id id_table[] = { + { USB_DEVICE(XSENS_VID, MTi_10_IMU_PID) }, + { USB_DEVICE(XSENS_VID, MTi_20_VRU_PID) }, + { USB_DEVICE(XSENS_VID, MTi_30_AHRS_PID) }, + + { USB_DEVICE(XSENS_VID, MTi_100_IMU_PID) }, + { USB_DEVICE(XSENS_VID, MTi_200_VRU_PID) }, + { USB_DEVICE(XSENS_VID, MTi_300_AHRS_PID) }, + + { USB_DEVICE(XSENS_VID, MTi_G_700_GPS_INS_PID) }, + { }, +}; +MODULE_DEVICE_TABLE(usb, id_table); + +static int has_required_endpoints(const struct usb_host_interface *interface) +{ + __u8 i; + int has_bulk_in = 0; + int has_bulk_out = 0; + + for (i = 0; i < interface->desc.bNumEndpoints; ++i) { + if (usb_endpoint_is_bulk_in(&interface->endpoint[i].desc)) + has_bulk_in = 1; + else if (usb_endpoint_is_bulk_out(&interface->endpoint[i].desc)) + has_bulk_out = 1; + } + + return has_bulk_in && has_bulk_out; +} + +static int xsens_mt_probe(struct usb_serial *serial, + const struct usb_device_id *id) +{ + if (!has_required_endpoints(serial->interface->cur_altsetting)) + return -ENODEV; + return 0; +} + +static struct usb_serial_driver xsens_mt_device = { + .driver = { + .owner = THIS_MODULE, + .name = "xsens_mt", + }, + .id_table = id_table, + .num_ports = 1, + + .probe = xsens_mt_probe, +}; + +static struct usb_serial_driver * const serial_drivers[] = { + &xsens_mt_device, NULL +}; + +module_usb_serial_driver(serial_drivers, id_table); + +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/serial/zio.c b/drivers/usb/serial/zio.c deleted file mode 100644 index f5796727883..00000000000 --- a/drivers/usb/serial/zio.c +++ /dev/null @@ -1,64 +0,0 @@ -/* - * ZIO Motherboard USB driver - * - * Copyright (C) 2010 Zilogic Systems <code@zilogic.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - */ - -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/tty.h> -#include <linux/module.h> -#include <linux/usb.h> -#include <linux/usb/serial.h> -#include <linux/uaccess.h> - -static const struct usb_device_id id_table[] = { - { USB_DEVICE(0x1CBE, 0x0103) }, - { }, -}; -MODULE_DEVICE_TABLE(usb, id_table); - -static struct usb_driver zio_driver = { - .name = "zio", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, - .no_dynamic_id = 1, -}; - -static struct usb_serial_driver zio_device = { - .driver = { - .owner = THIS_MODULE, - .name = "zio", - }, - .id_table = id_table, - .usb_driver = &zio_driver, - .num_ports = 1, -}; - -static int __init zio_init(void) -{ - int retval; - - retval = usb_serial_register(&zio_device); - if (retval) - return retval; - retval = usb_register(&zio_driver); - if (retval) - usb_serial_deregister(&zio_device); - return retval; -} - -static void __exit zio_exit(void) -{ - usb_deregister(&zio_driver); - usb_serial_deregister(&zio_device); -} - -module_init(zio_init); -module_exit(zio_exit); -MODULE_LICENSE("GPL"); diff --git a/drivers/usb/serial/zte_ev.c b/drivers/usb/serial/zte_ev.c new file mode 100644 index 00000000000..e40ab739c4a --- /dev/null +++ b/drivers/usb/serial/zte_ev.c @@ -0,0 +1,317 @@ +/* + * ZTE_EV USB serial driver + * + * Copyright (C) 2012 Greg Kroah-Hartman <gregkh@linuxfoundation.org> + * Copyright (C) 2012 Linux Foundation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This driver is based on code found in a ZTE_ENV patch that modified + * the usb-serial generic driver. Comments were left in that I think + * show the commands used to talk to the device, but I am not sure. + */ +#include <linux/kernel.h> +#include <linux/tty.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/usb.h> +#include <linux/usb/serial.h> +#include <linux/uaccess.h> + +#define MAX_SETUP_DATA_SIZE 32 + +static void debug_data(struct device *dev, const char *function, int len, + const unsigned char *data, int result) +{ + dev_dbg(dev, "result = %d\n", result); + if (result == len) + dev_dbg(dev, "%s - length = %d, data = %*ph\n", function, + len, len, data); +} + +static int zte_ev_usb_serial_open(struct tty_struct *tty, + struct usb_serial_port *port) +{ + struct usb_device *udev = port->serial->dev; + struct device *dev = &port->dev; + int result = 0; + int len; + unsigned char *buf; + + buf = kmalloc(MAX_SETUP_DATA_SIZE, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + /* send 1st ctl cmd(CTL 21 22 01 00 00 00 00 00) */ + len = 0; + result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + 0x22, 0x21, + 0x0001, 0x0000, NULL, len, + USB_CTRL_GET_TIMEOUT); + dev_dbg(dev, "result = %d\n", result); + + /* send 2st cmd and receive data */ + /* + * 16.0 CTL a1 21 00 00 00 00 07 00 CLASS 25.1.0(5) + * 16.0 DI 00 96 00 00 00 00 08 + */ + len = 0x0007; + result = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + 0x21, 0xa1, + 0x0000, 0x0000, buf, len, + USB_CTRL_GET_TIMEOUT); + debug_data(dev, __func__, len, buf, result); + + /* send 3rd cmd */ + /* + * 16.0 CTL 21 20 00 00 00 00 07 00 CLASS 30.1.0 + * 16.0 DO 80 25 00 00 00 00 08 .%..... 30.2.0 + */ + len = 0x0007; + buf[0] = 0x80; + buf[1] = 0x25; + buf[2] = 0x00; + buf[3] = 0x00; + buf[4] = 0x00; + buf[5] = 0x00; + buf[6] = 0x08; + result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + 0x20, 0x21, + 0x0000, 0x0000, buf, len, + USB_CTRL_GET_TIMEOUT); + debug_data(dev, __func__, len, buf, result); + + /* send 4th cmd */ + /* + * 16.0 CTL 21 22 03 00 00 00 00 00 + */ + len = 0; + result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + 0x22, 0x21, + 0x0003, 0x0000, NULL, len, + USB_CTRL_GET_TIMEOUT); + dev_dbg(dev, "result = %d\n", result); + + /* send 5th cmd */ + /* + * 16.0 CTL a1 21 00 00 00 00 07 00 CLASS 33.1.0 + * 16.0 DI 80 25 00 00 00 00 08 + */ + len = 0x0007; + result = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + 0x21, 0xa1, + 0x0000, 0x0000, buf, len, + USB_CTRL_GET_TIMEOUT); + debug_data(dev, __func__, len, buf, result); + + /* send 6th cmd */ + /* + * 16.0 CTL 21 20 00 00 00 00 07 00 CLASS 34.1.0 + * 16.0 DO 80 25 00 00 00 00 08 + */ + len = 0x0007; + buf[0] = 0x80; + buf[1] = 0x25; + buf[2] = 0x00; + buf[3] = 0x00; + buf[4] = 0x00; + buf[5] = 0x00; + buf[6] = 0x08; + result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + 0x20, 0x21, + 0x0000, 0x0000, buf, len, + USB_CTRL_GET_TIMEOUT); + debug_data(dev, __func__, len, buf, result); + kfree(buf); + + return usb_serial_generic_open(tty, port); +} + +/* + * CTL 21 22 02 00 00 00 00 00 CLASS 338.1.0 + * + * 16.1 DI a1 20 00 00 00 00 02 00 02 00 . ........ 340.1.0 + * 16.0 CTL 21 22 03 00 00 00 00 00 CLASS 341.1.0 + * + * 16.0 CTL a1 21 00 00 00 00 07 00 CLASS 346.1.0(3) + * 16.0 DI 00 08 07 00 00 00 08 ....... 346.2.0 + * + * 16.0 CTL 21 20 00 00 00 00 07 00 CLASS 349.1.0 + * 16.0 DO 00 c2 01 00 00 00 08 ....... 349.2.0 + * + * 16.0 CTL 21 22 03 00 00 00 00 00 CLASS 350.1.0(2) + * + * 16.0 CTL a1 21 00 00 00 00 07 00 CLASS 352.1.0 + * 16.0 DI 00 c2 01 00 00 00 08 ....... 352.2.0 + * + * 16.1 DI a1 20 00 00 00 00 02 00 02 00 . ........ 353.1.0 + * + * 16.0 CTL 21 20 00 00 00 00 07 00 CLASS 354.1.0 + * 16.0 DO 00 c2 01 00 00 00 08 ....... 354.2.0 + * + * 16.0 CTL 21 22 03 00 00 00 00 00 +*/ + +static void zte_ev_usb_serial_close(struct usb_serial_port *port) +{ + struct usb_device *udev = port->serial->dev; + struct device *dev = &port->dev; + int result = 0; + int len; + unsigned char *buf; + + buf = kmalloc(MAX_SETUP_DATA_SIZE, GFP_KERNEL); + if (!buf) + return; + + /* send 1st ctl cmd(CTL 21 22 02 00 00 00 00 00) */ + len = 0; + result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + 0x22, 0x21, + 0x0002, 0x0000, NULL, len, + USB_CTRL_GET_TIMEOUT); + dev_dbg(dev, "result = %d\n", result); + + /* send 2st ctl cmd(CTL 21 22 03 00 00 00 00 00 ) */ + len = 0; + result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + 0x22, 0x21, + 0x0003, 0x0000, NULL, len, + USB_CTRL_GET_TIMEOUT); + dev_dbg(dev, "result = %d\n", result); + + /* send 3st cmd and recieve data */ + /* + * 16.0 CTL a1 21 00 00 00 00 07 00 CLASS 25.1.0(5) + * 16.0 DI 00 08 07 00 00 00 08 + */ + len = 0x0007; + result = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + 0x21, 0xa1, + 0x0000, 0x0000, buf, len, + USB_CTRL_GET_TIMEOUT); + debug_data(dev, __func__, len, buf, result); + + /* send 4th cmd */ + /* + * 16.0 CTL 21 20 00 00 00 00 07 00 CLASS 30.1.0 + * 16.0 DO 00 c2 01 00 00 00 08 .%..... 30.2.0 + */ + len = 0x0007; + buf[0] = 0x00; + buf[1] = 0xc2; + buf[2] = 0x01; + buf[3] = 0x00; + buf[4] = 0x00; + buf[5] = 0x00; + buf[6] = 0x08; + result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + 0x20, 0x21, + 0x0000, 0x0000, buf, len, + USB_CTRL_GET_TIMEOUT); + debug_data(dev, __func__, len, buf, result); + + /* send 5th cmd */ + /* + * 16.0 CTL 21 22 03 00 00 00 00 00 + */ + len = 0; + result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + 0x22, 0x21, + 0x0003, 0x0000, NULL, len, + USB_CTRL_GET_TIMEOUT); + dev_dbg(dev, "result = %d\n", result); + + /* send 6th cmd */ + /* + * 16.0 CTL a1 21 00 00 00 00 07 00 CLASS 33.1.0 + * 16.0 DI 00 c2 01 00 00 00 08 + */ + len = 0x0007; + result = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + 0x21, 0xa1, + 0x0000, 0x0000, buf, len, + USB_CTRL_GET_TIMEOUT); + debug_data(dev, __func__, len, buf, result); + + /* send 7th cmd */ + /* + * 16.0 CTL 21 20 00 00 00 00 07 00 CLASS 354.1.0 + * 16.0 DO 00 c2 01 00 00 00 08 ....... 354.2.0 + */ + len = 0x0007; + buf[0] = 0x00; + buf[1] = 0xc2; + buf[2] = 0x01; + buf[3] = 0x00; + buf[4] = 0x00; + buf[5] = 0x00; + buf[6] = 0x08; + result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + 0x20, 0x21, + 0x0000, 0x0000, buf, len, + USB_CTRL_GET_TIMEOUT); + debug_data(dev, __func__, len, buf, result); + + /* send 8th cmd */ + /* + * 16.0 CTL 21 22 03 00 00 00 00 00 + */ + len = 0; + result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + 0x22, 0x21, + 0x0003, 0x0000, NULL, len, + USB_CTRL_GET_TIMEOUT); + dev_dbg(dev, "result = %d\n", result); + + kfree(buf); + + usb_serial_generic_close(port); +} + +static const struct usb_device_id id_table[] = { + /* AC8710, AC8710T */ + { USB_DEVICE_AND_INTERFACE_INFO(0x19d2, 0xffff, 0xff, 0xff, 0xff) }, + /* AC8700 */ + { USB_DEVICE_AND_INTERFACE_INFO(0x19d2, 0xfffe, 0xff, 0xff, 0xff) }, + /* MG880 */ + { USB_DEVICE(0x19d2, 0xfffd) }, + { USB_DEVICE(0x19d2, 0xfffc) }, + { USB_DEVICE(0x19d2, 0xfffb) }, + /* AC8710_V3 */ + { USB_DEVICE(0x19d2, 0xfff6) }, + { USB_DEVICE(0x19d2, 0xfff7) }, + { USB_DEVICE(0x19d2, 0xfff8) }, + { USB_DEVICE(0x19d2, 0xfff9) }, + { USB_DEVICE(0x19d2, 0xffee) }, + /* AC2716, MC2716 */ + { USB_DEVICE_AND_INTERFACE_INFO(0x19d2, 0xffed, 0xff, 0xff, 0xff) }, + /* AD3812 */ + { USB_DEVICE_AND_INTERFACE_INFO(0x19d2, 0xffeb, 0xff, 0xff, 0xff) }, + { USB_DEVICE(0x19d2, 0xffec) }, + { USB_DEVICE(0x05C6, 0x3197) }, + { USB_DEVICE(0x05C6, 0x6000) }, + { USB_DEVICE(0x05C6, 0x9008) }, + { }, +}; +MODULE_DEVICE_TABLE(usb, id_table); + +static struct usb_serial_driver zio_device = { + .driver = { + .owner = THIS_MODULE, + .name = "zte_ev", + }, + .id_table = id_table, + .num_ports = 1, + .open = zte_ev_usb_serial_open, + .close = zte_ev_usb_serial_close, +}; + +static struct usb_serial_driver * const serial_drivers[] = { + &zio_device, NULL +}; + +module_usb_serial_driver(serial_drivers, id_table); +MODULE_LICENSE("GPL v2"); |
