Hi Matt, > What's the deal with the "special" inquiry command you send as part of > initialization? The code suggests that you're trying to detect something, > but all you look for is a response to, as far as I can tell, a normal > INQUIRY command.... I just played with the patch again to fine tune patch file to comply requirements of checkpatch.pl script and I also tested if I really can somehow drop that fake inquiry. I've found out that it is not possible. That device does not respond correctly during first bulk transfer and this inquiry detects it and as the init routine exits with 0 error code even after wrong result of inquiry routine, usb-store module does not send error message into syslog. Second and subsequent transfers work so second inquiry returns with 0 code and the switchmode routine is run afterwards. And switch mode should run well otherwise init will return with -EIO error code. I have cleaned up a bit the patch file. Find it attached to this email. I've already updated it on the page: http://www.magdina.org/projects/toshiba-g450-kernel-patch Peter
Signed-off-by: Peter Magdina <peter@xxxxxxxxxx> diff -Nparu linux-2.6.31.1-old/drivers/usb/serial/option.c linux-2.6.31.1-new/drivers/usb/serial/option.c --- linux-2.6.31.1-old/drivers/usb/serial/option.c 2009-10-03 00:14:54.000000000 +0200 +++ linux-2.6.31.1-new/drivers/usb/serial/option.c 2009-10-06 23:16:50.000000000 +0200 @@ -317,6 +317,7 @@ static int option_resume(struct usb_ser /* TOSHIBA PRODUCTS */ #define TOSHIBA_VENDOR_ID 0x0930 #define TOSHIBA_PRODUCT_HSDPA_MINICARD 0x1302 +#define TOSHIBA_PRODUCT_G450 0x0d45 #define ALINK_VENDOR_ID 0x1e0e #define ALINK_PRODUCT_3GU 0x9200 @@ -578,6 +579,7 @@ static struct usb_device_id option_ids[] { USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H21_4523) }, { USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H20_4515) }, { USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H20_4519) }, + { USB_DEVICE(TOSHIBA_VENDOR_ID, TOSHIBA_PRODUCT_G450) }, { USB_DEVICE(TOSHIBA_VENDOR_ID, TOSHIBA_PRODUCT_HSDPA_MINICARD ) }, /* Toshiba 3G HSDPA == Novatel Expedite EU870D MiniCard */ { USB_DEVICE(ALINK_VENDOR_ID, 0x9000) }, { USB_DEVICE_AND_INTERFACE_INFO(ALINK_VENDOR_ID, ALINK_PRODUCT_3GU, 0xff, 0xff, 0xff) }, diff -Nparu linux-2.6.31.1-old/drivers/usb/storage/Makefile linux-2.6.31.1-new/drivers/usb/storage/Makefile --- linux-2.6.31.1-old/drivers/usb/storage/Makefile 2009-10-03 00:14:54.000000000 +0200 +++ linux-2.6.31.1-new/drivers/usb/storage/Makefile 2009-10-03 00:15:40.000000000 +0200 @@ -12,7 +12,8 @@ obj-$(CONFIG_USB_STORAGE) += usb-storage usb-storage-obj-$(CONFIG_USB_STORAGE_DEBUG) += debug.o usb-storage-objs := scsiglue.o protocol.o transport.o usb.o \ - initializers.o sierra_ms.o option_ms.o $(usb-storage-obj-y) + initializers.o sierra_ms.o option_ms.o \ + toshiba_g450.o $(usb-storage-obj-y) ifeq ($(CONFIG_USB_LIBUSUAL),) usb-storage-objs += usual-tables.o diff -Nparu linux-2.6.31.1-old/drivers/usb/storage/toshiba_g450.c linux-2.6.31.1-new/drivers/usb/storage/toshiba_g450.c --- linux-2.6.31.1-old/drivers/usb/storage/toshiba_g450.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31.1-new/drivers/usb/storage/toshiba_g450.c 2009-10-06 23:37:58.000000000 +0200 @@ -0,0 +1,158 @@ +/* + * Driver for Toshiba G450 HSDPA modem. + * + * (c) 2009 Peter Magdina <peter@xxxxxxxxxx> + * + * Inspired by option_ms.c by Dan Williams <dcbw@xxxxxxxxxx> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <linux/usb.h> + +#include "usb.h" +#include "transport.h" +#include "toshiba_g450.h" +#include "debug.h" + +#define G450_FORCE_MODEM 0x01 +#define G450_ALLOW_MS 0x02 + +static unsigned int toshiba_g450_cd = G450_FORCE_MODEM; +module_param(toshiba_g450_cd, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(toshiba_g450_cd, "cd mode (1=Force Modem (default)," + " 2=Allow CD-Rom"); + +#define RESPONSE_LEN 1024 + +static int toshiba_g450_switchmode(struct us_data *us) +{ + const unsigned char switch_msg[] = { + 0x55, 0x53, 0x42, 0x43, 0x12, 0x34, 0x56, 0x78, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x1b, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + char *buffer; + int result; + + US_DEBUGP("Toshiba G450 : DEVICE MODE SWITCH\n"); + + buffer = kzalloc(RESPONSE_LEN, GFP_KERNEL); + if (buffer == NULL) + return USB_STOR_TRANSPORT_ERROR; + + memcpy(buffer, switch_msg, sizeof(switch_msg)); + result = usb_stor_bulk_transfer_buf(us, + us->send_bulk_pipe, + buffer, sizeof(switch_msg), NULL); + if (result != USB_STOR_XFER_GOOD) { + result = USB_STOR_XFER_ERROR; + goto out; + } + + /* Some of the devices need to be asked for a response, but we don't + * care what that response is. + */ + usb_stor_bulk_transfer_buf(us, + us->recv_bulk_pipe, + buffer, RESPONSE_LEN, NULL); + + result = USB_STOR_XFER_GOOD; + + usb_stor_clear_halt(us, us->send_bulk_pipe); + +out: + kfree(buffer); + return result; +} + +static int toshiba_g450_inquiry(struct us_data *us) +{ + const unsigned char inquiry_msg[] = { + 0x55, 0x53, 0x42, 0x43, 0x12, 0x34, 0x56, 0x78, + 0x24, 0x00, 0x00, 0x00, 0x80, 0x00, 0x06, 0x12, + 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + char *buffer; + int result; + + US_DEBUGP("Toshiba G450 : device inquiry\n"); + + buffer = kzalloc(0x24, GFP_KERNEL); + if (buffer == NULL) + return USB_STOR_TRANSPORT_ERROR; + + memcpy(buffer, inquiry_msg, sizeof(inquiry_msg)); + result = usb_stor_bulk_transfer_buf(us, + us->send_bulk_pipe, + buffer, sizeof(inquiry_msg), NULL); + if (result != USB_STOR_XFER_GOOD) { + result = USB_STOR_XFER_ERROR; + goto out; + } + + result = usb_stor_bulk_transfer_buf(us, + us->recv_bulk_pipe, + buffer, 0x24, NULL); + if (result != USB_STOR_XFER_GOOD) { + result = USB_STOR_XFER_ERROR; + goto out; + } + + /* Read the CSW */ + usb_stor_bulk_transfer_buf(us, + us->recv_bulk_pipe, + buffer, 13, NULL); + + usb_stor_clear_halt(us, us->send_bulk_pipe); + +out: + kfree(buffer); + return result; +} + + +int toshiba_g450_init(struct us_data *us) +{ + int result; + + US_DEBUGP("Toshiba G450 : toshiba_g450_init called\n"); + + result = toshiba_g450_inquiry(us); + if (result != 0) { + US_DEBUGP("Toshiba G450 : unable to inquire device," + " no action taken\n"); + return 0; + } + + /* Force Modem mode */ + if (toshiba_g450_cd == G450_FORCE_MODEM) { + US_DEBUGP("Toshiba G450 : Forcing Modem Mode\n"); + result = toshiba_g450_switchmode(us); + if (result != USB_STOR_XFER_GOOD) { + US_DEBUGP("Toshiba G450 : Failed to switch" + " to modem mode.\n"); + return -EIO; + } + } else if (toshiba_g450_cd == G450_ALLOW_MS) { + /* Allow Mass Storage mode (keep CD-Rom) */ + US_DEBUGP("Toshiba G450 : Allowing Mass Storage Mode" + " if device requests it\n"); + } + + return 0; +} diff -Nparu linux-2.6.31.1-old/drivers/usb/storage/toshiba_g450.h linux-2.6.31.1-new/drivers/usb/storage/toshiba_g450.h --- linux-2.6.31.1-old/drivers/usb/storage/toshiba_g450.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31.1-new/drivers/usb/storage/toshiba_g450.h 2009-10-03 00:15:40.000000000 +0200 @@ -0,0 +1,4 @@ +#ifndef _TOSHIBA_G450_H_ +#define _TOSHIBA_G450_H_ +extern int toshiba_g450_init(struct us_data *us); +#endif diff -Nparu linux-2.6.31.1-old/drivers/usb/storage/unusual_devs.h linux-2.6.31.1-new/drivers/usb/storage/unusual_devs.h --- linux-2.6.31.1-old/drivers/usb/storage/unusual_devs.h 2009-10-03 00:14:54.000000000 +0200 +++ linux-2.6.31.1-new/drivers/usb/storage/unusual_devs.h 2009-10-06 23:38:17.000000000 +0200 @@ -1110,6 +1110,13 @@ UNUSUAL_DEV( 0x090c, 0x1132, 0x0000, 0xf US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_CAPACITY ), +/* Patch by Peter Magdina <peter@xxxxxxxxxx> */ +UNUSUAL_DEV(0x0930, 0x0d46, 0x0000, 0x0000, + "Toshiba G450", + "Mass Storage", + US_SC_DEVICE, US_PR_DEVICE, toshiba_g450_init, + 0), + /* This Pentax still camera is not conformant * to the USB storage specification: - * - It does not like the INQUIRY command. So we must handle this command diff -Nparu linux-2.6.31.1-old/drivers/usb/storage/usb.c linux-2.6.31.1-new/drivers/usb/storage/usb.c --- linux-2.6.31.1-old/drivers/usb/storage/usb.c 2009-10-03 00:14:54.000000000 +0200 +++ linux-2.6.31.1-new/drivers/usb/storage/usb.c 2009-10-03 00:15:42.000000000 +0200 @@ -68,6 +68,7 @@ #include "sierra_ms.h" #include "option_ms.h" +#include "toshiba_g450.h" /* Some informational data */ MODULE_AUTHOR("Matthew Dharm <mdharm-usb@xxxxxxxxxxxxxxxxxx>");