visor.c revision e33fe4d86f91127f6f7d931ff59ed6cbda06e72b
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * USB HandSpring Visor, Palm m50x, and Sony Clie driver 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (supports all of the Palm OS USB devices) 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 1999 - 2004 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Greg Kroah-Hartman (greg@kroah.com) 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 84d0dce3e0b794942407391c52f8dd2760802f391Greg Kroah-Hartman * This program is free software; you can redistribute it and/or 94d0dce3e0b794942407391c52f8dd2760802f391Greg Kroah-Hartman * modify it under the terms of the GNU General Public License version 104d0dce3e0b794942407391c52f8dd2760802f391Greg Kroah-Hartman * 2 as published by the Free Software Foundation. 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * See Documentation/usb/usb-serial.txt for more information on using this driver 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h> 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h> 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty.h> 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty_driver.h> 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty_flip.h> 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/moduleparam.h> 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/spinlock.h> 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h> 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/usb.h> 28a969888ce91673c7f4b86520d851a6f0d5a5fa7dGreg Kroah-Hartman#include <linux/usb/serial.h> 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "visor.h" 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Version Information 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>" 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_DESC "USB HandSpring Visor / Palm OS driver" 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* function prototypes for a handspring visor */ 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int visor_open (struct usb_serial_port *port, struct file *filp); 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void visor_close (struct usb_serial_port *port, struct file *filp); 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int visor_write (struct usb_serial_port *port, const unsigned char *buf, int count); 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int visor_write_room (struct usb_serial_port *port); 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int visor_chars_in_buffer (struct usb_serial_port *port); 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void visor_throttle (struct usb_serial_port *port); 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void visor_unthrottle (struct usb_serial_port *port); 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int visor_probe (struct usb_serial *serial, const struct usb_device_id *id); 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int visor_calc_num_ports(struct usb_serial *serial); 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void visor_shutdown (struct usb_serial *serial); 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int visor_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg); 497d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void visor_write_bulk_callback (struct urb *urb); 507d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void visor_read_bulk_callback (struct urb *urb); 517d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void visor_read_int_callback (struct urb *urb); 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int clie_3_5_startup (struct usb_serial *serial); 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int treo_attach (struct usb_serial *serial); 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int clie_5_attach (struct usb_serial *serial); 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int palm_os_3_probe (struct usb_serial *serial, const struct usb_device_id *id); 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int palm_os_4_probe (struct usb_serial *serial, const struct usb_device_id *id); 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Parameters that may be passed into the module. */ 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int debug; 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic __u16 vendor; 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic __u16 product; 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_device_id id_table [] = { 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_VISOR_ID), 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .driver_info = (kernel_ulong_t)&palm_os_3_probe }, 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_TREO_ID), 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .driver_info = (kernel_ulong_t)&palm_os_4_probe }, 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_TREO600_ID), 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .driver_info = (kernel_ulong_t)&palm_os_4_probe }, 7004d52461c6ecfc5b72e688b0eb2ead7b555eca25Hendrik Schweppe { USB_DEVICE(GSPDA_VENDOR_ID, GSPDA_XPLORE_M68_ID), 7104d52461c6ecfc5b72e688b0eb2ead7b555eca25Hendrik Schweppe .driver_info = (kernel_ulong_t)&palm_os_4_probe }, 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(PALM_VENDOR_ID, PALM_M500_ID), 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .driver_info = (kernel_ulong_t)&palm_os_4_probe }, 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(PALM_VENDOR_ID, PALM_M505_ID), 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .driver_info = (kernel_ulong_t)&palm_os_4_probe }, 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(PALM_VENDOR_ID, PALM_M515_ID), 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .driver_info = (kernel_ulong_t)&palm_os_4_probe }, 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(PALM_VENDOR_ID, PALM_I705_ID), 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .driver_info = (kernel_ulong_t)&palm_os_4_probe }, 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(PALM_VENDOR_ID, PALM_M100_ID), 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .driver_info = (kernel_ulong_t)&palm_os_4_probe }, 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(PALM_VENDOR_ID, PALM_M125_ID), 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .driver_info = (kernel_ulong_t)&palm_os_4_probe }, 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(PALM_VENDOR_ID, PALM_M130_ID), 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .driver_info = (kernel_ulong_t)&palm_os_4_probe }, 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_T_ID), 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .driver_info = (kernel_ulong_t)&palm_os_4_probe }, 88ac21e9ff08db3d6fac41d356c77fcb531c2e03e1Greg Kroah-Hartman { USB_DEVICE(PALM_VENDOR_ID, PALM_TREO_650), 89ac21e9ff08db3d6fac41d356c77fcb531c2e03e1Greg Kroah-Hartman .driver_info = (kernel_ulong_t)&palm_os_4_probe }, 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_Z_ID), 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .driver_info = (kernel_ulong_t)&palm_os_4_probe }, 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE_ID), 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .driver_info = (kernel_ulong_t)&palm_os_4_probe }, 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID), 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .driver_info = (kernel_ulong_t)&palm_os_4_probe }, 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_S360_ID), 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .driver_info = (kernel_ulong_t)&palm_os_4_probe }, 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_1_ID), 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .driver_info = (kernel_ulong_t)&palm_os_4_probe }, 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_NX60_ID), 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .driver_info = (kernel_ulong_t)&palm_os_4_probe }, 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_NZ90V_ID), 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .driver_info = (kernel_ulong_t)&palm_os_4_probe }, 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_TJ25_ID), 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .driver_info = (kernel_ulong_t)&palm_os_4_probe }, 106c8ba84a0c682068a55a5892d6e12e3f196fd792cMaximilian Attems { USB_DEVICE(ACER_VENDOR_ID, ACER_S10_ID), 107c8ba84a0c682068a55a5892d6e12e3f196fd792cMaximilian Attems .driver_info = (kernel_ulong_t)&palm_os_4_probe }, 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_SCH_I330_ID), 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .driver_info = (kernel_ulong_t)&palm_os_4_probe }, 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_SPH_I500_ID), 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .driver_info = (kernel_ulong_t)&palm_os_4_probe }, 112115c1ce524869309e4bddcfc3dd112ac76b92defLarry Battraw { USB_DEVICE(TAPWAVE_VENDOR_ID, TAPWAVE_ZODIAC_ID), 113115c1ce524869309e4bddcfc3dd112ac76b92defLarry Battraw .driver_info = (kernel_ulong_t)&palm_os_4_probe }, 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(GARMIN_VENDOR_ID, GARMIN_IQUE_3600_ID), 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .driver_info = (kernel_ulong_t)&palm_os_4_probe }, 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(ACEECA_VENDOR_ID, ACEECA_MEZ1000_ID), 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .driver_info = (kernel_ulong_t)&palm_os_4_probe }, 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_7135_ID), 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .driver_info = (kernel_ulong_t)&palm_os_4_probe }, 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(FOSSIL_VENDOR_ID, FOSSIL_ABACUS_ID), 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .driver_info = (kernel_ulong_t)&palm_os_4_probe }, 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { }, /* optional parameter entry */ 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { } /* Terminating entry */ 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_device_id clie_id_5_table [] = { 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_UX50_ID), 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .driver_info = (kernel_ulong_t)&palm_os_4_probe }, 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { }, /* optional parameter entry */ 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { } /* Terminating entry */ 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_device_id clie_id_3_5_table [] = { 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_3_5_ID) }, 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { } /* Terminating entry */ 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_device_id id_table_combined [] = { 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_VISOR_ID) }, 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_TREO_ID) }, 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_TREO600_ID) }, 14204d52461c6ecfc5b72e688b0eb2ead7b555eca25Hendrik Schweppe { USB_DEVICE(GSPDA_VENDOR_ID, GSPDA_XPLORE_M68_ID) }, 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(PALM_VENDOR_ID, PALM_M500_ID) }, 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(PALM_VENDOR_ID, PALM_M505_ID) }, 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(PALM_VENDOR_ID, PALM_M515_ID) }, 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(PALM_VENDOR_ID, PALM_I705_ID) }, 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(PALM_VENDOR_ID, PALM_M100_ID) }, 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(PALM_VENDOR_ID, PALM_M125_ID) }, 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(PALM_VENDOR_ID, PALM_M130_ID) }, 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_T_ID) }, 151ac21e9ff08db3d6fac41d356c77fcb531c2e03e1Greg Kroah-Hartman { USB_DEVICE(PALM_VENDOR_ID, PALM_TREO_650) }, 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_Z_ID) }, 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE_ID) }, 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_3_5_ID) }, 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID) }, 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_S360_ID) }, 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_1_ID) }, 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_NX60_ID) }, 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_NZ90V_ID) }, 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_UX50_ID) }, 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_TJ25_ID) }, 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_SCH_I330_ID) }, 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_SPH_I500_ID) }, 164115c1ce524869309e4bddcfc3dd112ac76b92defLarry Battraw { USB_DEVICE(TAPWAVE_VENDOR_ID, TAPWAVE_ZODIAC_ID) }, 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(GARMIN_VENDOR_ID, GARMIN_IQUE_3600_ID) }, 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(ACEECA_VENDOR_ID, ACEECA_MEZ1000_ID) }, 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_7135_ID) }, 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(FOSSIL_VENDOR_ID, FOSSIL_ABACUS_ID) }, 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { }, /* optional parameter entry */ 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { } /* Terminating entry */ 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DEVICE_TABLE (usb, id_table_combined); 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_driver visor_driver = { 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .name = "visor", 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .probe = usb_serial_probe, 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .disconnect = usb_serial_disconnect, 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .id_table = id_table_combined, 180ba9dc657af86d05d2971633e57d1f6f94ed60472Greg Kroah-Hartman .no_dynamic_id = 1, 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* All of the device info needed for the Handspring Visor, and Palm 4.0 devices */ 184ea65370d025f5005649e5cb37c4d025e92c6fc38Greg Kroah-Hartmanstatic struct usb_serial_driver handspring_device = { 18518fcac353fdc7cd072b0d24c8667042e675a4c11Greg Kroah-Hartman .driver = { 18618fcac353fdc7cd072b0d24c8667042e675a4c11Greg Kroah-Hartman .owner = THIS_MODULE, 187269bda1c123c7caf88e1deb2264f9086f0344192Greg Kroah-Hartman .name = "visor", 18818fcac353fdc7cd072b0d24c8667042e675a4c11Greg Kroah-Hartman }, 189269bda1c123c7caf88e1deb2264f9086f0344192Greg Kroah-Hartman .description = "Handspring Visor / Palm OS", 190d9b1b787736852f462dbf277b3ca708cbbf693aeJohannes Hölzl .usb_driver = &visor_driver, 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .id_table = id_table, 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .num_interrupt_in = NUM_DONT_CARE, 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .num_bulk_in = 2, 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .num_bulk_out = 2, 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .num_ports = 2, 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .open = visor_open, 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .close = visor_close, 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .throttle = visor_throttle, 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .unthrottle = visor_unthrottle, 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .attach = treo_attach, 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .probe = visor_probe, 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .calc_num_ports = visor_calc_num_ports, 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .shutdown = visor_shutdown, 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .ioctl = visor_ioctl, 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .write = visor_write, 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .write_room = visor_write_room, 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .chars_in_buffer = visor_chars_in_buffer, 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .write_bulk_callback = visor_write_bulk_callback, 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .read_bulk_callback = visor_read_bulk_callback, 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .read_int_callback = visor_read_int_callback, 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* All of the device info needed for the Clie UX50, TH55 Palm 5.0 devices */ 214ea65370d025f5005649e5cb37c4d025e92c6fc38Greg Kroah-Hartmanstatic struct usb_serial_driver clie_5_device = { 21518fcac353fdc7cd072b0d24c8667042e675a4c11Greg Kroah-Hartman .driver = { 21618fcac353fdc7cd072b0d24c8667042e675a4c11Greg Kroah-Hartman .owner = THIS_MODULE, 217269bda1c123c7caf88e1deb2264f9086f0344192Greg Kroah-Hartman .name = "clie_5", 21818fcac353fdc7cd072b0d24c8667042e675a4c11Greg Kroah-Hartman }, 219269bda1c123c7caf88e1deb2264f9086f0344192Greg Kroah-Hartman .description = "Sony Clie 5.0", 220d9b1b787736852f462dbf277b3ca708cbbf693aeJohannes Hölzl .usb_driver = &visor_driver, 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .id_table = clie_id_5_table, 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .num_interrupt_in = NUM_DONT_CARE, 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .num_bulk_in = 2, 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .num_bulk_out = 2, 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .num_ports = 2, 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .open = visor_open, 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .close = visor_close, 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .throttle = visor_throttle, 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .unthrottle = visor_unthrottle, 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .attach = clie_5_attach, 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .probe = visor_probe, 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .calc_num_ports = visor_calc_num_ports, 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .shutdown = visor_shutdown, 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .ioctl = visor_ioctl, 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .write = visor_write, 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .write_room = visor_write_room, 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .chars_in_buffer = visor_chars_in_buffer, 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .write_bulk_callback = visor_write_bulk_callback, 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .read_bulk_callback = visor_read_bulk_callback, 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .read_int_callback = visor_read_int_callback, 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* device info for the Sony Clie OS version 3.5 */ 244ea65370d025f5005649e5cb37c4d025e92c6fc38Greg Kroah-Hartmanstatic struct usb_serial_driver clie_3_5_device = { 24518fcac353fdc7cd072b0d24c8667042e675a4c11Greg Kroah-Hartman .driver = { 24618fcac353fdc7cd072b0d24c8667042e675a4c11Greg Kroah-Hartman .owner = THIS_MODULE, 247269bda1c123c7caf88e1deb2264f9086f0344192Greg Kroah-Hartman .name = "clie_3.5", 24818fcac353fdc7cd072b0d24c8667042e675a4c11Greg Kroah-Hartman }, 249269bda1c123c7caf88e1deb2264f9086f0344192Greg Kroah-Hartman .description = "Sony Clie 3.5", 250d9b1b787736852f462dbf277b3ca708cbbf693aeJohannes Hölzl .usb_driver = &visor_driver, 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .id_table = clie_id_3_5_table, 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .num_interrupt_in = 0, 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .num_bulk_in = 1, 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .num_bulk_out = 1, 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .num_ports = 1, 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .open = visor_open, 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .close = visor_close, 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .throttle = visor_throttle, 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .unthrottle = visor_unthrottle, 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .attach = clie_3_5_startup, 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .ioctl = visor_ioctl, 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .write = visor_write, 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .write_room = visor_write_room, 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .chars_in_buffer = visor_chars_in_buffer, 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .write_bulk_callback = visor_write_bulk_callback, 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .read_bulk_callback = visor_read_bulk_callback, 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct visor_private { 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spinlock_t lock; 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int bytes_in; 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int bytes_out; 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int outstanding_urbs; 274b308e74d9c708ee2a9af14fbe235e0a41216f4edOliver Neukum unsigned char throttled; 275b308e74d9c708ee2a9af14fbe235e0a41216f4edOliver Neukum unsigned char actually_throttled; 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* number of outstanding urbs to prevent userspace DoS from happening */ 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define URB_UPPER_LIMIT 42 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int stats; 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/****************************************************************************** 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Handspring Visor specific driver functions 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ******************************************************************************/ 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int visor_open (struct usb_serial_port *port, struct file *filp) 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_serial *serial = port->serial; 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct visor_private *priv = usb_get_serial_port_data(port); 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int result = 0; 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s - port %d", __FUNCTION__, port->number); 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!port->read_urb) { 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* this is needed for some brain dead Sony devices */ 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_err(&port->dev, "Device lied about number of ports, please use a lower one.\n"); 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&priv->lock, flags); 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->bytes_in = 0; 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->bytes_out = 0; 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->throttled = 0; 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&priv->lock, flags); 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Force low_latency on so that our tty_push actually forces the data 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * through, otherwise it is scheduled, and with high data rates (like 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * with OHCI) data can get lost. 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (port->tty) 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->tty->low_latency = 1; 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Start reading from the device */ 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_fill_bulk_urb (port->read_urb, serial->dev, 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_rcvbulkpipe (serial->dev, 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->bulk_in_endpointAddress), 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->read_urb->transfer_buffer, 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->read_urb->transfer_buffer_length, 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds visor_read_bulk_callback, port); 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = usb_submit_urb(port->read_urb, GFP_KERNEL); 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) { 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_err(&port->dev, "%s - failed submitting read urb, error %d\n", 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FUNCTION__, result); 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (port->interrupt_in_urb) { 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s - adding interrupt input for treo", __FUNCTION__); 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_err(&port->dev, "%s - failed submitting interrupt urb, error %d\n", 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FUNCTION__, result); 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsexit: 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return result; 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void visor_close (struct usb_serial_port *port, struct file * filp) 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct visor_private *priv = usb_get_serial_port_data(port); 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char *transfer_buffer; 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s - port %d", __FUNCTION__, port->number); 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* shutdown our urbs */ 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_kill_urb(port->read_urb); 350bcb54a54033ff9359cf64e4283e4f4b92bf9132fMariusz Kozlowski usb_kill_urb(port->interrupt_in_urb); 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 352e33fe4d86f91127f6f7d931ff59ed6cbda06e72bOliver Neukum mutex_lock(&port->serial->disc_mutex); 353e33fe4d86f91127f6f7d931ff59ed6cbda06e72bOliver Neukum if (!port->serial->disconnected) { 354e33fe4d86f91127f6f7d931ff59ed6cbda06e72bOliver Neukum /* Try to send shutdown message, unless the device is gone */ 355e33fe4d86f91127f6f7d931ff59ed6cbda06e72bOliver Neukum transfer_buffer = kmalloc (0x12, GFP_KERNEL); 356e33fe4d86f91127f6f7d931ff59ed6cbda06e72bOliver Neukum if (transfer_buffer) { 357e33fe4d86f91127f6f7d931ff59ed6cbda06e72bOliver Neukum usb_control_msg (port->serial->dev, 358e33fe4d86f91127f6f7d931ff59ed6cbda06e72bOliver Neukum usb_rcvctrlpipe(port->serial->dev, 0), 359e33fe4d86f91127f6f7d931ff59ed6cbda06e72bOliver Neukum VISOR_CLOSE_NOTIFICATION, 0xc2, 360e33fe4d86f91127f6f7d931ff59ed6cbda06e72bOliver Neukum 0x0000, 0x0000, 361e33fe4d86f91127f6f7d931ff59ed6cbda06e72bOliver Neukum transfer_buffer, 0x12, 300); 362e33fe4d86f91127f6f7d931ff59ed6cbda06e72bOliver Neukum kfree (transfer_buffer); 363e33fe4d86f91127f6f7d931ff59ed6cbda06e72bOliver Neukum } 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 365e33fe4d86f91127f6f7d931ff59ed6cbda06e72bOliver Neukum mutex_lock(&port->serial->disc_mutex); 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (stats) 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_info(&port->dev, "Bytes In = %d Bytes Out = %d\n", 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->bytes_in, priv->bytes_out); 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int visor_write (struct usb_serial_port *port, const unsigned char *buf, int count) 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct visor_private *priv = usb_get_serial_port_data(port); 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_serial *serial = port->serial; 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct urb *urb; 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char *buffer; 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int status; 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s - port %d", __FUNCTION__, port->number); 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&priv->lock, flags); 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (priv->outstanding_urbs > URB_UPPER_LIMIT) { 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&priv->lock, flags); 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s - write limit hit\n", __FUNCTION__); 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 390b80349b17c6e1236a24616f71e59ed31279de25aOliver Neukum priv->outstanding_urbs++; 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&priv->lock, flags); 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buffer = kmalloc (count, GFP_ATOMIC); 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!buffer) { 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_err(&port->dev, "out of memory\n"); 396b80349b17c6e1236a24616f71e59ed31279de25aOliver Neukum count = -ENOMEM; 397b80349b17c6e1236a24616f71e59ed31279de25aOliver Neukum goto error_no_buffer; 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds urb = usb_alloc_urb(0, GFP_ATOMIC); 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!urb) { 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_err(&port->dev, "no more free urbs\n"); 403b80349b17c6e1236a24616f71e59ed31279de25aOliver Neukum count = -ENOMEM; 404b80349b17c6e1236a24616f71e59ed31279de25aOliver Neukum goto error_no_urb; 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy (buffer, buf, count); 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count, buffer); 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_fill_bulk_urb (urb, serial->dev, 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_sndbulkpipe (serial->dev, 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->bulk_out_endpointAddress), 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buffer, count, 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds visor_write_bulk_callback, port); 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* send it down the pipe */ 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = usb_submit_urb(urb, GFP_ATOMIC); 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status) { 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_err(&port->dev, "%s - usb_submit_urb(write bulk) failed with status = %d\n", 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FUNCTION__, status); 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count = status; 423b80349b17c6e1236a24616f71e59ed31279de25aOliver Neukum goto error; 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&priv->lock, flags); 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->bytes_out += count; 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&priv->lock, flags); 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* we are done with this urb, so let the host driver 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * really free it when it is finished with it */ 432b80349b17c6e1236a24616f71e59ed31279de25aOliver Neukum usb_free_urb(urb); 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return count; 435b80349b17c6e1236a24616f71e59ed31279de25aOliver Neukumerror: 436b80349b17c6e1236a24616f71e59ed31279de25aOliver Neukum usb_free_urb(urb); 437b80349b17c6e1236a24616f71e59ed31279de25aOliver Neukumerror_no_urb: 438b80349b17c6e1236a24616f71e59ed31279de25aOliver Neukum kfree(buffer); 439b80349b17c6e1236a24616f71e59ed31279de25aOliver Neukumerror_no_buffer: 440b80349b17c6e1236a24616f71e59ed31279de25aOliver Neukum spin_lock_irqsave(&priv->lock, flags); 441b80349b17c6e1236a24616f71e59ed31279de25aOliver Neukum --priv->outstanding_urbs; 442b80349b17c6e1236a24616f71e59ed31279de25aOliver Neukum spin_unlock_irqrestore(&priv->lock, flags); 443b80349b17c6e1236a24616f71e59ed31279de25aOliver Neukum return count; 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int visor_write_room (struct usb_serial_port *port) 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 449bd97c4f035b47c1a3ae5cc5ceccdda028b25e9d5Pete Zaitcev struct visor_private *priv = usb_get_serial_port_data(port); 450bd97c4f035b47c1a3ae5cc5ceccdda028b25e9d5Pete Zaitcev unsigned long flags; 451bd97c4f035b47c1a3ae5cc5ceccdda028b25e9d5Pete Zaitcev 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s - port %d", __FUNCTION__, port->number); 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We really can take anything the user throws at us 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * but let's pick a nice big number to tell the tty 457bd97c4f035b47c1a3ae5cc5ceccdda028b25e9d5Pete Zaitcev * layer that we have lots of free space, unless we don't. 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 459bd97c4f035b47c1a3ae5cc5ceccdda028b25e9d5Pete Zaitcev 460bd97c4f035b47c1a3ae5cc5ceccdda028b25e9d5Pete Zaitcev spin_lock_irqsave(&priv->lock, flags); 461bd97c4f035b47c1a3ae5cc5ceccdda028b25e9d5Pete Zaitcev if (priv->outstanding_urbs > URB_UPPER_LIMIT * 2 / 3) { 462bd97c4f035b47c1a3ae5cc5ceccdda028b25e9d5Pete Zaitcev spin_unlock_irqrestore(&priv->lock, flags); 463bd97c4f035b47c1a3ae5cc5ceccdda028b25e9d5Pete Zaitcev dbg("%s - write limit hit\n", __FUNCTION__); 464bd97c4f035b47c1a3ae5cc5ceccdda028b25e9d5Pete Zaitcev return 0; 465bd97c4f035b47c1a3ae5cc5ceccdda028b25e9d5Pete Zaitcev } 466bd97c4f035b47c1a3ae5cc5ceccdda028b25e9d5Pete Zaitcev spin_unlock_irqrestore(&priv->lock, flags); 467bd97c4f035b47c1a3ae5cc5ceccdda028b25e9d5Pete Zaitcev 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 2048; 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int visor_chars_in_buffer (struct usb_serial_port *port) 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s - port %d", __FUNCTION__, port->number); 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We can't really account for how much data we 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * have sent out, but hasn't made it through to the 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * device, so just tell the tty layer that everything 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * is flushed. 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4867d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void visor_write_bulk_callback (struct urb *urb) 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_serial_port *port = (struct usb_serial_port *)urb->context; 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct visor_private *priv = usb_get_serial_port_data(port); 49038e8c910ff7a1aafe2923f085df0f74a60f9de3cGreg Kroah-Hartman int status = urb->status; 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* free up the transfer buffer, as usb_free_urb() does not do this */ 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree (urb->transfer_buffer); 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s - port %d", __FUNCTION__, port->number); 49738e8c910ff7a1aafe2923f085df0f74a60f9de3cGreg Kroah-Hartman 49838e8c910ff7a1aafe2923f085df0f74a60f9de3cGreg Kroah-Hartman if (status) 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s - nonzero write bulk status received: %d", 50038e8c910ff7a1aafe2923f085df0f74a60f9de3cGreg Kroah-Hartman __FUNCTION__, status); 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&priv->lock, flags); 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds --priv->outstanding_urbs; 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&priv->lock, flags); 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 506cf2c7481d2ff7f0c266de873b2fe93883e9782f9Pete Zaitcev usb_serial_port_softint(port); 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5107d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void visor_read_bulk_callback (struct urb *urb) 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_serial_port *port = (struct usb_serial_port *)urb->context; 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct visor_private *priv = usb_get_serial_port_data(port); 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char *data = urb->transfer_buffer; 51538e8c910ff7a1aafe2923f085df0f74a60f9de3cGreg Kroah-Hartman int status = urb->status; 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct tty_struct *tty; 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int result; 518b308e74d9c708ee2a9af14fbe235e0a41216f4edOliver Neukum int available_room; 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s - port %d", __FUNCTION__, port->number); 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 52238e8c910ff7a1aafe2923f085df0f74a60f9de3cGreg Kroah-Hartman if (status) { 52338e8c910ff7a1aafe2923f085df0f74a60f9de3cGreg Kroah-Hartman dbg("%s - nonzero read bulk status received: %d", 52438e8c910ff7a1aafe2923f085df0f74a60f9de3cGreg Kroah-Hartman __FUNCTION__, status); 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data); 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty = port->tty; 5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tty && urb->actual_length) { 532b308e74d9c708ee2a9af14fbe235e0a41216f4edOliver Neukum available_room = tty_buffer_request_room(tty, urb->actual_length); 533b308e74d9c708ee2a9af14fbe235e0a41216f4edOliver Neukum if (available_room) { 534b308e74d9c708ee2a9af14fbe235e0a41216f4edOliver Neukum tty_insert_flip_string(tty, data, available_room); 535b308e74d9c708ee2a9af14fbe235e0a41216f4edOliver Neukum tty_flip_buffer_push(tty); 536b308e74d9c708ee2a9af14fbe235e0a41216f4edOliver Neukum } 537b308e74d9c708ee2a9af14fbe235e0a41216f4edOliver Neukum spin_lock(&priv->lock); 538b308e74d9c708ee2a9af14fbe235e0a41216f4edOliver Neukum priv->bytes_in += available_room; 539b308e74d9c708ee2a9af14fbe235e0a41216f4edOliver Neukum 540b308e74d9c708ee2a9af14fbe235e0a41216f4edOliver Neukum } else { 541b308e74d9c708ee2a9af14fbe235e0a41216f4edOliver Neukum spin_lock(&priv->lock); 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Continue trying to always read if we should */ 545b308e74d9c708ee2a9af14fbe235e0a41216f4edOliver Neukum if (!priv->throttled) { 5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_fill_bulk_urb (port->read_urb, port->serial->dev, 5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_rcvbulkpipe(port->serial->dev, 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->bulk_in_endpointAddress), 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->read_urb->transfer_buffer, 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->read_urb->transfer_buffer_length, 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds visor_read_bulk_callback, port); 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = usb_submit_urb(port->read_urb, GFP_ATOMIC); 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_err(&port->dev, "%s - failed resubmitting read urb, error %d\n", __FUNCTION__, result); 555b308e74d9c708ee2a9af14fbe235e0a41216f4edOliver Neukum } else { 556b308e74d9c708ee2a9af14fbe235e0a41216f4edOliver Neukum priv->actually_throttled = 1; 5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 558b308e74d9c708ee2a9af14fbe235e0a41216f4edOliver Neukum spin_unlock(&priv->lock); 5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5617d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void visor_read_int_callback (struct urb *urb) 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_serial_port *port = (struct usb_serial_port *)urb->context; 56438e8c910ff7a1aafe2923f085df0f74a60f9de3cGreg Kroah-Hartman int status = urb->status; 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int result; 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 56738e8c910ff7a1aafe2923f085df0f74a60f9de3cGreg Kroah-Hartman switch (status) { 5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0: 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* success */ 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case -ECONNRESET: 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case -ENOENT: 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case -ESHUTDOWN: 5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* this urb is terminated, clean up */ 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s - urb shutting down with status: %d", 57638e8c910ff7a1aafe2923f085df0f74a60f9de3cGreg Kroah-Hartman __FUNCTION__, status); 5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s - nonzero urb status received: %d", 58038e8c910ff7a1aafe2923f085df0f74a60f9de3cGreg Kroah-Hartman __FUNCTION__, status); 5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This information is still unknown what it can be used for. 5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If anyone has an idea, please let the author know... 5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Rumor has it this endpoint is used to notify when data 5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * is ready to be read from the bulk ones. 5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_serial_debug_data(debug, &port->dev, __FUNCTION__, 5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds urb->actual_length, urb->transfer_buffer); 5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsexit: 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = usb_submit_urb (urb, GFP_ATOMIC); 5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) 5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_err(&urb->dev->dev, "%s - Error %d submitting interrupt urb\n", 5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FUNCTION__, result); 5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void visor_throttle (struct usb_serial_port *port) 6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct visor_private *priv = usb_get_serial_port_data(port); 6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s - port %d", __FUNCTION__, port->number); 6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&priv->lock, flags); 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->throttled = 1; 6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&priv->lock, flags); 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void visor_unthrottle (struct usb_serial_port *port) 6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct visor_private *priv = usb_get_serial_port_data(port); 6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int result; 6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s - port %d", __FUNCTION__, port->number); 6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&priv->lock, flags); 6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->throttled = 0; 622b308e74d9c708ee2a9af14fbe235e0a41216f4edOliver Neukum priv->actually_throttled = 0; 6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&priv->lock, flags); 6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->read_urb->dev = port->serial->dev; 6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = usb_submit_urb(port->read_urb, GFP_ATOMIC); 6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) 6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_err(&port->dev, "%s - failed submitting read urb, error %d\n", __FUNCTION__, result); 6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int palm_os_3_probe (struct usb_serial *serial, const struct usb_device_id *id) 6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct device *dev = &serial->dev->dev; 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct visor_connection_info *connection_info; 6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char *transfer_buffer; 6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *string; 6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval = 0; 6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int num_ports = 0; 6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s", __FUNCTION__); 6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds transfer_buffer = kmalloc (sizeof (*connection_info), GFP_KERNEL); 6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!transfer_buffer) { 6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_err(dev, "%s - kmalloc(%Zd) failed.\n", __FUNCTION__, 6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sizeof(*connection_info)); 6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* send a get connection info request */ 6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = usb_control_msg (serial->dev, 6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_rcvctrlpipe(serial->dev, 0), 6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds VISOR_GET_CONNECTION_INFORMATION, 6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0xc2, 0x0000, 0x0000, transfer_buffer, 6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sizeof(*connection_info), 300); 6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval < 0) { 6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_err(dev, "%s - error %d getting connection information\n", 6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FUNCTION__, retval); 6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval == sizeof(*connection_info)) { 6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds connection_info = (struct visor_connection_info *)transfer_buffer; 6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds num_ports = le16_to_cpu(connection_info->num_ports); 6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < num_ports; ++i) { 6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (connection_info->connections[i].port_function_id) { 6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case VISOR_FUNCTION_GENERIC: 6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds string = "Generic"; 6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case VISOR_FUNCTION_DEBUGGER: 6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds string = "Debugger"; 6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case VISOR_FUNCTION_HOTSYNC: 6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds string = "HotSync"; 6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case VISOR_FUNCTION_CONSOLE: 6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds string = "Console"; 6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case VISOR_FUNCTION_REMOTE_FILE_SYS: 6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds string = "Remote File System"; 6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds string = "unknown"; 6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_info(dev, "%s: port %d, is for %s use\n", 688269bda1c123c7caf88e1deb2264f9086f0344192Greg Kroah-Hartman serial->type->description, 6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds connection_info->connections[i].port, string); 6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Handle devices that report invalid stuff here. 6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (num_ports == 0 || num_ports > 2) { 6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_warn (dev, "%s: No valid connect info available\n", 697269bda1c123c7caf88e1deb2264f9086f0344192Greg Kroah-Hartman serial->type->description); 6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds num_ports = 2; 6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 701269bda1c123c7caf88e1deb2264f9086f0344192Greg Kroah-Hartman dev_info(dev, "%s: Number of ports: %d\n", serial->type->description, 7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds num_ports); 7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * save off our num_ports info so that we can use it in the 7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * calc_num_ports callback 7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_set_serial_data(serial, (void *)(long)num_ports); 7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* ask for the number of bytes available, but ignore the response as it is broken */ 7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = usb_control_msg (serial->dev, 7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_rcvctrlpipe(serial->dev, 0), 7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds VISOR_REQUEST_BYTES_AVAILABLE, 7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0xc2, 0x0000, 0x0005, transfer_buffer, 7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0x02, 300); 7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval < 0) 7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_err(dev, "%s - error %d getting bytes available request\n", 7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FUNCTION__, retval); 7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = 0; 7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsexit: 7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree (transfer_buffer); 7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int palm_os_4_probe (struct usb_serial *serial, const struct usb_device_id *id) 7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct device *dev = &serial->dev->dev; 7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct palm_ext_connection_info *connection_info; 7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char *transfer_buffer; 7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval; 7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s", __FUNCTION__); 7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds transfer_buffer = kmalloc (sizeof (*connection_info), GFP_KERNEL); 7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!transfer_buffer) { 7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_err(dev, "%s - kmalloc(%Zd) failed.\n", __FUNCTION__, 7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sizeof(*connection_info)); 7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = usb_control_msg (serial->dev, 7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_rcvctrlpipe(serial->dev, 0), 7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PALM_GET_EXT_CONNECTION_INFORMATION, 7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0xc2, 0x0000, 0x0000, transfer_buffer, 7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sizeof (*connection_info), 300); 7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval < 0) 7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_err(dev, "%s - error %d getting connection info\n", 7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FUNCTION__, retval); 7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_serial_debug_data(debug, &serial->dev->dev, __FUNCTION__, 7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval, transfer_buffer); 7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree (transfer_buffer); 7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int visor_probe (struct usb_serial *serial, const struct usb_device_id *id) 7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval = 0; 7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int (*startup) (struct usb_serial *serial, const struct usb_device_id *id); 7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s", __FUNCTION__); 7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (serial->dev->actconfig->desc.bConfigurationValue != 1) { 7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err("active config #%d != 1 ??", 7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serial->dev->actconfig->desc.bConfigurationValue); 7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (id->driver_info) { 7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds startup = (void *)id->driver_info; 7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = startup(serial, id); 7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int visor_calc_num_ports (struct usb_serial *serial) 7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int num_ports = (int)(long)(usb_get_serial_data(serial)); 7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (num_ports) 7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_set_serial_data(serial, NULL); 7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return num_ports; 7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int generic_startup(struct usb_serial *serial) 7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 793bd97c4f035b47c1a3ae5cc5ceccdda028b25e9d5Pete Zaitcev struct usb_serial_port **ports = serial->port; 7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct visor_private *priv; 7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < serial->num_ports; ++i) { 79880b6ca48321974a6566a1c9048ba34f60420bca6Eric Sesterhenn priv = kzalloc (sizeof(*priv), GFP_KERNEL); 799bd97c4f035b47c1a3ae5cc5ceccdda028b25e9d5Pete Zaitcev if (!priv) { 800bd97c4f035b47c1a3ae5cc5ceccdda028b25e9d5Pete Zaitcev while (i-- != 0) { 801bd97c4f035b47c1a3ae5cc5ceccdda028b25e9d5Pete Zaitcev priv = usb_get_serial_port_data(ports[i]); 802bd97c4f035b47c1a3ae5cc5ceccdda028b25e9d5Pete Zaitcev usb_set_serial_port_data(ports[i], NULL); 803bd97c4f035b47c1a3ae5cc5ceccdda028b25e9d5Pete Zaitcev kfree(priv); 804bd97c4f035b47c1a3ae5cc5ceccdda028b25e9d5Pete Zaitcev } 8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 806bd97c4f035b47c1a3ae5cc5ceccdda028b25e9d5Pete Zaitcev } 8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_init(&priv->lock); 808bd97c4f035b47c1a3ae5cc5ceccdda028b25e9d5Pete Zaitcev usb_set_serial_port_data(ports[i], priv); 8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int clie_3_5_startup (struct usb_serial *serial) 8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct device *dev = &serial->dev->dev; 8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int result; 8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 data; 8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s", __FUNCTION__); 8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note that PEG-300 series devices expect the following two calls. 8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* get the config number */ 8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), 8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds USB_REQ_GET_CONFIGURATION, USB_DIR_IN, 8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0, 0, &data, 1, 3000); 8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result < 0) { 8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_err(dev, "%s: get config number failed: %d\n", __FUNCTION__, result); 8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return result; 8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result != 1) { 8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_err(dev, "%s: get config number bad return length: %d\n", __FUNCTION__, result); 8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* get the interface number */ 8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), 8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds USB_REQ_GET_INTERFACE, 8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds USB_DIR_IN | USB_RECIP_INTERFACE, 8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0, 0, &data, 1, 3000); 8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result < 0) { 8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_err(dev, "%s: get interface number failed: %d\n", __FUNCTION__, result); 8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return result; 8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result != 1) { 8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_err(dev, "%s: get interface number bad return length: %d\n", __FUNCTION__, result); 8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return generic_startup(serial); 8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int treo_attach (struct usb_serial *serial) 8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_serial_port *swap_port; 8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Only do this endpoint hack for the Handspring devices with 8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * interrupt in endpoints, which for now are the Treo devices. */ 8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!((le16_to_cpu(serial->dev->descriptor.idVendor) == HANDSPRING_VENDOR_ID) || 8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (le16_to_cpu(serial->dev->descriptor.idVendor) == KYOCERA_VENDOR_ID)) || 8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (serial->num_interrupt_in == 0)) 8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto generic_startup; 8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s", __FUNCTION__); 8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * It appears that Treos and Kyoceras want to use the 8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1st bulk in endpoint to communicate with the 2nd bulk out endpoint, 8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * so let's swap the 1st and 2nd bulk in and interrupt endpoints. 8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note that swapping the bulk out endpoints would break lots of 8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * apps that want to communicate on the second port. 8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define COPY_PORT(dest, src) \ 8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dest->read_urb = src->read_urb; \ 8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dest->bulk_in_endpointAddress = src->bulk_in_endpointAddress; \ 8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dest->bulk_in_buffer = src->bulk_in_buffer; \ 8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dest->interrupt_in_urb = src->interrupt_in_urb; \ 8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dest->interrupt_in_endpointAddress = src->interrupt_in_endpointAddress; \ 8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dest->interrupt_in_buffer = src->interrupt_in_buffer; 8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds swap_port = kmalloc(sizeof(*swap_port), GFP_KERNEL); 8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!swap_port) 8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds COPY_PORT(swap_port, serial->port[0]); 8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds COPY_PORT(serial->port[0], serial->port[1]); 8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds COPY_PORT(serial->port[1], swap_port); 8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(swap_port); 8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsgeneric_startup: 8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return generic_startup(serial); 8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int clie_5_attach (struct usb_serial *serial) 8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s", __FUNCTION__); 8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* TH55 registers 2 ports. 9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Communication in from the UX50/TH55 uses bulk_in_endpointAddress from port 0 9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Communication out to the UX50/TH55 uses bulk_out_endpointAddress from port 1 9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Lets do a quick and dirty mapping 9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* some sanity check */ 9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (serial->num_ports < 2) 9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* port 0 now uses the modified endpoint Address */ 9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serial->port[0]->bulk_out_endpointAddress = serial->port[1]->bulk_out_endpointAddress; 9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return generic_startup(serial); 9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void visor_shutdown (struct usb_serial *serial) 9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 918bd97c4f035b47c1a3ae5cc5ceccdda028b25e9d5Pete Zaitcev struct visor_private *priv; 919bd97c4f035b47c1a3ae5cc5ceccdda028b25e9d5Pete Zaitcev int i; 920bd97c4f035b47c1a3ae5cc5ceccdda028b25e9d5Pete Zaitcev 9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s", __FUNCTION__); 922bd97c4f035b47c1a3ae5cc5ceccdda028b25e9d5Pete Zaitcev 923bd97c4f035b47c1a3ae5cc5ceccdda028b25e9d5Pete Zaitcev for (i = 0; i < serial->num_ports; i++) { 924bd97c4f035b47c1a3ae5cc5ceccdda028b25e9d5Pete Zaitcev priv = usb_get_serial_port_data(serial->port[i]); 925bd97c4f035b47c1a3ae5cc5ceccdda028b25e9d5Pete Zaitcev if (priv) { 926bd97c4f035b47c1a3ae5cc5ceccdda028b25e9d5Pete Zaitcev usb_set_serial_port_data(serial->port[i], NULL); 927bd97c4f035b47c1a3ae5cc5ceccdda028b25e9d5Pete Zaitcev kfree(priv); 928bd97c4f035b47c1a3ae5cc5ceccdda028b25e9d5Pete Zaitcev } 929bd97c4f035b47c1a3ae5cc5ceccdda028b25e9d5Pete Zaitcev } 9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int visor_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg) 9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s - port %d, cmd 0x%.4x", __FUNCTION__, port->number, cmd); 9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOIOCTLCMD; 9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init visor_init (void) 9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, retval; 9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Only if parameters were passed to us */ 9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((vendor>0) && (product>0)) { 9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_device_id usb_dev_temp[]= 9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds {{USB_DEVICE(vendor, product), 9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .driver_info = (kernel_ulong_t)&palm_os_4_probe }}; 9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Find the last entry in id_table */ 9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i=0; ; i++) { 9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (id_table[i].idVendor==0) { 9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds id_table[i] = usb_dev_temp[0]; 9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Find the last entry in id_table_combined */ 9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i=0; ; i++) { 9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (id_table_combined[i].idVendor==0) { 9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds id_table_combined[i] = usb_dev_temp[0]; 9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info("Untested USB device specified at time of module insertion"); 9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info("Warning: This is not guaranteed to work"); 9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info("Using a newer kernel is preferred to this method"); 9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info("Adding Palm OS protocol 4.x support for unknown device: 0x%x/0x%x", 9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vendor, product); 9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = usb_serial_register(&handspring_device); 9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval) 9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto failed_handspring_register; 9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = usb_serial_register(&clie_3_5_device); 9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval) 9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto failed_clie_3_5_register; 9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = usb_serial_register(&clie_5_device); 9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval) 9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto failed_clie_5_register; 9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = usb_register(&visor_driver); 9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval) 9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto failed_usb_register; 98017a882fc0c91477b2582a6dfd4ca93ae7eb58cd3Greg Kroah-Hartman info(DRIVER_DESC); 9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfailed_usb_register: 9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_serial_deregister(&clie_5_device); 9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfailed_clie_5_register: 9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_serial_deregister(&clie_3_5_device); 9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfailed_clie_3_5_register: 9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_serial_deregister(&handspring_device); 9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfailed_handspring_register: 9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit visor_exit (void) 9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_deregister (&visor_driver); 9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_serial_deregister (&handspring_device); 9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_serial_deregister (&clie_3_5_device); 9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_serial_deregister (&clie_5_device); 10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(visor_init); 10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(visor_exit); 10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR( DRIVER_AUTHOR ); 10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION( DRIVER_DESC ); 10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(debug, bool, S_IRUGO | S_IWUSR); 10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(debug, "Debug enabled or not"); 10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(stats, bool, S_IRUGO | S_IWUSR); 10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(stats, "Enables statistics or not"); 10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(vendor, ushort, 0); 10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(vendor, "User specified vendor ID"); 10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(product, ushort, 0); 10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(product, "User specified product ID"); 10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1020