aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNick Fedchik <nfedchik@atlantic-link.com.ua>2006-06-11 23:56:02 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2006-06-18 00:30:26 -0400
commit8ef80aef118e405f2b6505f623830e6e73224f85 (patch)
tree6abecac69d73eb3ffb884e29eb6ecc3c1d39cb7e
parentf8d596211291a8d98efa47ae0261326218f310cf (diff)
[IRDA]: irda-usb.c: STIR421x cleanups
This cleans the STIR421x part of the irda-usb code. We also no longer try to load all existing firmwares but only the matching one (according to the USB id we get from the dongle). Signed-off-by: Nick Fedchik <nfedchik@atlantic-link.com.ua> Signed-off-by: Samuel Ortiz <samuel@sortiz.org> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/irda/irda-usb.c327
-rw-r--r--drivers/net/irda/irda-usb.h10
2 files changed, 145 insertions, 192 deletions
diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c
index cd87593e4e8a..844fa74ac9ec 100644
--- a/drivers/net/irda/irda-usb.c
+++ b/drivers/net/irda/irda-usb.c
@@ -83,9 +83,9 @@ static struct usb_device_id dongles[] = {
83 /* Extended Systems, Inc., XTNDAccess IrDA USB (ESI-9685) */ 83 /* Extended Systems, Inc., XTNDAccess IrDA USB (ESI-9685) */
84 { USB_DEVICE(0x8e9, 0x100), .driver_info = IUC_SPEED_BUG | IUC_NO_WINDOW }, 84 { USB_DEVICE(0x8e9, 0x100), .driver_info = IUC_SPEED_BUG | IUC_NO_WINDOW },
85 /* SigmaTel STIR4210/4220/4116 USB IrDA (VFIR) Bridge */ 85 /* SigmaTel STIR4210/4220/4116 USB IrDA (VFIR) Bridge */
86 { USB_DEVICE(0x66f, 0x4210), .driver_info = IUC_STIR_4210 | IUC_SPEED_BUG }, 86 { USB_DEVICE(0x66f, 0x4210), .driver_info = IUC_STIR421X | IUC_SPEED_BUG },
87 { USB_DEVICE(0x66f, 0x4220), .driver_info = IUC_STIR_4210 | IUC_SPEED_BUG }, 87 { USB_DEVICE(0x66f, 0x4220), .driver_info = IUC_STIR421X | IUC_SPEED_BUG },
88 { USB_DEVICE(0x66f, 0x4116), .driver_info = IUC_STIR_4210 | IUC_SPEED_BUG }, 88 { USB_DEVICE(0x66f, 0x4116), .driver_info = IUC_STIR421X | IUC_SPEED_BUG },
89 { .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS | 89 { .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS |
90 USB_DEVICE_ID_MATCH_INT_SUBCLASS, 90 USB_DEVICE_ID_MATCH_INT_SUBCLASS,
91 .bInterfaceClass = USB_CLASS_APP_SPEC, 91 .bInterfaceClass = USB_CLASS_APP_SPEC,
@@ -154,7 +154,7 @@ static void irda_usb_build_header(struct irda_usb_cb *self,
154 * and if either speed or xbofs (or both) needs 154 * and if either speed or xbofs (or both) needs
155 * to be changed. 155 * to be changed.
156 */ 156 */
157 if (self->capability & IUC_STIR_4210 && 157 if (self->capability & IUC_STIR421X &&
158 ((self->new_speed != -1) || (self->new_xbofs != -1))) { 158 ((self->new_speed != -1) || (self->new_xbofs != -1))) {
159 159
160 /* With STIR421x, speed and xBOFs must be set at the same 160 /* With STIR421x, speed and xBOFs must be set at the same
@@ -318,7 +318,7 @@ static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self)
318 /* Set the new speed and xbofs in this fake frame */ 318 /* Set the new speed and xbofs in this fake frame */
319 irda_usb_build_header(self, frame, 1); 319 irda_usb_build_header(self, frame, 1);
320 320
321 if ( self->capability & IUC_STIR_4210 ) { 321 if (self->capability & IUC_STIR421X) {
322 if (frame[0] == 0) return ; // do nothing if no change 322 if (frame[0] == 0) return ; // do nothing if no change
323 frame[1] = 0; // other parameters don't change here 323 frame[1] = 0; // other parameters don't change here
324 frame[2] = 0; 324 frame[2] = 0;
@@ -455,7 +455,7 @@ static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev)
455 455
456 /* Change setting for next frame */ 456 /* Change setting for next frame */
457 457
458 if ( self->capability & IUC_STIR_4210 ) { 458 if (self->capability & IUC_STIR421X) {
459 __u8 turnaround_time; 459 __u8 turnaround_time;
460 __u8* frame; 460 __u8* frame;
461 turnaround_time = get_turnaround_time( skb ); 461 turnaround_time = get_turnaround_time( skb );
@@ -897,10 +897,13 @@ static void irda_usb_receive(struct urb *urb, struct pt_regs *regs)
897 docopy = (urb->actual_length < IRDA_RX_COPY_THRESHOLD); 897 docopy = (urb->actual_length < IRDA_RX_COPY_THRESHOLD);
898 898
899 /* Allocate a new skb */ 899 /* Allocate a new skb */
900 if ( self->capability & IUC_STIR_4210 ) 900 if (self->capability & IUC_STIR421X)
901 newskb = dev_alloc_skb(docopy ? urb->actual_length : IRDA_SKB_MAX_MTU + USB_IRDA_SIGMATEL_HEADER); 901 newskb = dev_alloc_skb(docopy ? urb->actual_length :
902 IRDA_SKB_MAX_MTU +
903 USB_IRDA_STIR421X_HEADER);
902 else 904 else
903 newskb = dev_alloc_skb(docopy ? urb->actual_length : IRDA_SKB_MAX_MTU); 905 newskb = dev_alloc_skb(docopy ? urb->actual_length :
906 IRDA_SKB_MAX_MTU);
904 907
905 if (!newskb) { 908 if (!newskb) {
906 self->stats.rx_dropped++; 909 self->stats.rx_dropped++;
@@ -1022,188 +1025,140 @@ static int irda_usb_is_receiving(struct irda_usb_cb *self)
1022 return 0; /* For now */ 1025 return 0; /* For now */
1023} 1026}
1024 1027
1025 1028#define STIR421X_PATCH_PRODUCT_VER "Product Version: "
1026#define STIR421X_PATCH_PRODUCT_VERSION_STR "Product Version: " 1029#define STIR421X_PATCH_STMP_TAG "STMP"
1027#define STIR421X_PATCH_COMPONENT_VERSION_STR "Component Version: " 1030#define STIR421X_PATCH_CODE_OFFSET 512 /* patch image starts before here */
1028#define STIR421X_PATCH_DATA_TAG_STR "STMP" 1031/* marks end of patch file header (PC DOS text file EOF character) */
1029#define STIR421X_PATCH_FILE_VERSION_MAX_OFFSET 512 /* version info is before here */ 1032#define STIR421X_PATCH_END_OF_HDR_TAG 0x1A
1030#define STIR421X_PATCH_FILE_IMAGE_MAX_OFFSET 512 /* patch image starts before here */ 1033#define STIR421X_PATCH_BLOCK_SIZE 1023
1031#define STIR421X_PATCH_FILE_END_OF_HEADER_TAG 0x1A /* marks end of patch file header (PC DOS text file EOF character) */
1032 1034
1033/* 1035/*
1034 * Known firmware patches for STIR421x dongles 1036 * Function stir421x_fwupload (struct irda_usb_cb *self,
1037 * unsigned char *patch,
1038 * const unsigned int patch_len)
1039 *
1040 * Upload firmware code to SigmaTel 421X IRDA-USB dongle
1035 */ 1041 */
1036static char * stir421x_patches[] = { 1042static int stir421x_fw_upload(struct irda_usb_cb *self,
1037 "42101001.sb", 1043 unsigned char *patch,
1038 "42101002.sb", 1044 const unsigned int patch_len)
1039};
1040
1041static int stir421x_get_patch_version(unsigned char * patch, const unsigned long patch_len)
1042{ 1045{
1043 unsigned int version_offset; 1046 int ret = -ENOMEM;
1044 unsigned long version_major, version_minor, version_build; 1047 int actual_len = 0;
1045 unsigned char * version_start; 1048 unsigned int i;
1046 int version_found = 0; 1049 unsigned int block_size = 0;
1047 1050 unsigned char *patch_block;
1048 for (version_offset = 0; 1051
1049 version_offset < STIR421X_PATCH_FILE_END_OF_HEADER_TAG; 1052 patch_block = kzalloc(STIR421X_PATCH_BLOCK_SIZE, GFP_KERNEL);
1050 version_offset++) { 1053 if (patch_block == NULL)
1051 if (!memcmp(patch + version_offset, 1054 return -ENOMEM;
1052 STIR421X_PATCH_PRODUCT_VERSION_STR, 1055
1053 sizeof(STIR421X_PATCH_PRODUCT_VERSION_STR) - 1)) { 1056 /* break up patch into 1023-byte sections */
1054 version_found = 1; 1057 for (i = 0; i < patch_len; i += block_size) {
1055 version_start = patch + 1058 block_size = patch_len - i;
1056 version_offset + 1059
1057 sizeof(STIR421X_PATCH_PRODUCT_VERSION_STR) - 1; 1060 if (block_size > STIR421X_PATCH_BLOCK_SIZE)
1058 break; 1061 block_size = STIR421X_PATCH_BLOCK_SIZE;
1059 } 1062
1063 /* upload the patch section */
1064 memcpy(patch_block, patch + i, block_size);
1065
1066 ret = usb_bulk_msg(self->usbdev,
1067 usb_sndbulkpipe(self->usbdev,
1068 self->bulk_out_ep),
1069 patch_block, block_size,
1070 &actual_len, msecs_to_jiffies(500));
1071 IRDA_DEBUG(3,"%s(): Bulk send %u bytes, ret=%d\n",
1072 __FUNCTION__, actual_len, ret);
1073
1074 if (ret < 0)
1075 break;
1060 } 1076 }
1061 1077
1062 /* We couldn't find a product version on this patch */ 1078 kfree(patch_block);
1063 if (!version_found)
1064 return -EINVAL;
1065
1066 /* Let's check if the product version is dotted */
1067 if (version_start[3] != '.' ||
1068 version_start[7] != '.')
1069 return -EINVAL;
1070
1071 version_major = simple_strtoul(version_start, NULL, 10);
1072 version_minor = simple_strtoul(version_start + 4, NULL, 10);
1073 version_build = simple_strtoul(version_start + 8, NULL, 10);
1074
1075 IRDA_DEBUG(2, "%s(), Major: %ld Minor: %ld Build: %ld\n",
1076 __FUNCTION__,
1077 version_major, version_minor, version_build);
1078
1079 return (((version_major) << 12) +
1080 ((version_minor) << 8) +
1081 ((version_build / 10) << 4) +
1082 (version_build % 10));
1083
1084}
1085
1086
1087static int stir421x_upload_patch (struct irda_usb_cb *self,
1088 unsigned char * patch,
1089 const unsigned int patch_len)
1090{
1091 int retval = 0;
1092 int actual_len;
1093 unsigned int i = 0, download_amount = 0;
1094 unsigned char * patch_chunk;
1095
1096 IRDA_DEBUG (2, "%s(), Uploading STIR421x Patch\n", __FUNCTION__);
1097
1098 patch_chunk = kzalloc(STIR421X_MAX_PATCH_DOWNLOAD_SIZE, GFP_KERNEL);
1099 if (patch_chunk == NULL)
1100 return -ENOMEM;
1101
1102 /* break up patch into 1023-byte sections */
1103 for (i = 0; retval >= 0 && i < patch_len; i += download_amount) {
1104 download_amount = patch_len - i;
1105 if (download_amount > STIR421X_MAX_PATCH_DOWNLOAD_SIZE)
1106 download_amount = STIR421X_MAX_PATCH_DOWNLOAD_SIZE;
1107
1108 /* download the patch section */
1109 memcpy(patch_chunk, patch + i, download_amount);
1110
1111 retval = usb_bulk_msg (self->usbdev,
1112 usb_sndbulkpipe (self->usbdev,
1113 self->bulk_out_ep),
1114 patch_chunk, download_amount,
1115 &actual_len, msecs_to_jiffies (500));
1116 IRDA_DEBUG (2, "%s(), Sent %u bytes\n", __FUNCTION__,
1117 actual_len);
1118 if (retval == 0)
1119 mdelay(10);
1120 }
1121
1122 kfree(patch_chunk);
1123
1124 if (i != patch_len) {
1125 IRDA_ERROR ("%s(), Pushed %d bytes (!= patch_len (%d))\n",
1126 __FUNCTION__, i, patch_len);
1127 retval = -EIO;
1128 }
1129
1130 if (retval < 0)
1131 /* todo - mark device as not ready */
1132 IRDA_ERROR ("%s(), STIR421x patch upload failed (%d)\n",
1133 __FUNCTION__, retval);
1134
1135 return retval;
1136}
1137 1079
1080 return ret;
1081 }
1138 1082
1083/*
1084 * Function stir421x_patch_device(struct irda_usb_cb *self)
1085 *
1086 * Get a firmware code from userspase using hotplug request_firmware() call
1087 */
1139static int stir421x_patch_device(struct irda_usb_cb *self) 1088static int stir421x_patch_device(struct irda_usb_cb *self)
1140{ 1089{
1141 unsigned int i, patch_found = 0, data_found = 0, data_offset; 1090 unsigned int i;
1142 int patch_version, ret = 0; 1091 int ret;
1143 const struct firmware *fw_entry; 1092 char stir421x_fw_name[11];
1144 1093 const struct firmware *fw;
1145 for (i = 0; i < ARRAY_SIZE(stir421x_patches); i++) { 1094 unsigned char *fw_version_ptr; /* pointer to version string */
1146 if(request_firmware(&fw_entry, stir421x_patches[i], &self->usbdev->dev) != 0) { 1095 unsigned long fw_version = 0;
1147 IRDA_ERROR( "%s(), Patch %s is not available\n", __FUNCTION__, stir421x_patches[i]); 1096
1148 continue; 1097 /*
1149 } 1098 * Known firmware patch file names for STIR421x dongles
1150 1099 * are "42101001.sb" or "42101002.sb"
1151 /* We found a patch from userspace */ 1100 */
1152 patch_version = stir421x_get_patch_version (fw_entry->data, fw_entry->size); 1101 sprintf(stir421x_fw_name, "4210%4X.sb",
1153 1102 self->usbdev->descriptor.bcdDevice);
1154 if (patch_version < 0) { 1103 ret = request_firmware(&fw, stir421x_fw_name, &self->usbdev->dev);
1155 /* Couldn't fetch a version, let's move on to the next file */ 1104 if (ret < 0)
1156 IRDA_ERROR("%s(), version parsing failed\n", __FUNCTION__); 1105 return ret;
1157 ret = patch_version; 1106
1158 release_firmware(fw_entry); 1107 /* We get a patch from userspace */
1159 continue; 1108 IRDA_MESSAGE("%s(): Received firmware %s (%u bytes)\n",
1160 } 1109 __FUNCTION__, stir421x_fw_name, fw->size);
1161 1110
1162 if (patch_version != self->usbdev->descriptor.bcdDevice) { 1111 ret = -EINVAL;
1163 /* Patch version and device don't match */ 1112
1164 IRDA_ERROR ("%s(), wrong patch version (%d <-> %d)\n", 1113 /* Get the bcd product version */
1165 __FUNCTION__, 1114 if (!memcmp(fw->data, STIR421X_PATCH_PRODUCT_VER,
1166 patch_version, self->usbdev->descriptor.bcdDevice); 1115 sizeof(STIR421X_PATCH_PRODUCT_VER) - 1)) {
1167 ret = -EINVAL; 1116 fw_version_ptr = fw->data +
1168 release_firmware(fw_entry); 1117 sizeof(STIR421X_PATCH_PRODUCT_VER) - 1;
1169 continue; 1118
1170 } 1119 /* Let's check if the product version is dotted */
1171 1120 if (fw_version_ptr[3] == '.' &&
1172 /* If we're here, we've found a correct patch */ 1121 fw_version_ptr[7] == '.') {
1173 patch_found = 1; 1122 unsigned long major, minor, build;
1174 break; 1123 major = simple_strtoul(fw_version_ptr, NULL, 10);
1175 1124 minor = simple_strtoul(fw_version_ptr + 4, NULL, 10);
1176 } 1125 build = simple_strtoul(fw_version_ptr + 8, NULL, 10);
1177 1126
1178 /* We couldn't find a valid firmware, let's leave */ 1127 fw_version = (major << 12)
1179 if (!patch_found) 1128 + (minor << 8)
1180 return ret; 1129 + ((build / 10) << 4)
1181 1130 + (build % 10);
1182 /* The actual image starts after the "STMP" keyword */ 1131
1183 for (data_offset = 0; data_offset < STIR421X_PATCH_FILE_IMAGE_MAX_OFFSET; data_offset++) { 1132 IRDA_DEBUG(3, "%s(): Firmware Product version %ld\n",
1184 if (!memcmp(fw_entry->data + data_offset, 1133 __FUNCTION__, fw_version);
1185 STIR421X_PATCH_DATA_TAG_STR, 1134 }
1186 sizeof(STIR421X_PATCH_FILE_IMAGE_MAX_OFFSET))) { 1135 }
1187 IRDA_DEBUG(2, "%s(), found patch data for STIR421x at offset %d\n", 1136
1188 __FUNCTION__, data_offset); 1137 if (self->usbdev->descriptor.bcdDevice == fw_version) {
1189 data_found = 1; 1138 /*
1190 break; 1139 * If we're here, we've found a correct patch
1191 } 1140 * The actual image starts after the "STMP" keyword
1192 } 1141 * so forward to the firmware header tag
1193 1142 */
1194 /* We couldn't find "STMP" from the header */ 1143 for (i = 0; (fw->data[i] != STIR421X_PATCH_END_OF_HDR_TAG)
1195 if (!data_found) 1144 && (i < fw->size); i++) ;
1196 return -EINVAL; 1145 /* here we check for the out of buffer case */
1197 1146 if ((STIR421X_PATCH_END_OF_HDR_TAG == fw->data[i])
1198 /* Let's upload the patch to the target */ 1147 && (i < STIR421X_PATCH_CODE_OFFSET)) {
1199 ret = stir421x_upload_patch(self, 1148 if (!memcmp(fw->data + i + 1, STIR421X_PATCH_STMP_TAG,
1200 &fw_entry->data[data_offset + sizeof(STIR421X_PATCH_FILE_IMAGE_MAX_OFFSET)], 1149 sizeof(STIR421X_PATCH_STMP_TAG) - 1)) {
1201 fw_entry->size - (data_offset + sizeof(STIR421X_PATCH_FILE_IMAGE_MAX_OFFSET))); 1150
1202 1151 /* We can upload the patch to the target */
1203 release_firmware(fw_entry); 1152 i += sizeof(STIR421X_PATCH_STMP_TAG);
1204 1153 ret = stir421x_fw_upload(self, &fw->data[i],
1205 return ret; 1154 fw->size - i);
1206 1155 }
1156 }
1157 }
1158
1159 release_firmware(fw);
1160
1161 return ret;
1207} 1162}
1208 1163
1209 1164
@@ -1702,12 +1657,12 @@ static int irda_usb_probe(struct usb_interface *intf,
1702 init_timer(&self->rx_defer_timer); 1657 init_timer(&self->rx_defer_timer);
1703 1658
1704 self->capability = id->driver_info; 1659 self->capability = id->driver_info;
1705 self->needspatch = ((self->capability & IUC_STIR_4210) != 0) ; 1660 self->needspatch = ((self->capability & IUC_STIR421X) != 0);
1706 1661
1707 /* Create all of the needed urbs */ 1662 /* Create all of the needed urbs */
1708 if (self->capability & IUC_STIR_4210) { 1663 if (self->capability & IUC_STIR421X) {
1709 self->max_rx_urb = IU_SIGMATEL_MAX_RX_URBS; 1664 self->max_rx_urb = IU_SIGMATEL_MAX_RX_URBS;
1710 self->header_length = USB_IRDA_SIGMATEL_HEADER; 1665 self->header_length = USB_IRDA_STIR421X_HEADER;
1711 } else { 1666 } else {
1712 self->max_rx_urb = IU_MAX_RX_URBS; 1667 self->max_rx_urb = IU_MAX_RX_URBS;
1713 self->header_length = USB_IRDA_HEADER; 1668 self->header_length = USB_IRDA_HEADER;
@@ -1813,8 +1768,8 @@ static int irda_usb_probe(struct usb_interface *intf,
1813 /* Now we fetch and upload the firmware patch */ 1768 /* Now we fetch and upload the firmware patch */
1814 ret = stir421x_patch_device(self); 1769 ret = stir421x_patch_device(self);
1815 self->needspatch = (ret < 0); 1770 self->needspatch = (ret < 0);
1816 if (ret < 0) { 1771 if (self->needspatch) {
1817 printk("patch_device failed\n"); 1772 IRDA_ERROR("STIR421X: Couldn't upload patch\n");
1818 goto err_out_5; 1773 goto err_out_5;
1819 } 1774 }
1820 1775
diff --git a/drivers/net/irda/irda-usb.h b/drivers/net/irda/irda-usb.h
index d833db52cebf..6b2271f18e77 100644
--- a/drivers/net/irda/irda-usb.h
+++ b/drivers/net/irda/irda-usb.h
@@ -34,9 +34,6 @@
34#include <net/irda/irda.h> 34#include <net/irda/irda.h>
35#include <net/irda/irda_device.h> /* struct irlap_cb */ 35#include <net/irda/irda_device.h> /* struct irlap_cb */
36 36
37#define PATCH_FILE_SIZE_MAX 65536
38#define PATCH_FILE_SIZE_MIN 80
39
40#define RX_COPY_THRESHOLD 200 37#define RX_COPY_THRESHOLD 200
41#define IRDA_USB_MAX_MTU 2051 38#define IRDA_USB_MAX_MTU 2051
42#define IRDA_USB_SPEED_MTU 64 /* Weird, but work like this */ 39#define IRDA_USB_SPEED_MTU 64 /* Weird, but work like this */
@@ -107,14 +104,15 @@
107#define IUC_SMALL_PKT 0x10 /* Device doesn't behave with big Rx packets */ 104#define IUC_SMALL_PKT 0x10 /* Device doesn't behave with big Rx packets */
108#define IUC_MAX_WINDOW 0x20 /* Device underestimate the Rx window */ 105#define IUC_MAX_WINDOW 0x20 /* Device underestimate the Rx window */
109#define IUC_MAX_XBOFS 0x40 /* Device need more xbofs than advertised */ 106#define IUC_MAX_XBOFS 0x40 /* Device need more xbofs than advertised */
110#define IUC_STIR_4210 0x80 /* SigmaTel 4210/4220/4116 VFIR */ 107#define IUC_STIR421X 0x80 /* SigmaTel 4210/4220/4116 VFIR */
111 108
112/* USB class definitions */ 109/* USB class definitions */
113#define USB_IRDA_HEADER 0x01 110#define USB_IRDA_HEADER 0x01
114#define USB_CLASS_IRDA 0x02 /* USB_CLASS_APP_SPEC subclass */ 111#define USB_CLASS_IRDA 0x02 /* USB_CLASS_APP_SPEC subclass */
115#define USB_DT_IRDA 0x21 112#define USB_DT_IRDA 0x21
116#define USB_IRDA_SIGMATEL_HEADER 0x03 113#define USB_IRDA_STIR421X_HEADER 0x03
117#define IU_SIGMATEL_MAX_RX_URBS (IU_MAX_ACTIVE_RX_URBS + USB_IRDA_SIGMATEL_HEADER) 114#define IU_SIGMATEL_MAX_RX_URBS (IU_MAX_ACTIVE_RX_URBS + \
115 USB_IRDA_STIR421X_HEADER)
118 116
119struct irda_class_desc { 117struct irda_class_desc {
120 __u8 bLength; 118 __u8 bLength;