whiteheat.c revision 5cbded585d129d0226cb48ac4202b253c781be26
1a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 2ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek * USB ConnectTech WhiteHEAT driver 3ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek * 4a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * Copyright (C) 2002 5a5fb297d634ba20bd53a7d6fecd611bbfd342e78Lennert Buytenhek * Connect Tech Inc. 6a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * 7a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * Copyright (C) 1999 - 2001 8a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * Greg Kroah-Hartman (greg@kroah.com) 9a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * 10a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * This program is free software; you can redistribute it and/or modify 11a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * it under the terms of the GNU General Public License as published by 12a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * the Free Software Foundation; either version 2 of the License, or 13a6b7a407865aab9f849dd99a71072b7cd1175116Alexey Dobriyan * (at your option) any later version. 14a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * 15a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * See Documentation/usb/usb-serial.txt for more information on using this driver 163d76e82c9538d8104e578ca460d35f214bfddfd3Lennert Buytenhek * 17a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * (10/09/2002) Stuart MacDonald (stuartm@connecttech.com) 18a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * Upgrade to full working driver 19a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * 20a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * (05/30/2001) gkh 21a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * switched from using spinlock to a semaphore, which fixes lots of problems. 22a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * 235a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo * (04/08/2001) gb 24a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * Identify version on module load. 25a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * 26a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * 2001_Mar_19 gkh 27a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * Fixed MOD_INC and MOD_DEC logic, the ability to open a port more 28a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * than once, and the got the proper usb_device_id table entries so 29a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * the driver works again. 30a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * 3100e8e69270cc8d5b9db98dcb73d26f21c2539010Yogesh Ashok Powar * (11/01/2000) Adam J. Richter 32a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * usb_device_id table support 330863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo * 34eb93992207dadb946a3b5cf4544957dc924a6f58Rusty Russell * (10/05/2000) gkh 350863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo * Fixed bug with urb->dev not being set properly, now that the usb 360863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo * core needs it. 370863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo * 380863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo * (10/03/2000) smd 39a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * firmware is improved to guard against crap sent to device 40a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * firmware now replies CMD_FAILURE on bad things 41ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek * read_callback fix you provided for private info struct 42ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek * command_finished now indicates success or fail 43a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * setup_port struct now packed to avoid gcc padding 44ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek * firmware uses 1 based port numbering, driver now handles that 45ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek * 46ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek * (09/11/2000) gkh 47a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * Removed DEBUG #ifdefs with call to usb_serial_debug_data 48a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * 49a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * (07/19/2000) gkh 50a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * Added module_init and module_exit functions to handle the fact that this 51a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * driver is a loadable module now. 52a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * Fixed bug with port->minor that was found by Al Borchers 53a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * 54a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * (07/04/2000) gkh 55ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek * Added support for port settings. Baud rate can now be changed. Line signals 56ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek * are not transferred to and from the tty layer yet, but things seem to be 57ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek * working well now. 58ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek * 59a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * (05/04/2000) gkh 60a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * First cut at open and close commands. Data can flow through the ports at 61a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * default speeds now. 62a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * 63a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * (03/26/2000) gkh 64a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * Split driver up into device specific pieces. 65a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * 66ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek */ 673aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam 68ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek#include <linux/kernel.h> 69ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek#include <linux/errno.h> 70ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek#include <linux/init.h> 71ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek#include <linux/slab.h> 72ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek#include <linux/tty.h> 73ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek#include <linux/tty_driver.h> 74ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek#include <linux/tty_flip.h> 75ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek#include <linux/module.h> 76ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek#include <linux/spinlock.h> 77a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#include <asm/uaccess.h> 78566875db5058f582ea56da891f9c3cabc01efff5Pradeep Nemavat#include <asm/termbits.h> 79566875db5058f582ea56da891f9c3cabc01efff5Pradeep Nemavat#include <linux/usb.h> 80566875db5058f582ea56da891f9c3cabc01efff5Pradeep Nemavat#include <linux/serial_reg.h> 81566875db5058f582ea56da891f9c3cabc01efff5Pradeep Nemavat#include <linux/serial.h> 82566875db5058f582ea56da891f9c3cabc01efff5Pradeep Nemavat#include <linux/usb/serial.h> 83566875db5058f582ea56da891f9c3cabc01efff5Pradeep Nemavat#include "whiteheat_fw.h" /* firmware for the ConnectTech WhiteHEAT device */ 84566875db5058f582ea56da891f9c3cabc01efff5Pradeep Nemavat#include "whiteheat.h" /* WhiteHEAT specific commands */ 85566875db5058f582ea56da891f9c3cabc01efff5Pradeep Nemavat 86a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int debug; 87a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 88a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#ifndef CMSPAR 89a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define CMSPAR 0 90a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#endif 91a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 92a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 93a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * Version Information 94a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 953aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam#define DRIVER_VERSION "v2.0" 963aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam#define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Stuart MacDonald <stuartm@connecttech.com>" 97a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define DRIVER_DESC "USB ConnectTech WhiteHEAT driver" 98a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 99e600707b021efdc109e7becd467798da339ec26dBrian Cavagnolo#define CONNECT_TECH_VENDOR_ID 0x0710 1008a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo#define CONNECT_TECH_FAKE_WHITE_HEAT_ID 0x0001 101e600707b021efdc109e7becd467798da339ec26dBrian Cavagnolo#define CONNECT_TECH_WHITE_HEAT_ID 0x8001 102e600707b021efdc109e7becd467798da339ec26dBrian Cavagnolo 103a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 1047fb978b7e93b5c4a378eba5767c7513540b56642Yogesh Ashok Powar ID tables for whiteheat are unusual, because we want to different 1057fb978b7e93b5c4a378eba5767c7513540b56642Yogesh Ashok Powar things for different versions of the device. Eventually, this 1067fb978b7e93b5c4a378eba5767c7513540b56642Yogesh Ashok Powar will be doable from a single table. But, for now, we define two 1077fb978b7e93b5c4a378eba5767c7513540b56642Yogesh Ashok Powar separate ID tables, and then a third table that combines them 1087fb978b7e93b5c4a378eba5767c7513540b56642Yogesh Ashok Powar just for the purpose of exporting the autoloading information. 1097fb978b7e93b5c4a378eba5767c7513540b56642Yogesh Ashok Powar*/ 1107fb978b7e93b5c4a378eba5767c7513540b56642Yogesh Ashok Powarstatic struct usb_device_id id_table_std [] = { 1117fb978b7e93b5c4a378eba5767c7513540b56642Yogesh Ashok Powar { USB_DEVICE(CONNECT_TECH_VENDOR_ID, CONNECT_TECH_WHITE_HEAT_ID) }, 1127fb978b7e93b5c4a378eba5767c7513540b56642Yogesh Ashok Powar { } /* Terminating entry */ 1137fb978b7e93b5c4a378eba5767c7513540b56642Yogesh Ashok Powar}; 1147fb978b7e93b5c4a378eba5767c7513540b56642Yogesh Ashok Powar 1157fb978b7e93b5c4a378eba5767c7513540b56642Yogesh Ashok Powarstatic struct usb_device_id id_table_prerenumeration [] = { 11654bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek { USB_DEVICE(CONNECT_TECH_VENDOR_ID, CONNECT_TECH_FAKE_WHITE_HEAT_ID) }, 11754bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek { } /* Terminating entry */ 11854bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek}; 11954bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 12020f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhekstatic struct usb_device_id id_table_combined [] = { 1210d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville { USB_DEVICE(CONNECT_TECH_VENDOR_ID, CONNECT_TECH_WHITE_HEAT_ID) }, 12254bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek { USB_DEVICE(CONNECT_TECH_VENDOR_ID, CONNECT_TECH_FAKE_WHITE_HEAT_ID) }, 12354bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek { } /* Terminating entry */ 12445a390ddd70d8bec0b17dd37bc8f77372c9c3d33Lennert Buytenhek}; 125a74b295edb3e2b39d6c03255b24dca862a843c59Lennert Buytenhek 126a74b295edb3e2b39d6c03255b24dca862a843c59Lennert BuytenhekMODULE_DEVICE_TABLE (usb, id_table_combined); 1270863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo 1280863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolostatic struct usb_driver whiteheat_driver = { 12989a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek .name = "whiteheat", 130952a0e963fb02e50f4afbf502f7d468a8fe2b0faBrian Cavagnolo .probe = usb_serial_probe, 13145a390ddd70d8bec0b17dd37bc8f77372c9c3d33Lennert Buytenhek .disconnect = usb_serial_disconnect, 13245a390ddd70d8bec0b17dd37bc8f77372c9c3d33Lennert Buytenhek .id_table = id_table_combined, 133a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek .no_dynamic_id = 1, 13445eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek}; 135a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 136a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* function prototypes for the Connect Tech WhiteHEAT prerenumeration device */ 13745eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhekstatic int whiteheat_firmware_download (struct usb_serial *serial, const struct usb_device_id *id); 138a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int whiteheat_firmware_attach (struct usb_serial *serial); 139a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 14045eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek/* function prototypes for the Connect Tech WhiteHEAT serial converter */ 141a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int whiteheat_attach (struct usb_serial *serial); 14254bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhekstatic void whiteheat_shutdown (struct usb_serial *serial); 14345eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhekstatic int whiteheat_open (struct usb_serial_port *port, struct file *filp); 144788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhekstatic void whiteheat_close (struct usb_serial_port *port, struct file *filp); 145788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhekstatic int whiteheat_write (struct usb_serial_port *port, const unsigned char *buf, int count); 14653b1b3e1f0feaa57b82d3dc344d887fe3eecc90bFUJITA Tomonoristatic int whiteheat_write_room (struct usb_serial_port *port); 147788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhekstatic int whiteheat_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg); 148a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic void whiteheat_set_termios (struct usb_serial_port *port, struct ktermios * old); 149a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int whiteheat_tiocmget (struct usb_serial_port *port, struct file *file); 150a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int whiteheat_tiocmset (struct usb_serial_port *port, struct file *file, unsigned int set, unsigned int clear); 151a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic void whiteheat_break_ctl (struct usb_serial_port *port, int break_state); 15245eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhekstatic int whiteheat_chars_in_buffer (struct usb_serial_port *port); 153a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic void whiteheat_throttle (struct usb_serial_port *port); 154a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic void whiteheat_unthrottle (struct usb_serial_port *port); 15545eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhekstatic void whiteheat_read_callback (struct urb *urb); 156a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic void whiteheat_write_callback (struct urb *urb); 1578ccbc3b8b0c919e8609560ca56cd777ece8d2c41Kalle Valo 15845eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhekstatic struct usb_serial_driver whiteheat_fake_device = { 15945eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek .driver = { 16045eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek .owner = THIS_MODULE, 161a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek .name = "whiteheatnofirm", 162a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek }, 163ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo .description = "Connect Tech - WhiteHEAT - (prerenumeration)", 164ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo .id_table = id_table_prerenumeration, 165ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo .num_interrupt_in = NUM_DONT_CARE, 166ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo .num_bulk_in = NUM_DONT_CARE, 167ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo .num_bulk_out = NUM_DONT_CARE, 168ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo .num_ports = 1, 169ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo .probe = whiteheat_firmware_download, 1705faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam .attach = whiteheat_firmware_attach, 1715faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam}; 1725faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam 1735faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadamstatic struct usb_serial_driver whiteheat_device = { 1745faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam .driver = { 1755faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam .owner = THIS_MODULE, 1765faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam .name = "whiteheat", 177a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek }, 178a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek .description = "Connect Tech - WhiteHEAT", 179a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek .id_table = id_table_std, 180bf3ca7f752d8f5009c9a83db56035566f3e313deBrian Cavagnolo .num_interrupt_in = NUM_DONT_CARE, 181a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek .num_bulk_in = NUM_DONT_CARE, 18245a390ddd70d8bec0b17dd37bc8f77372c9c3d33Lennert Buytenhek .num_bulk_out = NUM_DONT_CARE, 18345a390ddd70d8bec0b17dd37bc8f77372c9c3d33Lennert Buytenhek .num_ports = 4, 184be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek .attach = whiteheat_attach, 185be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek .shutdown = whiteheat_shutdown, 186be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek .open = whiteheat_open, 187be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek .close = whiteheat_close, 188d1f9e41d1d739cd4393840d35e7554f4a439a4f1Brian Cavagnolo .write = whiteheat_write, 189d1f9e41d1d739cd4393840d35e7554f4a439a4f1Brian Cavagnolo .write_room = whiteheat_write_room, 190a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek .ioctl = whiteheat_ioctl, 191be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek .set_termios = whiteheat_set_termios, 192be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek .break_ctl = whiteheat_break_ctl, 193be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek .tiocmget = whiteheat_tiocmget, 194777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek .tiocmset = whiteheat_tiocmset, 195777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek .chars_in_buffer = whiteheat_chars_in_buffer, 196777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek .throttle = whiteheat_throttle, 1974eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek .unthrottle = whiteheat_unthrottle, 1984eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek .read_bulk_callback = whiteheat_read_callback, 1994eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek .write_bulk_callback = whiteheat_write_callback, 200ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek}; 201ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek 202be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek 2038a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolostruct whiteheat_command_private { 2048a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo spinlock_t lock; 205ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo __u8 port_running; 206ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo __u8 command_finished; 2073aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam wait_queue_head_t wait_command; /* for handling sleeping while waiting for a command to finish */ 2088a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo __u8 result_buffer[64]; 209618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek}; 210618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek 211618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek 2126b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar#define THROTTLED 0x01 213618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek#define ACTUALLY_THROTTLED 0x02 214618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek 215618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhekstatic int urb_pool_size = 8; 216c27a54d3f12383789b57a404649daf98a05cbd72Yogesh Ashok Powar 217c27a54d3f12383789b57a404649daf98a05cbd72Yogesh Ashok Powarstruct whiteheat_urb_wrap { 218a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct list_head list; 219a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct urb *urb; 220a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek}; 22188de754ad59025eba797e7a8375807755577f450Lennert Buytenhek 22288de754ad59025eba797e7a8375807755577f450Lennert Buytenhekstruct whiteheat_private { 22388de754ad59025eba797e7a8375807755577f450Lennert Buytenhek spinlock_t lock; 224f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek __u8 flags; 225ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek __u8 mcr; 226f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek struct list_head rx_urbs_free; 227a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct list_head rx_urbs_submitted; 228a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct list_head rx_urb_q; 229a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct work_struct rx_work; 230a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct usb_serial_port *port; 231a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct list_head tx_urbs_free; 232a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct list_head tx_urbs_submitted; 233a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek}; 2342aa7b01fe4f2d0978115bfd40364f52d86003606Lennert Buytenhek 235a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 236a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* local function prototypes */ 237a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int start_command_port(struct usb_serial *serial); 238a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic void stop_command_port(struct usb_serial *serial); 239a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic void command_port_write_callback(struct urb *urb); 240a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic void command_port_read_callback(struct urb *urb); 241a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 242a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int start_port_read(struct usb_serial_port *port); 243e600707b021efdc109e7becd467798da339ec26dBrian Cavagnolostatic struct whiteheat_urb_wrap *urb_to_wrap(struct urb *urb, struct list_head *head); 244e600707b021efdc109e7becd467798da339ec26dBrian Cavagnolostatic struct list_head *list_first(struct list_head *head); 245a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic void rx_data_softint(struct work_struct *work); 246c46563b714b09d44eec4d1fd8a0f53e79ddaa3aaLennert Buytenhek 24768ce38845c23443b15e374fb7362916c1231278eLennert Buytenhekstatic int firm_send_command(struct usb_serial_port *port, __u8 command, __u8 *data, __u8 datasize); 248a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhekstatic int firm_open(struct usb_serial_port *port); 2490439b1f55646ea944b0d58337f5065b79a1c1be0Lennert Buytenhekstatic int firm_close(struct usb_serial_port *port); 250a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int firm_setup_port(struct usb_serial_port *port); 251a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int firm_set_rts(struct usb_serial_port *port, __u8 onoff); 252a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int firm_set_dtr(struct usb_serial_port *port, __u8 onoff); 253d89173f25228b8795af2d4b53e985cc44c729332Lennert Buytenhekstatic int firm_set_break(struct usb_serial_port *port, __u8 onoff); 254a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int firm_purge(struct usb_serial_port *port, __u8 rxtx); 255a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int firm_get_dtr_rts(struct usb_serial_port *port); 256a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int firm_report_tx_done(struct usb_serial_port *port); 257a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 258a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 259a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define COMMAND_PORT 4 260a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define COMMAND_TIMEOUT (2*HZ) /* 2 second timeout for a command */ 261a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define COMMAND_TIMEOUT_MS 2000 262a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define CLOSING_DELAY (30 * HZ) 263a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2641e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek 2651e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek/***************************************************************************** 26667e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek * Connect Tech's White Heat prerenumeration driver functions 26767e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek *****************************************************************************/ 26867e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek 2690d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville/* steps to download the firmware to the WhiteHEAT device: 2700d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville - hold the reset (by writing to the reset bit of the CPUCS register) 2710d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville - download the VEND_AX.HEX file to the chip using VENDOR_REQUEST-ANCHOR_LOAD 2720863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo - release the reset (by writing to the CPUCS register) 2730863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo - download the WH.HEX file for all addresses greater than 0x1b3f using 2740863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo VENDOR_REQUEST-ANCHOR_EXTERNAL_RAM_LOAD 2750863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo - hold the reset 2760863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo - download the WH.HEX file for all addresses less than 0x1b40 using 277e600707b021efdc109e7becd467798da339ec26dBrian Cavagnolo VENDOR_REQUEST_ANCHOR_LOAD 27899020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo - release the reset 2796b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar - device renumerated itself and comes up as new device id with all 2806b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar firmware download completed. 2816b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar*/ 2826b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powarstatic int whiteheat_firmware_download (struct usb_serial *serial, const struct usb_device_id *id) 28399020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo{ 28499020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo int response; 28599020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo const struct whiteheat_hex_record *record; 28699020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo 28799020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo dbg("%s", __FUNCTION__); 288e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar 289e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar response = ezusb_set_reset (serial, 1); 290e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar 291a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek record = &whiteheat_loader[0]; 292a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek while (record->address != 0xffff) { 293e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam response = ezusb_writememory (serial, record->address, 294e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam (unsigned char *)record->data, record->data_size, 0xa0); 295e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam if (response < 0) { 296a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek err("%s - ezusb_writememory failed for loader (%d %04X %p %d)", 297a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __FUNCTION__, response, record->address, record->data, record->data_size); 298f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek break; 299f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek } 300f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek ++record; 301f57ca9c1af3c1e30a40ad99d75940176d8c3ff3aLennert Buytenhek } 302f57ca9c1af3c1e30a40ad99d75940176d8c3ff3aLennert Buytenhek 303f57ca9c1af3c1e30a40ad99d75940176d8c3ff3aLennert Buytenhek response = ezusb_set_reset (serial, 0); 304c2c2b12a8b6cd23d4abbc086642647c656bf406cLennert Buytenhek 305a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek record = &whiteheat_firmware[0]; 306e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam while (record->address < 0x1b40) { 307e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam ++record; 308e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam } 309e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam while (record->address != 0xffff) { 310e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam response = ezusb_writememory (serial, record->address, 311e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam (unsigned char *)record->data, record->data_size, 0xa3); 312d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam if (response < 0) { 313d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam err("%s - ezusb_writememory failed for first firmware step (%d %04X %p %d)", 314d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam __FUNCTION__, response, record->address, record->data, record->data_size); 315d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam break; 316d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam } 317d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam ++record; 318a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 319a94cc97e14c5750ec2b50b2e4ecdfb0f369ed0f4Lennert Buytenhek 320fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam response = ezusb_set_reset (serial, 1); 321a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 322d0805c1c5758f8fd16c88bf1efa8fb4be4408ce1Brian Cavagnolo record = &whiteheat_firmware[0]; 323d0805c1c5758f8fd16c88bf1efa8fb4be4408ce1Brian Cavagnolo while (record->address < 0x1b40) { 324d0805c1c5758f8fd16c88bf1efa8fb4be4408ce1Brian Cavagnolo response = ezusb_writememory (serial, record->address, 325d0805c1c5758f8fd16c88bf1efa8fb4be4408ce1Brian Cavagnolo (unsigned char *)record->data, record->data_size, 0xa0); 326d0805c1c5758f8fd16c88bf1efa8fb4be4408ce1Brian Cavagnolo if (response < 0) { 327d0805c1c5758f8fd16c88bf1efa8fb4be4408ce1Brian Cavagnolo err("%s - ezusb_writememory failed for second firmware step (%d %04X %p %d)", 328a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek __FUNCTION__, response, record->address, record->data, record->data_size); 329a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek break; 330a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek } 331170335432ad36584a6d24fc1fd903024d221ef55Nishant Sarmukadam ++record; 332d0805c1c5758f8fd16c88bf1efa8fb4be4408ce1Brian Cavagnolo } 333a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek 334a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek response = ezusb_set_reset (serial, 0); 335a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek 336777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek return 0; 337a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 338a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 339a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 340a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int whiteheat_firmware_attach (struct usb_serial *serial) 341a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 342a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* We want this device to fail to have a driver assigned to it */ 343a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return 1; 344a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 345a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 346a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 347a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/***************************************************************************** 348647ca6b01a5289948e970ea7c1f656f9d90b0a27Lennert Buytenhek * Connect Tech's White Heat serial driver functions 349647ca6b01a5289948e970ea7c1f656f9d90b0a27Lennert Buytenhek *****************************************************************************/ 350647ca6b01a5289948e970ea7c1f656f9d90b0a27Lennert Buytenhekstatic int whiteheat_attach (struct usb_serial *serial) 351a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 352a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct usb_serial_port *command_port; 353777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek struct whiteheat_command_private *command_info; 354a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct usb_serial_port *port; 355a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct whiteheat_private *info; 356a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct whiteheat_hw_info *hw_info; 3575dfd3e2c6fb69cf4295ec139107f4ebd3f7fbff0Lennert Buytenhek int pipe; 3585dfd3e2c6fb69cf4295ec139107f4ebd3f7fbff0Lennert Buytenhek int ret; 359a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int alen; 360a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __u8 *command; 361a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __u8 *result; 362a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int i; 363a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int j; 364a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct urb *urb; 365a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int buf_size; 366a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct whiteheat_urb_wrap *wrap; 367140eb5e2c1978622d7cd979d59a1c0586fe3bbdbLennert Buytenhek struct list_head *tmp; 368140eb5e2c1978622d7cd979d59a1c0586fe3bbdbLennert Buytenhek 369140eb5e2c1978622d7cd979d59a1c0586fe3bbdbLennert Buytenhek command_port = serial->port[COMMAND_PORT]; 3704eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek 3714eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek pipe = usb_sndbulkpipe (serial->dev, command_port->bulk_out_endpointAddress); 3724eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek command = kmalloc(2, GFP_KERNEL); 3734eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek if (!command) 3744eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek goto no_command_buffer; 3754eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek command[0] = WHITEHEAT_GET_HW_INFO; 3764eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek command[1] = 0; 3774eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek 3784eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek result = kmalloc(sizeof(*hw_info) + 1, GFP_KERNEL); 3794eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek if (!result) 3804eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek goto no_result_buffer; 3814eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek /* 3824eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek * When the module is reloaded the firmware is still there and 3834eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek * the endpoints are still in the usb core unchanged. This is the 3844eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek * unlinking bug in disguise. Same for the call below. 3854eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek */ 3864eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek usb_clear_halt(serial->dev, pipe); 3874eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek ret = usb_bulk_msg (serial->dev, pipe, command, 2, &alen, COMMAND_TIMEOUT_MS); 3884eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek if (ret) { 389a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek err("%s: Couldn't send command [%d]", serial->type->description, ret); 390a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek goto no_firmware; 39141fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam } else if (alen != 2) { 39241fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam err("%s: Send command incomplete [%d]", serial->type->description, alen); 393a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek goto no_firmware; 394a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 395a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 396a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek pipe = usb_rcvbulkpipe (serial->dev, command_port->bulk_in_endpointAddress); 39742fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek /* See the comment on the usb_clear_halt() above */ 398a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek usb_clear_halt(serial->dev, pipe); 399a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek ret = usb_bulk_msg (serial->dev, pipe, result, sizeof(*hw_info) + 1, &alen, COMMAND_TIMEOUT_MS); 400ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek if (ret) { 401ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek err("%s: Couldn't get results [%d]", serial->type->description, ret); 40241fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam goto no_firmware; 40308b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek } else if (alen != sizeof(*hw_info) + 1) { 404aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek err("%s: Get results incomplete [%d]", serial->type->description, alen); 405a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek goto no_firmware; 406a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } else if (result[0] != command[0]) { 407ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek err("%s: Command failed [%d]", serial->type->description, result[0]); 408ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek goto no_firmware; 409ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek } 410ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek 411ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek hw_info = (struct whiteheat_hw_info *)&result[1]; 412a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 413ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek info("%s: Driver %s: Firmware v%d.%02d", serial->type->description, 414ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek DRIVER_VERSION, hw_info->sw_major_rev, hw_info->sw_minor_rev); 415a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 416ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek for (i = 0; i < serial->num_ports; i++) { 417a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek port = serial->port[i]; 418aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek 419a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek info = kmalloc(sizeof(struct whiteheat_private), GFP_KERNEL); 4203aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam if (info == NULL) { 421197a4e4e1f7ef11458f09b4dd74397baf6758133Yogesh Ashok Powar err("%s: Out of memory for port structures\n", serial->type->description); 422aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek goto no_private; 423aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek } 424fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 425ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek spin_lock_init(&info->lock); 4265faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam info->flags = 0; 427a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek info->mcr = 0; 428b603742f49c3ec922522602e18ac22e8f6835132John W. Linville INIT_WORK(&info->rx_work, rx_data_softint); 429a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek info->port = port; 430b603742f49c3ec922522602e18ac22e8f6835132John W. Linville 431b603742f49c3ec922522602e18ac22e8f6835132John W. Linville INIT_LIST_HEAD(&info->rx_urbs_free); 432a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek INIT_LIST_HEAD(&info->rx_urbs_submitted); 433a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek INIT_LIST_HEAD(&info->rx_urb_q); 434a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek INIT_LIST_HEAD(&info->tx_urbs_free); 435a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek INIT_LIST_HEAD(&info->tx_urbs_submitted); 436b603742f49c3ec922522602e18ac22e8f6835132John W. Linville 437a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek for (j = 0; j < urb_pool_size; j++) { 438a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek urb = usb_alloc_urb(0, GFP_KERNEL); 43942fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek if (!urb) { 440a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek err("No free urbs available"); 441a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek goto no_rx_urb; 442a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 443a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek buf_size = port->read_urb->transfer_buffer_length; 44441fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam urb->transfer_buffer = kmalloc(buf_size, GFP_KERNEL); 44508b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek if (!urb->transfer_buffer) { 446b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek err("Couldn't allocate urb buffer"); 447a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek goto no_rx_buf; 448a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 449a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek wrap = kmalloc(sizeof(*wrap), GFP_KERNEL); 450ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek if (!wrap) { 451ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek err("Couldn't allocate urb wrapper"); 452ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek goto no_rx_wrap; 453ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek } 454a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek usb_fill_bulk_urb(urb, serial->dev, 455ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek usb_rcvbulkpipe(serial->dev, 456ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek port->bulk_in_endpointAddress), 457a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek urb->transfer_buffer, buf_size, 458ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek whiteheat_read_callback, port); 459a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek wrap->urb = urb; 46032060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek list_add(&wrap->list, &info->rx_urbs_free); 461a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 462b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek urb = usb_alloc_urb(0, GFP_KERNEL); 4633f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek if (!urb) { 464fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam err("No free urbs available"); 465ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek goto no_tx_urb; 4665faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam } 4673aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam buf_size = port->write_urb->transfer_buffer_length; 468a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek urb->transfer_buffer = kmalloc(buf_size, GFP_KERNEL); 469a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (!urb->transfer_buffer) { 470a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek err("Couldn't allocate urb buffer"); 471a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek goto no_tx_buf; 472a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 473a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek wrap = kmalloc(sizeof(*wrap), GFP_KERNEL); 474a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (!wrap) { 475a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek err("Couldn't allocate urb wrapper"); 476a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek goto no_tx_wrap; 477a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 478a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek usb_fill_bulk_urb(urb, serial->dev, 479a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek usb_sndbulkpipe(serial->dev, 480a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek port->bulk_out_endpointAddress), 481a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek urb->transfer_buffer, buf_size, 482a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek whiteheat_write_callback, port); 483a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek wrap->urb = urb; 484a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek list_add(&wrap->list, &info->tx_urbs_free); 485a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 486a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 487d1f9e41d1d739cd4393840d35e7554f4a439a4f1Brian Cavagnolo usb_set_serial_port_data(port, info); 488a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 489a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 490a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek command_info = kmalloc(sizeof(struct whiteheat_command_private), GFP_KERNEL); 491a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (command_info == NULL) { 492a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek err("%s: Out of memory for port structures\n", serial->type->description); 493a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek goto no_command_private; 494a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 495a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 496a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek spin_lock_init(&command_info->lock); 49722be40d9c53faa10d03a679160e0854ad115b610Lennert Buytenhek command_info->port_running = 0; 49822be40d9c53faa10d03a679160e0854ad115b610Lennert Buytenhek init_waitqueue_head(&command_info->wait_command); 499a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek usb_set_serial_port_data(command_port, command_info); 500a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek command_port->write_urb->complete = command_port_write_callback; 50199020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo command_port->read_urb->complete = command_port_read_callback; 50299020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo kfree(result); 50399020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo kfree(command); 50499020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo 50599020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo return 0; 50699020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo 50799020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolono_firmware: 50899020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo /* Firmware likely not running */ 50999020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo err("%s: Unable to retrieve firmware version, try replugging\n", serial->type->description); 510a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek err("%s: If the firmware is not running (status led not blinking)\n", serial->type->description); 511a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek err("%s: please contact support@connecttech.com\n", serial->type->description); 512d1f9e41d1d739cd4393840d35e7554f4a439a4f1Brian Cavagnolo kfree(result); 51399020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo return -ENODEV; 514a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 515a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekno_command_private: 516a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek for (i = serial->num_ports - 1; i >= 0; i--) { 517a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek port = serial->port[i]; 518a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek info = usb_get_serial_port_data(port); 51999020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo for (j = urb_pool_size - 1; j >= 0; j--) { 52099020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo tmp = list_first(&info->tx_urbs_free); 52199020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo list_del(tmp); 52299020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); 52399020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo urb = wrap->urb; 524d1f9e41d1d739cd4393840d35e7554f4a439a4f1Brian Cavagnolo kfree(wrap); 525a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekno_tx_wrap: 526a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek kfree(urb->transfer_buffer); 52799020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolono_tx_buf: 52899020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo usb_free_urb(urb); 529a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekno_tx_urb: 530a74b295edb3e2b39d6c03255b24dca862a843c59Lennert Buytenhek tmp = list_first(&info->rx_urbs_free); 531a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek list_del(tmp); 532a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); 533a74b295edb3e2b39d6c03255b24dca862a843c59Lennert Buytenhek urb = wrap->urb; 53499020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo kfree(wrap); 53599020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolono_rx_wrap: 53699020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo kfree(urb->transfer_buffer); 53799020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolono_rx_buf: 53899020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo usb_free_urb(urb); 53999020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolono_rx_urb: 54099020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo ; 54199020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo } 54299020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo kfree(info); 54399020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolono_private: 54499020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo ; 545a74b295edb3e2b39d6c03255b24dca862a843c59Lennert Buytenhek } 546a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek kfree(result); 547a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekno_result_buffer: 54899020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo kfree(command); 54999020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolono_command_buffer: 55099020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo return -ENOMEM; 55199020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo} 55299020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo 55399020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo 55499020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolostatic void whiteheat_shutdown (struct usb_serial *serial) 55599020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo{ 55699020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo struct usb_serial_port *command_port; 55799020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo struct usb_serial_port *port; 55899020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo struct whiteheat_private *info; 55999020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo struct whiteheat_urb_wrap *wrap; 560a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct urb *urb; 561c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek struct list_head *tmp; 5620863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo struct list_head *tmp2; 56322be40d9c53faa10d03a679160e0854ad115b610Lennert Buytenhek int i; 564a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 565a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek dbg("%s", __FUNCTION__); 566a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 567a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* free up our private data for our command port */ 568a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek command_port = serial->port[COMMAND_PORT]; 569a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek kfree (usb_get_serial_port_data(command_port)); 570a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 571a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek for (i = 0; i < serial->num_ports; i++) { 572a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek port = serial->port[i]; 573f57ca9c1af3c1e30a40ad99d75940176d8c3ff3aLennert Buytenhek info = usb_get_serial_port_data(port); 574f57ca9c1af3c1e30a40ad99d75940176d8c3ff3aLennert Buytenhek list_for_each_safe(tmp, tmp2, &info->rx_urbs_free) { 575a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek list_del(tmp); 576a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); 577ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet urb = wrap->urb; 578a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek kfree(wrap); 579a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek kfree(urb->transfer_buffer); 580a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek usb_free_urb(urb); 581a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 582a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek list_for_each_safe(tmp, tmp2, &info->tx_urbs_free) { 583a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek list_del(tmp); 584a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); 585a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek urb = wrap->urb; 586a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek kfree(wrap); 587a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek kfree(urb->transfer_buffer); 588a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek usb_free_urb(urb); 589a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 590a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek kfree(info); 591a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 592a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 593a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return; 594a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 595a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 596a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 597a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int whiteheat_open (struct usb_serial_port *port, struct file *filp) 598a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 599a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int retval = 0; 600a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct ktermios old_term; 601a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 602a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek dbg("%s - port %d", __FUNCTION__, port->number); 603a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 604a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek retval = start_command_port(port->serial); 605a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (retval) 606a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek goto exit; 607a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 608a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (port->tty) 609a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek port->tty->low_latency = 1; 6103d76e82c9538d8104e578ca460d35f214bfddfd3Lennert Buytenhek 611a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* send an open port command */ 612a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek retval = firm_open(port); 613a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (retval) { 614a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek stop_command_port(port->serial); 615a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek goto exit; 616d4b7057052236e81ab0788cc8df306dc02b0e7beLennert Buytenhek } 617a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 618a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek retval = firm_purge(port, WHITEHEAT_PURGE_RX | WHITEHEAT_PURGE_TX); 619a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (retval) { 620a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek firm_close(port); 621a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek stop_command_port(port->serial); 622a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek goto exit; 623a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 624a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 625a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek old_term.c_cflag = ~port->tty->termios->c_cflag; 626a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek old_term.c_iflag = ~port->tty->termios->c_iflag; 627a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek whiteheat_set_termios(port, &old_term); 628a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 629a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* Work around HCD bugs */ 630a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek usb_clear_halt(port->serial->dev, port->read_urb->pipe); 631a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek usb_clear_halt(port->serial->dev, port->write_urb->pipe); 632f57ca9c1af3c1e30a40ad99d75940176d8c3ff3aLennert Buytenhek 633a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* Start reading from the device */ 634a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek retval = start_port_read(port); 635a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (retval) { 636a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek err("%s - failed submitting read urb, error %d", __FUNCTION__, retval); 637a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek firm_close(port); 638a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek stop_command_port(port->serial); 639a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek goto exit; 640a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 641a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 642a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekexit: 643a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek dbg("%s - exit, retval = %d", __FUNCTION__, retval); 644a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return retval; 645a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 646a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 647a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 648a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic void whiteheat_close(struct usb_serial_port *port, struct file * filp) 649a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 650a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct whiteheat_private *info = usb_get_serial_port_data(port); 651a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct whiteheat_urb_wrap *wrap; 652a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct urb *urb; 653a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct list_head *tmp; 654a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct list_head *tmp2; 655a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek unsigned long flags; 656a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 657a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek dbg("%s - port %d", __FUNCTION__, port->number); 658a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 659a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* filp is NULL when called from usb_serial_disconnect */ 660a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (filp && (tty_hung_up_p(filp))) { 661a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return; 662a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 663a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 664a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek port->tty->closing = 1; 665a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 666a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 667a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * Not currently in use; tty_wait_until_sent() calls 668a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * serial_chars_in_buffer() which deadlocks on the second semaphore 669a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * acquisition. This should be fixed at some point. Greg's been 670a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * notified. 671a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if ((filp->f_flags & (O_NDELAY | O_NONBLOCK)) == 0) { 672a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek tty_wait_until_sent(port->tty, CLOSING_DELAY); 673a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 674a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek*/ 675a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 676a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (port->tty->driver->flush_buffer) 677a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek port->tty->driver->flush_buffer(port->tty); 678a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek tty_ldisc_flush(port->tty); 679a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 680a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek firm_report_tx_done(port); 681a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 682a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek firm_close(port); 683a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 684a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* shutdown our bulk reads and writes */ 685a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek spin_lock_irqsave(&info->lock, flags); 686a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek list_for_each_safe(tmp, tmp2, &info->rx_urbs_submitted) { 687a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); 688a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek urb = wrap->urb; 689a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek usb_kill_urb(urb); 690a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek list_move(tmp, &info->rx_urbs_free); 691a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 692a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek list_for_each_safe(tmp, tmp2, &info->rx_urb_q) 693a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek list_move(tmp, &info->rx_urbs_free); 694a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 695a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek list_for_each_safe(tmp, tmp2, &info->tx_urbs_submitted) { 696a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); 697a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek urb = wrap->urb; 698a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek usb_kill_urb(urb); 699a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek list_move(tmp, &info->tx_urbs_free); 700a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 701a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek spin_unlock_irqrestore(&info->lock, flags); 702a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 703a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek stop_command_port(port->serial); 704a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 705a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek port->tty->closing = 0; 706a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 707a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 708a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 709a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int whiteheat_write(struct usb_serial_port *port, const unsigned char *buf, int count) 710a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 711a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct usb_serial *serial = port->serial; 712a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct whiteheat_private *info = usb_get_serial_port_data(port); 713a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct whiteheat_urb_wrap *wrap; 714a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct urb *urb; 715a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int result; 716a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int bytes; 717a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int sent = 0; 718a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek unsigned long flags; 719a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct list_head *tmp; 720c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek 721a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek dbg("%s - port %d", __FUNCTION__, port->number); 722c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek 723d1f9e41d1d739cd4393840d35e7554f4a439a4f1Brian Cavagnolo if (count == 0) { 724c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek dbg("%s - write request of 0 bytes", __FUNCTION__); 725c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek return (0); 726c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek } 727c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek 728d1f9e41d1d739cd4393840d35e7554f4a439a4f1Brian Cavagnolo while (count) { 729a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek spin_lock_irqsave(&info->lock, flags); 730c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek if (list_empty(&info->tx_urbs_free)) { 731c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek spin_unlock_irqrestore(&info->lock, flags); 732c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek break; 733c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek } 734c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek tmp = list_first(&info->tx_urbs_free); 735a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek list_del(tmp); 736c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek spin_unlock_irqrestore(&info->lock, flags); 737a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 738a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); 739c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek urb = wrap->urb; 740a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek bytes = (count > port->bulk_out_size) ? port->bulk_out_size : count; 741a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek memcpy (urb->transfer_buffer, buf + sent, bytes); 742ba30c4a58ceb10e81dbf6bd80aeb6a4db42db8feYogesh Ashok Powar 743a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek usb_serial_debug_data(debug, &port->dev, __FUNCTION__, bytes, urb->transfer_buffer); 744c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek 745a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek urb->dev = serial->dev; 746c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek urb->transfer_buffer_length = bytes; 747a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek result = usb_submit_urb(urb, GFP_ATOMIC); 748a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (result) { 749a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek err("%s - failed submitting write urb, error %d", __FUNCTION__, result); 750c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek sent = result; 751c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek spin_lock_irqsave(&info->lock, flags); 752a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek list_add(tmp, &info->tx_urbs_free); 753a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek spin_unlock_irqrestore(&info->lock, flags); 754a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek break; 75589a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek } else { 756a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek sent += bytes; 75789b872e2e476833cde8aaac658c75817f67e8f81Lennert Buytenhek count -= bytes; 758a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek spin_lock_irqsave(&info->lock, flags); 759eae74e6545d995ab0baa8fb07309f714d9616293Lennert Buytenhek list_add(tmp, &info->tx_urbs_submitted); 760eae74e6545d995ab0baa8fb07309f714d9616293Lennert Buytenhek spin_unlock_irqrestore(&info->lock, flags); 761eae74e6545d995ab0baa8fb07309f714d9616293Lennert Buytenhek } 762eae74e6545d995ab0baa8fb07309f714d9616293Lennert Buytenhek } 7633db1cd5c05f35fb43eb134df6f321de4e63141f2Rusty Russell 764eae74e6545d995ab0baa8fb07309f714d9616293Lennert Buytenhek return sent; 765eae74e6545d995ab0baa8fb07309f714d9616293Lennert Buytenhek} 7663db1cd5c05f35fb43eb134df6f321de4e63141f2Rusty Russell 767a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 768eae74e6545d995ab0baa8fb07309f714d9616293Lennert Buytenhekstatic int whiteheat_write_room(struct usb_serial_port *port) 769eae74e6545d995ab0baa8fb07309f714d9616293Lennert Buytenhek{ 770eae74e6545d995ab0baa8fb07309f714d9616293Lennert Buytenhek struct whiteheat_private *info = usb_get_serial_port_data(port); 771a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct list_head *tmp; 772a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int room = 0; 773a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek unsigned long flags; 774a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 775a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek dbg("%s - port %d", __FUNCTION__, port->number); 776a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 777a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek spin_lock_irqsave(&info->lock, flags); 778a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek list_for_each(tmp, &info->tx_urbs_free) 779a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek room++; 780a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek spin_unlock_irqrestore(&info->lock, flags); 781a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek room *= port->bulk_out_size; 78220f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek 783ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet dbg("%s - returns %d", __FUNCTION__, room); 784a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return (room); 785a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 78620f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek 787a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 78820f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhekstatic int whiteheat_tiocmget (struct usb_serial_port *port, struct file *file) 78920f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek{ 79020f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek struct whiteheat_private *info = usb_get_serial_port_data(port); 79120f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek unsigned int modem_signals = 0; 79220f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek 79320f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek dbg("%s - port %d", __FUNCTION__, port->number); 79420f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek 79520f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek firm_get_dtr_rts(port); 79620f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek if (info->mcr & UART_MCR_DTR) 79720f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek modem_signals |= TIOCM_DTR; 79820f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek if (info->mcr & UART_MCR_RTS) 79920f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek modem_signals |= TIOCM_RTS; 80020f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek 801a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return modem_signals; 80220f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek} 80320f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek 80420f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek 805a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int whiteheat_tiocmset (struct usb_serial_port *port, struct file *file, 806a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek unsigned int set, unsigned int clear) 807ff776cecec92fe7cac4a9ce1919576ad6e737e08Yogesh Ashok Powar{ 808ff776cecec92fe7cac4a9ce1919576ad6e737e08Yogesh Ashok Powar struct whiteheat_private *info = usb_get_serial_port_data(port); 809252486a13a36e2846ff046c18aae67658692ecedNishant Sarmukadam 810e4eefec73ea0a740bfe8736e3ac30dfe92fe392bYogesh Ashok Powar dbg("%s - port %d", __FUNCTION__, port->number); 811e4eefec73ea0a740bfe8736e3ac30dfe92fe392bYogesh Ashok Powar 812a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (set & TIOCM_RTS) 813a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek info->mcr |= UART_MCR_RTS; 814ca00930153c14b323c31b97623ac5c4f7855ed6aLennert Buytenhek if (set & TIOCM_DTR) 815252486a13a36e2846ff046c18aae67658692ecedNishant Sarmukadam info->mcr |= UART_MCR_DTR; 816a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 817a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (clear & TIOCM_RTS) 818ca00930153c14b323c31b97623ac5c4f7855ed6aLennert Buytenhek info->mcr &= ~UART_MCR_RTS; 819ca00930153c14b323c31b97623ac5c4f7855ed6aLennert Buytenhek if (clear & TIOCM_DTR) 820ca00930153c14b323c31b97623ac5c4f7855ed6aLennert Buytenhek info->mcr &= ~UART_MCR_DTR; 821ca00930153c14b323c31b97623ac5c4f7855ed6aLennert Buytenhek 822ca00930153c14b323c31b97623ac5c4f7855ed6aLennert Buytenhek firm_set_dtr(port, info->mcr & UART_MCR_DTR); 823ca00930153c14b323c31b97623ac5c4f7855ed6aLennert Buytenhek firm_set_rts(port, info->mcr & UART_MCR_RTS); 824a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return 0; 825ca00930153c14b323c31b97623ac5c4f7855ed6aLennert Buytenhek} 826a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 827ff776cecec92fe7cac4a9ce1919576ad6e737e08Yogesh Ashok Powar 828ff776cecec92fe7cac4a9ce1919576ad6e737e08Yogesh Ashok Powarstatic int whiteheat_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg) 829ff776cecec92fe7cac4a9ce1919576ad6e737e08Yogesh Ashok Powar{ 830ff776cecec92fe7cac4a9ce1919576ad6e737e08Yogesh Ashok Powar struct serial_struct serstruct; 831ff776cecec92fe7cac4a9ce1919576ad6e737e08Yogesh Ashok Powar void __user *user_arg = (void __user *)arg; 832ff776cecec92fe7cac4a9ce1919576ad6e737e08Yogesh Ashok Powar 833ff776cecec92fe7cac4a9ce1919576ad6e737e08Yogesh Ashok Powar dbg("%s - port %d, cmd 0x%.4x", __FUNCTION__, port->number, cmd); 834ff776cecec92fe7cac4a9ce1919576ad6e737e08Yogesh Ashok Powar 835ff776cecec92fe7cac4a9ce1919576ad6e737e08Yogesh Ashok Powar switch (cmd) { 836ff776cecec92fe7cac4a9ce1919576ad6e737e08Yogesh Ashok Powar case TIOCGSERIAL: 837ff776cecec92fe7cac4a9ce1919576ad6e737e08Yogesh Ashok Powar memset(&serstruct, 0, sizeof(serstruct)); 838ff776cecec92fe7cac4a9ce1919576ad6e737e08Yogesh Ashok Powar serstruct.type = PORT_16654; 839ff776cecec92fe7cac4a9ce1919576ad6e737e08Yogesh Ashok Powar serstruct.line = port->serial->minor; 840ff776cecec92fe7cac4a9ce1919576ad6e737e08Yogesh Ashok Powar serstruct.port = port->number; 841ff776cecec92fe7cac4a9ce1919576ad6e737e08Yogesh Ashok Powar serstruct.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ; 842ff776cecec92fe7cac4a9ce1919576ad6e737e08Yogesh Ashok Powar serstruct.xmit_fifo_size = port->bulk_out_size; 843e4eefec73ea0a740bfe8736e3ac30dfe92fe392bYogesh Ashok Powar serstruct.custom_divisor = 0; 844252486a13a36e2846ff046c18aae67658692ecedNishant Sarmukadam serstruct.baud_base = 460800; 845252486a13a36e2846ff046c18aae67658692ecedNishant Sarmukadam serstruct.close_delay = CLOSING_DELAY; 846252486a13a36e2846ff046c18aae67658692ecedNishant Sarmukadam serstruct.closing_wait = CLOSING_DELAY; 847a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 848ca00930153c14b323c31b97623ac5c4f7855ed6aLennert Buytenhek if (copy_to_user(user_arg, &serstruct, sizeof(serstruct))) 849252486a13a36e2846ff046c18aae67658692ecedNishant Sarmukadam return -EFAULT; 850a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 851a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek break; 852a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 853a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek case TIOCSSERIAL: 854ca00930153c14b323c31b97623ac5c4f7855ed6aLennert Buytenhek if (copy_from_user(&serstruct, user_arg, sizeof(serstruct))) 855ca00930153c14b323c31b97623ac5c4f7855ed6aLennert Buytenhek return -EFAULT; 856a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 857a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* 858a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * For now this is ignored. dip sets the ASYNC_[V]HI flags 859a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * but this isn't used by us at all. Maybe someone somewhere 860a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * will need the custom_divisor setting. 861a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 862252486a13a36e2846ff046c18aae67658692ecedNishant Sarmukadam 863a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek break; 864a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 865ff776cecec92fe7cac4a9ce1919576ad6e737e08Yogesh Ashok Powar default: 866ff776cecec92fe7cac4a9ce1919576ad6e737e08Yogesh Ashok Powar break; 867e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam } 868e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam 869e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam return -ENOIOCTLCMD; 870e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam} 871e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam 872e4eefec73ea0a740bfe8736e3ac30dfe92fe392bYogesh Ashok Powar 873e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadamstatic void whiteheat_set_termios (struct usb_serial_port *port, struct ktermios *old_termios) 874e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam{ 875e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam dbg("%s -port %d", __FUNCTION__, port->number); 876e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam 877e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam if ((!port->tty) || (!port->tty->termios)) { 878e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam dbg("%s - no tty structures", __FUNCTION__); 879e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam goto exit; 880e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam } 881e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam 882e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam /* check that they really want us to change something */ 883e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam if (old_termios) { 884e4eefec73ea0a740bfe8736e3ac30dfe92fe392bYogesh Ashok Powar if ((port->tty->termios->c_cflag == old_termios->c_cflag) && 885e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam (port->tty->termios->c_iflag == old_termios->c_iflag)) { 886e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam dbg("%s - nothing to change...", __FUNCTION__); 887e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam goto exit; 888e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam } 889e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam } 890e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam 891e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam firm_setup_port(port); 892e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam 893e4eefec73ea0a740bfe8736e3ac30dfe92fe392bYogesh Ashok Powarexit: 894e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam return; 895e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam} 896e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam 897e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam 898e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadamstatic void whiteheat_break_ctl(struct usb_serial_port *port, int break_state) { 899e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam firm_set_break(port, break_state); 900e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam} 901e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam 902e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam 903e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadamstatic int whiteheat_chars_in_buffer(struct usb_serial_port *port) 904e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam{ 905e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam struct whiteheat_private *info = usb_get_serial_port_data(port); 906e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam struct list_head *tmp; 907e4eefec73ea0a740bfe8736e3ac30dfe92fe392bYogesh Ashok Powar struct whiteheat_urb_wrap *wrap; 908e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam int chars = 0; 909a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek unsigned long flags; 910a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 91189a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek dbg("%s - port %d", __FUNCTION__, port->number); 9126f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek 91389a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek spin_lock_irqsave(&info->lock, flags); 9146f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek list_for_each(tmp, &info->tx_urbs_submitted) { 9156f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); 9166f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek chars += wrap->urb->transfer_buffer_length; 9176f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek } 9186f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek spin_unlock_irqrestore(&info->lock, flags); 9196f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek 9206f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek dbg ("%s - returns %d", __FUNCTION__, chars); 9216f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek return (chars); 9226f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek} 9236f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek 9246f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek 9256f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhekstatic void whiteheat_throttle (struct usb_serial_port *port) 9266f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek{ 9276f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek struct whiteheat_private *info = usb_get_serial_port_data(port); 9286f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek unsigned long flags; 929ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet 9306f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek dbg("%s - port %d", __FUNCTION__, port->number); 93189a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek 93289a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek spin_lock_irqsave(&info->lock, flags); 93389a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek info->flags |= THROTTLED; 9348e9f33f0ced82a797d285b233e1c956cbd5c7de3Lennert Buytenhek spin_unlock_irqrestore(&info->lock, flags); 93589a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek 9366f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek return; 937d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam} 938d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam 939d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam 940d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadamstatic void whiteheat_unthrottle (struct usb_serial_port *port) 941d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam{ 942d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam struct whiteheat_private *info = usb_get_serial_port_data(port); 943d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam int actually_throttled; 94489a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek unsigned long flags; 9456f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek 94689a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek dbg("%s - port %d", __FUNCTION__, port->number); 9476f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek 9486f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek spin_lock_irqsave(&info->lock, flags); 94989a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek actually_throttled = info->flags & ACTUALLY_THROTTLED; 9506f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek info->flags &= ~(THROTTLED | ACTUALLY_THROTTLED); 9516f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek spin_unlock_irqrestore(&info->lock, flags); 95289a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek 9536f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek if (actually_throttled) 95489a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek rx_data_softint(&info->rx_work); 9556f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek 9566f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek return; 9576f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek} 9586f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek 9596f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek 9606f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek/***************************************************************************** 9616f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek * Connect Tech's White Heat callback routines 9626f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek *****************************************************************************/ 96389a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhekstatic void command_port_write_callback (struct urb *urb) 9640d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville{ 9656f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek dbg("%s", __FUNCTION__); 96689a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek 9676f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek if (urb->status) { 96889a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek dbg ("nonzero urb status: %d", urb->status); 9696f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek return; 9706f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek } 9716f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek} 9726f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek 9736f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek 9746f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhekstatic void command_port_read_callback (struct urb *urb) 9750d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville{ 9766f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek struct usb_serial_port *command_port = (struct usb_serial_port *)urb->context; 97789a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek struct whiteheat_command_private *command_info; 9786f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek unsigned char *data = urb->transfer_buffer; 97989a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek int result; 9808e9f33f0ced82a797d285b233e1c956cbd5c7de3Lennert Buytenhek unsigned long flags; 98189a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek 9826f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek dbg("%s", __FUNCTION__); 9836f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek 9846f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek if (urb->status) { 985777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek dbg("%s - nonzero urb status: %d", __FUNCTION__, urb->status); 986777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek return; 9876f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek } 9886f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek 9896f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek usb_serial_debug_data(debug, &command_port->dev, __FUNCTION__, urb->actual_length, data); 9906f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek 9916f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek command_info = usb_get_serial_port_data(command_port); 9926f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek if (!command_info) { 993854783444bab0024556c0aefdb0a860f2f1da286Lennert Buytenhek dbg ("%s - command_info is NULL, exiting.", __FUNCTION__); 994854783444bab0024556c0aefdb0a860f2f1da286Lennert Buytenhek return; 995854783444bab0024556c0aefdb0a860f2f1da286Lennert Buytenhek } 996854783444bab0024556c0aefdb0a860f2f1da286Lennert Buytenhek spin_lock_irqsave(&command_info->lock, flags); 997854783444bab0024556c0aefdb0a860f2f1da286Lennert Buytenhek 998854783444bab0024556c0aefdb0a860f2f1da286Lennert Buytenhek if (data[0] == WHITEHEAT_CMD_COMPLETE) { 999854783444bab0024556c0aefdb0a860f2f1da286Lennert Buytenhek command_info->command_finished = WHITEHEAT_CMD_COMPLETE; 100059eb21a6504731fc16db4cf9463065dd61093e08Bruno Randolf wake_up_interruptible(&command_info->wait_command); 100159eb21a6504731fc16db4cf9463065dd61093e08Bruno Randolf } else if (data[0] == WHITEHEAT_CMD_FAILURE) { 10026f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek command_info->command_finished = WHITEHEAT_CMD_FAILURE; 100320f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek wake_up_interruptible(&command_info->wait_command); 100420f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek } else if (data[0] == WHITEHEAT_EVENT) { 1005d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam /* These are unsolicited reports from the firmware, hence no waiting command to wakeup */ 1006d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam dbg("%s - event received", __FUNCTION__); 1007d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam } else if (data[0] == WHITEHEAT_GET_DTR_RTS) { 1008d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam memcpy(command_info->result_buffer, &data[1], urb->actual_length - 1); 1009d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam command_info->command_finished = WHITEHEAT_CMD_COMPLETE; 10106f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek wake_up_interruptible(&command_info->wait_command); 10116f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek } else { 10126f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek dbg("%s - bad reply from firmware", __FUNCTION__); 101389a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek } 101489a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek 101589a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek /* Continue trying to always read */ 101689a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek command_port->read_urb->dev = command_port->serial->dev; 101789a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek result = usb_submit_urb(command_port->read_urb, GFP_ATOMIC); 10186f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek spin_unlock_irqrestore(&command_info->lock, flags); 10196f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek if (result) 10206f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek dbg("%s - failed resubmitting read urb, error %d", __FUNCTION__, result); 102189a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek} 1022a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 102389a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek 1024a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic void whiteheat_read_callback(struct urb *urb) 1025a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 1026a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct usb_serial_port *port = (struct usb_serial_port *)urb->context; 1027a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct whiteheat_urb_wrap *wrap; 102845eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek unsigned char *data = urb->transfer_buffer; 1029a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct whiteheat_private *info = usb_get_serial_port_data(port); 1030a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1031a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek dbg("%s - port %d", __FUNCTION__, port->number); 1032a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1033a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek spin_lock(&info->lock); 1034a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek wrap = urb_to_wrap(urb, &info->rx_urbs_submitted); 1035a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (!wrap) { 1036a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek spin_unlock(&info->lock); 1037a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek err("%s - Not my urb!", __FUNCTION__); 1038ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet return; 1039a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 104089a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek list_del(&wrap->list); 104189a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek spin_unlock(&info->lock); 104289a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek 104389a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek if (urb->status) { 104489a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status); 104589a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek spin_lock(&info->lock); 104654bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek list_add(&wrap->list, &info->rx_urbs_free); 104789a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek spin_unlock(&info->lock); 1048d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam return; 1049d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam } 1050d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam 1051d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data); 1052d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam 105354bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek spin_lock(&info->lock); 105489a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek list_add_tail(&wrap->list, &info->rx_urb_q); 105554bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek if (info->flags & THROTTLED) { 105689a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek info->flags |= ACTUALLY_THROTTLED; 105754bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek spin_unlock(&info->lock); 105854bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek return; 105989a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek } 106054bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek spin_unlock(&info->lock); 106154bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 106289a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek schedule_work(&info->rx_work); 106354bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek} 106489a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek 106554bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 106654bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhekstatic void whiteheat_write_callback(struct urb *urb) 106754bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek{ 106854bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek struct usb_serial_port *port = (struct usb_serial_port *)urb->context; 106954bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek struct whiteheat_private *info = usb_get_serial_port_data(port); 107054bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek struct whiteheat_urb_wrap *wrap; 107154bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 107254bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek dbg("%s - port %d", __FUNCTION__, port->number); 107389a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek 10740d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville spin_lock(&info->lock); 107554bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek wrap = urb_to_wrap(urb, &info->tx_urbs_submitted); 107689a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek if (!wrap) { 107754bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek spin_unlock(&info->lock); 107854bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek err("%s - Not my urb!", __FUNCTION__); 107989a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek return; 108054bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek } 108154bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek list_move(&wrap->list, &info->tx_urbs_free); 108254bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek spin_unlock(&info->lock); 108354bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 108454bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek if (urb->status) { 108554bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status); 108654bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek return; 108754bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek } 10880d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville 108989a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek usb_serial_port_softint(port); 109089a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek} 109154bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 109289a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek 109354bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek/***************************************************************************** 109489a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek * Connect Tech's White Heat firmware interface 109554bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek *****************************************************************************/ 109689a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhekstatic int firm_send_command (struct usb_serial_port *port, __u8 command, __u8 *data, __u8 datasize) 109754bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek{ 109889a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek struct usb_serial_port *command_port; 109954bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek struct whiteheat_command_private *command_info; 110054bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek struct whiteheat_private *info; 1101854783444bab0024556c0aefdb0a860f2f1da286Lennert Buytenhek __u8 *transfer_buffer; 1102854783444bab0024556c0aefdb0a860f2f1da286Lennert Buytenhek int retval = 0; 1103854783444bab0024556c0aefdb0a860f2f1da286Lennert Buytenhek unsigned long flags; 1104854783444bab0024556c0aefdb0a860f2f1da286Lennert Buytenhek 1105854783444bab0024556c0aefdb0a860f2f1da286Lennert Buytenhek dbg("%s - command %d", __FUNCTION__, command); 1106854783444bab0024556c0aefdb0a860f2f1da286Lennert Buytenhek 1107854783444bab0024556c0aefdb0a860f2f1da286Lennert Buytenhek command_port = port->serial->port[COMMAND_PORT]; 110859eb21a6504731fc16db4cf9463065dd61093e08Bruno Randolf command_info = usb_get_serial_port_data(command_port); 110959eb21a6504731fc16db4cf9463065dd61093e08Bruno Randolf spin_lock_irqsave(&command_info->lock, flags); 111054bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek command_info->command_finished = FALSE; 111120f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek 1112d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam transfer_buffer = (__u8 *)command_port->write_urb->transfer_buffer; 1113d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam transfer_buffer[0] = command; 1114d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam memcpy (&transfer_buffer[1], data, datasize); 111520f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek command_port->write_urb->transfer_buffer_length = datasize + 1; 111654bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek command_port->write_urb->dev = port->serial->dev; 111754bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek retval = usb_submit_urb (command_port->write_urb, GFP_KERNEL); 111854bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek if (retval) { 111989a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek dbg("%s - submit urb failed", __FUNCTION__); 112089a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek goto exit; 112189a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek } 112289a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek spin_unlock_irqrestore(&command_info->lock, flags); 112389a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek 112454bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek /* wait for the command to complete */ 112554bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek wait_event_interruptible_timeout(command_info->wait_command, 112654bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek (command_info->command_finished != FALSE), COMMAND_TIMEOUT); 1127a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1128a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek spin_lock_irqsave(&command_info->lock, flags); 1129a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1130a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (command_info->command_finished == FALSE) { 1131a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek dbg("%s - command timed out.", __FUNCTION__); 1132a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek retval = -ETIMEDOUT; 1133a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek goto exit; 1134a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 1135a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1136a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (command_info->command_finished == WHITEHEAT_CMD_FAILURE) { 113745eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek dbg("%s - command failed.", __FUNCTION__); 113845eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek retval = -EIO; 113945eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek goto exit; 1140a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 114154bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 1142a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (command_info->command_finished == WHITEHEAT_CMD_COMPLETE) { 114345eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek dbg("%s - command completed.", __FUNCTION__); 114445eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek switch (command) { 11455db5584441c2dceb75696fb31a44ac7b9b925359Joe Perches case WHITEHEAT_GET_DTR_RTS: 1146a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek info = usb_get_serial_port_data(port); 1147a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek memcpy(&info->mcr, command_info->result_buffer, sizeof(struct whiteheat_dr_info)); 114845eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek break; 1149a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 1150b9ede5f1dc03f96949dcaa8f8b3483766c047260Shan Wei } 1151788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek 11525db5584441c2dceb75696fb31a44ac7b9b925359Joe Perchesexit: 115345eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek spin_unlock_irqrestore(&command_info->lock, flags); 1154a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return retval; 1155a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 1156a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1157a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 115854bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhekstatic int firm_open(struct usb_serial_port *port) { 115954bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek struct whiteheat_simple open_command; 1160a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 116154bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek open_command.port = port->number - port->serial->minor + 1; 116254bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek return firm_send_command(port, WHITEHEAT_OPEN, (__u8 *)&open_command, sizeof(open_command)); 116354bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek} 116454bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 1165a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 116654bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhekstatic int firm_close(struct usb_serial_port *port) { 116754bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek struct whiteheat_simple close_command; 116854bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 116954bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek close_command.port = port->number - port->serial->minor + 1; 1170a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return firm_send_command(port, WHITEHEAT_CLOSE, (__u8 *)&close_command, sizeof(close_command)); 117154bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek} 1172a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1173a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1174a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int firm_setup_port(struct usb_serial_port *port) { 1175a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct whiteheat_port_settings port_settings; 1176a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek unsigned int cflag = port->tty->termios->c_cflag; 1177a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1178a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek port_settings.port = port->number + 1; 1179a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1180a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* get the byte size */ 1181a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek switch (cflag & CSIZE) { 1182a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek case CS5: port_settings.bits = 5; break; 1183a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek case CS6: port_settings.bits = 6; break; 118445eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek case CS7: port_settings.bits = 7; break; 1185a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek default: 1186788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek case CS8: port_settings.bits = 8; break; 1187a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 118854bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek dbg("%s - data bits = %d", __FUNCTION__, port_settings.bits); 1189a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1190a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* determine the parity */ 1191a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (cflag & PARENB) 1192a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (cflag & CMSPAR) 1193a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (cflag & PARODD) 1194788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek port_settings.parity = WHITEHEAT_PAR_MARK; 1195788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek else 1196a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek port_settings.parity = WHITEHEAT_PAR_SPACE; 119754bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek else 119854bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek if (cflag & PARODD) 119954bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek port_settings.parity = WHITEHEAT_PAR_ODD; 120054bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek else 1201788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek port_settings.parity = WHITEHEAT_PAR_EVEN; 120253b1b3e1f0feaa57b82d3dc344d887fe3eecc90bFUJITA Tomonori else 120354bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek port_settings.parity = WHITEHEAT_PAR_NONE; 120454bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek dbg("%s - parity = %c", __FUNCTION__, port_settings.parity); 120554bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 1206a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* figure out the stop bits requested */ 1207a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (cflag & CSTOPB) 1208a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek port_settings.stop = 2; 1209a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek else 1210a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek port_settings.stop = 1; 1211a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek dbg("%s - stop bits = %d", __FUNCTION__, port_settings.stop); 1212a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1213a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* figure out the flow control settings */ 1214a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (cflag & CRTSCTS) 1215a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek port_settings.hflow = (WHITEHEAT_HFLOW_CTS | WHITEHEAT_HFLOW_RTS); 1216a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek else 1217a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek port_settings.hflow = WHITEHEAT_HFLOW_NONE; 1218a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek dbg("%s - hardware flow control = %s %s %s %s", __FUNCTION__, 1219a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek (port_settings.hflow & WHITEHEAT_HFLOW_CTS) ? "CTS" : "", 122073b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo (port_settings.hflow & WHITEHEAT_HFLOW_RTS) ? "RTS" : "", 122173b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo (port_settings.hflow & WHITEHEAT_HFLOW_DSR) ? "DSR" : "", 122273b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo (port_settings.hflow & WHITEHEAT_HFLOW_DTR) ? "DTR" : ""); 1223a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1224788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek /* determine software flow control */ 1225788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek if (I_IXOFF(port->tty)) 122653b1b3e1f0feaa57b82d3dc344d887fe3eecc90bFUJITA Tomonori port_settings.sflow = WHITEHEAT_SFLOW_RXTX; 1227788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek else 122853b1b3e1f0feaa57b82d3dc344d887fe3eecc90bFUJITA Tomonori port_settings.sflow = WHITEHEAT_SFLOW_NONE; 1229788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek dbg("%s - software flow control = %c", __FUNCTION__, port_settings.sflow); 1230788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek 1231788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek port_settings.xon = START_CHAR(port->tty); 1232a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek port_settings.xoff = STOP_CHAR(port->tty); 1233a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek dbg("%s - XON = %2x, XOFF = %2x", __FUNCTION__, port_settings.xon, port_settings.xoff); 1234a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1235788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek /* get the baud rate wanted */ 1236788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek port_settings.baud = tty_get_baud_rate(port->tty); 1237a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek dbg("%s - baud rate = %d", __FUNCTION__, port_settings.baud); 1238a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 123954bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek /* handle any settings that aren't specified in the tty structure */ 124045eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek port_settings.lloop = 0; 124145eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek 1242a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* now send the message to the device */ 1243a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return firm_send_command(port, WHITEHEAT_SETUP_PORT, (__u8 *)&port_settings, sizeof(port_settings)); 1244a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 1245a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1246a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1247a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int firm_set_rts(struct usb_serial_port *port, __u8 onoff) { 1248a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct whiteheat_set_rdb rts_command; 1249a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1250a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rts_command.port = port->number - port->serial->minor + 1; 1251a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rts_command.state = onoff; 1252a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return firm_send_command(port, WHITEHEAT_SET_RTS, (__u8 *)&rts_command, sizeof(rts_command)); 1253a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 12542e42e4747ea72943c21551d8a206b51a9893b1e0Joe Perches 1255a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1256a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int firm_set_dtr(struct usb_serial_port *port, __u8 onoff) { 12573779752d764b86077375510b1fd13d8fb2c7c3a5Lennert Buytenhek struct whiteheat_set_rdb dtr_command; 12583779752d764b86077375510b1fd13d8fb2c7c3a5Lennert Buytenhek 1259a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek dtr_command.port = port->number - port->serial->minor + 1; 12603779752d764b86077375510b1fd13d8fb2c7c3a5Lennert Buytenhek dtr_command.state = onoff; 12613779752d764b86077375510b1fd13d8fb2c7c3a5Lennert Buytenhek return firm_send_command(port, WHITEHEAT_SET_RTS, (__u8 *)&dtr_command, sizeof(dtr_command)); 1262a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 1263d89173f25228b8795af2d4b53e985cc44c729332Lennert Buytenhek 1264a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1265a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int firm_set_break(struct usb_serial_port *port, __u8 onoff) { 1266a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct whiteheat_set_rdb break_command; 1267a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1268a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek break_command.port = port->number - port->serial->minor + 1; 1269a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek break_command.state = onoff; 1270a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return firm_send_command(port, WHITEHEAT_SET_RTS, (__u8 *)&break_command, sizeof(break_command)); 1271a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 12723779752d764b86077375510b1fd13d8fb2c7c3a5Lennert Buytenhek 1273a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1274a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int firm_purge(struct usb_serial_port *port, __u8 rxtx) { 1275d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam struct whiteheat_purge purge_command; 1276d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam 1277d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam purge_command.port = port->number - port->serial->minor + 1; 1278d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam purge_command.what = rxtx; 1279d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam return firm_send_command(port, WHITEHEAT_PURGE, (__u8 *)&purge_command, sizeof(purge_command)); 1280d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam} 1281d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam 1282d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam 1283d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadamstatic int firm_get_dtr_rts(struct usb_serial_port *port) { 1284d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam struct whiteheat_simple get_dr_command; 1285d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam 1286d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam get_dr_command.port = port->number - port->serial->minor + 1; 1287d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam return firm_send_command(port, WHITEHEAT_GET_DTR_RTS, (__u8 *)&get_dr_command, sizeof(get_dr_command)); 1288d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam} 1289d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam 1290a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1291a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int firm_report_tx_done(struct usb_serial_port *port) { 1292a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct whiteheat_simple close_command; 1293d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam 1294a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek close_command.port = port->number - port->serial->minor + 1; 1295a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return firm_send_command(port, WHITEHEAT_REPORT_TX_DONE, (__u8 *)&close_command, sizeof(close_command)); 1296a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 1297a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 129845eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek 1299a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/***************************************************************************** 130054bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek * Connect Tech's White Heat utility functions 130154bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek *****************************************************************************/ 1302a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int start_command_port(struct usb_serial *serial) 1303d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam{ 130420f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek struct usb_serial_port *command_port; 1305a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct whiteheat_command_private *command_info; 1306788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek unsigned long flags; 1307d25f9f1357139bbdc79bc960ea84909a7c22ec2bLennert Buytenhek int retval = 0; 1308d25f9f1357139bbdc79bc960ea84909a7c22ec2bLennert Buytenhek 130954bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek command_port = serial->port[COMMAND_PORT]; 131054bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek command_info = usb_get_serial_port_data(command_port); 131154bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek spin_lock_irqsave(&command_info->lock, flags); 13120d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville if (!command_info->port_running) { 13130d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville /* Work around HCD bugs */ 131454bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek usb_clear_halt(serial->dev, command_port->read_urb->pipe); 131554bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 131654bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek command_port->read_urb->dev = serial->dev; 1317788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek retval = usb_submit_urb(command_port->read_urb, GFP_KERNEL); 1318788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek if (retval) { 1319788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek err("%s - failed submitting read urb, error %d", __FUNCTION__, retval); 132053b1b3e1f0feaa57b82d3dc344d887fe3eecc90bFUJITA Tomonori goto exit; 1321788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek } 132253b1b3e1f0feaa57b82d3dc344d887fe3eecc90bFUJITA Tomonori } 1323a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek command_info->port_running++; 132454bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 132554bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhekexit: 132654bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek spin_unlock_irqrestore(&command_info->lock, flags); 132754bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek return retval; 132845eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek} 1329a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1330d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam 1331a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic void stop_command_port(struct usb_serial *serial) 1332a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 1333c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek struct usb_serial_port *command_port; 1334c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek struct whiteheat_command_private *command_info; 1335c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek unsigned long flags; 1336a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 133754bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek command_port = serial->port[COMMAND_PORT]; 13383779752d764b86077375510b1fd13d8fb2c7c3a5Lennert Buytenhek command_info = usb_get_serial_port_data(command_port); 1339a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek spin_lock_irqsave(&command_info->lock, flags); 1340d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam command_info->port_running--; 1341d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam if (!command_info->port_running) 1342d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam usb_kill_urb(command_port->read_urb); 1343d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam spin_unlock_irqrestore(&command_info->lock, flags); 1344d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam} 1345d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam 1346d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam 1347d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadamstatic int start_port_read(struct usb_serial_port *port) 1348d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam{ 1349d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam struct whiteheat_private *info = usb_get_serial_port_data(port); 135023677ce3172fcb93522a1df077d21019e73ee1e3Joe Perches struct whiteheat_urb_wrap *wrap; 1351d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam struct urb *urb; 1352d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam int retval = 0; 1353d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam unsigned long flags; 1354d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam struct list_head *tmp; 1355d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam struct list_head *tmp2; 1356d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam 1357d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam spin_lock_irqsave(&info->lock, flags); 1358d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam 1359d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam list_for_each_safe(tmp, tmp2, &info->rx_urbs_free) { 1360d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam list_del(tmp); 1361d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); 1362d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam urb = wrap->urb; 1363d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam urb->dev = port->serial->dev; 1364d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam retval = usb_submit_urb(urb, GFP_KERNEL); 1365d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam if (retval) { 1366d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam list_add(tmp, &info->rx_urbs_free); 1367d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam list_for_each_safe(tmp, tmp2, &info->rx_urbs_submitted) { 1368d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); 1369d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam urb = wrap->urb; 1370d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam usb_kill_urb(urb); 1371d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam list_move(tmp, &info->rx_urbs_free); 1372d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam } 1373d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam break; 1374d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam } 1375d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam list_add(tmp, &info->rx_urbs_submitted); 1376d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam } 1377d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam 1378d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam spin_unlock_irqrestore(&info->lock, flags); 1379d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam 1380f1d58c2521eb160178b2151d6326d8dc5d7c8560Johannes Berg return retval; 1381f1d58c2521eb160178b2151d6326d8dc5d7c8560Johannes Berg} 1382a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1383a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1384a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic struct whiteheat_urb_wrap *urb_to_wrap(struct urb* urb, struct list_head *head) 1385a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 1386a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct whiteheat_urb_wrap *wrap; 1387a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct list_head *tmp; 1388a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1389a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek list_for_each(tmp, head) { 1390a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); 1391a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (wrap->urb == urb) 1392a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return wrap; 1393a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 1394a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1395a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return NULL; 1396a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 1397a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1398a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1399a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic struct list_head *list_first(struct list_head *head) 1400e0493a8dd6351a114b53790dda6bd855ae73a85cLennert Buytenhek{ 1401e0493a8dd6351a114b53790dda6bd855ae73a85cLennert Buytenhek return head->next; 1402e0493a8dd6351a114b53790dda6bd855ae73a85cLennert Buytenhek} 1403e0493a8dd6351a114b53790dda6bd855ae73a85cLennert Buytenhek 1404e0493a8dd6351a114b53790dda6bd855ae73a85cLennert Buytenhek 1405e0493a8dd6351a114b53790dda6bd855ae73a85cLennert Buytenhekstatic void rx_data_softint(struct work_struct *work) 1406a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 1407a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct whiteheat_private *info = 1408a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek container_of(work, struct whiteheat_private, rx_work); 1409a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct usb_serial_port *port = info->port; 1410a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct tty_struct *tty = port->tty; 1411a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct whiteheat_urb_wrap *wrap; 1412a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct urb *urb; 1413d89173f25228b8795af2d4b53e985cc44c729332Lennert Buytenhek unsigned long flags; 141445eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek struct list_head *tmp; 14158a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo struct list_head *tmp2; 1416a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int result; 1417a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int sent = 0; 1418a1fe24b0fd8bf16b4e551ae3fb785bfc574b9ffbBrian Cavagnolo 1419ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet spin_lock_irqsave(&info->lock, flags); 1420a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (info->flags & THROTTLED) { 1421a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek spin_unlock_irqrestore(&info->lock, flags); 1422a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return; 1423a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 1424a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1425a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek list_for_each_safe(tmp, tmp2, &info->rx_urb_q) { 1426a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek list_del(tmp); 1427a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek spin_unlock_irqrestore(&info->lock, flags); 1428a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1429a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); 14308ccbc3b8b0c919e8609560ca56cd777ece8d2c41Kalle Valo urb = wrap->urb; 143145eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek 143245eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek if (tty && urb->actual_length) { 1433a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int len = tty_buffer_request_room(tty, urb->actual_length); 1434a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* This stuff can go away now I suspect */ 1435a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (unlikely(len < urb->actual_length)) { 143645eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek spin_lock_irqsave(&info->lock, flags); 143745eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek list_add(tmp, &info->rx_urb_q); 14385db5584441c2dceb75696fb31a44ac7b9b925359Joe Perches spin_unlock_irqrestore(&info->lock, flags); 1439a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek tty_flip_buffer_push(tty); 1440a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek schedule_work(&info->rx_work); 144145eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek return; 1442a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 1443b9ede5f1dc03f96949dcaa8f8b3483766c047260Shan Wei tty_insert_flip_string(tty, urb->transfer_buffer, len); 144445eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek sent += len; 14455db5584441c2dceb75696fb31a44ac7b9b925359Joe Perches } 144645eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek 1447a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek urb->dev = port->serial->dev; 1448a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek result = usb_submit_urb(urb, GFP_ATOMIC); 1449a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (result) { 1450a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result); 1451a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek spin_lock_irqsave(&info->lock, flags); 1452a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek list_add(tmp, &info->rx_urbs_free); 1453a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek continue; 145445eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek } 1455a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1456a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek spin_lock_irqsave(&info->lock, flags); 1457a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek list_add(tmp, &info->rx_urbs_submitted); 145845eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek } 145945eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek spin_unlock_irqrestore(&info->lock, flags); 1460a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1461a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (sent) 1462a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek tty_flip_buffer_push(tty); 1463a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 1464a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1465a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1466a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/***************************************************************************** 1467a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * Connect Tech's White Heat module functions 1468a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek *****************************************************************************/ 1469a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int __init whiteheat_init (void) 1470a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 1471a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int retval; 1472a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek retval = usb_serial_register(&whiteheat_fake_device); 1473a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (retval) 14747e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek goto failed_fake_register; 1475a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek retval = usb_serial_register(&whiteheat_device); 14767e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek if (retval) 14777e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek goto failed_device_register; 14787e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek retval = usb_register(&whiteheat_driver); 1479e600707b021efdc109e7becd467798da339ec26dBrian Cavagnolo if (retval) 14807e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek goto failed_usb_register; 14817e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek info(DRIVER_DESC " " DRIVER_VERSION); 14827e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek return 0; 14837e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhekfailed_usb_register: 14847e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek usb_serial_deregister(&whiteheat_device); 14857e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhekfailed_device_register: 1486a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek usb_serial_deregister(&whiteheat_fake_device); 14877e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhekfailed_fake_register: 14887e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek return retval; 1489a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 14907e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek 1491a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 14927e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhekstatic void __exit whiteheat_exit (void) 1493a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 14947e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek usb_deregister (&whiteheat_driver); 1495a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek usb_serial_deregister (&whiteheat_fake_device); 1496a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek usb_serial_deregister (&whiteheat_device); 14977e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek} 1498a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1499a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1500c96c31e499b70964cfc88744046c998bb710e4b8Joe Perchesmodule_init(whiteheat_init); 1501c96c31e499b70964cfc88744046c998bb710e4b8Joe Perchesmodule_exit(whiteheat_exit); 1502c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches 1503c96c31e499b70964cfc88744046c998bb710e4b8Joe PerchesMODULE_AUTHOR( DRIVER_AUTHOR ); 1504c96c31e499b70964cfc88744046c998bb710e4b8Joe PerchesMODULE_DESCRIPTION( DRIVER_DESC ); 1505c96c31e499b70964cfc88744046c998bb710e4b8Joe PerchesMODULE_LICENSE("GPL"); 15067e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek 1507a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekmodule_param(urb_pool_size, int, 0); 1508a66098daacee2f354dab311b58011e7076aa248cLennert BuytenhekMODULE_PARM_DESC(urb_pool_size, "Number of urbs to use for buffering"); 1509618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek 151088de754ad59025eba797e7a8375807755577f450Lennert Buytenhekmodule_param(debug, bool, S_IRUGO | S_IWUSR); 1511618952a7b19b796fce98364fb26551cbe3e16a75Lennert BuytenhekMODULE_PARM_DESC(debug, "Debug enabled or not"); 151262abd3cfb2f1a0ab1963ac4c4087c477da6b1f2aLennert Buytenhek