diff options
author | Samuel Ortiz <samuel.ortiz@nokia.com> | 2006-04-06 01:39:14 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-04-10 01:25:31 -0400 |
commit | 137dc0233fba0bfa19679bdd96eb104f0e659c5a (patch) | |
tree | b1a087b443e6865478b6f99b54cbd562d3837886 /drivers/net/irda/irda-usb.c | |
parent | c1e14a6ea2ae34993f431d2eb9a0f228ac3574eb (diff) |
[IRDA]: Support for Sigmatel STIR421x chip
This patch enables support for the Sigmatel's STIR421x IrDA chip.
Once patched with Sigmatel's firmware, this chip "almost" follows the
USB-IrDA spec. Thus this patch is against irda-usb.[ch].
The code has been tested by Nick Fedchik on an STIR4210 chipset based
dongle.
Signed-off-by: Samuel Ortiz <samuel.ortiz@nokia.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/irda/irda-usb.c')
-rw-r--r-- | drivers/net/irda/irda-usb.c | 363 |
1 files changed, 343 insertions, 20 deletions
diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c index 6e2ec56cde0b..606243d11793 100644 --- a/drivers/net/irda/irda-usb.c +++ b/drivers/net/irda/irda-usb.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /***************************************************************************** | 1 | /***************************************************************************** |
2 | * | 2 | * |
3 | * Filename: irda-usb.c | 3 | * Filename: irda-usb.c |
4 | * Version: 0.9b | 4 | * Version: 0.10 |
5 | * Description: IrDA-USB Driver | 5 | * Description: IrDA-USB Driver |
6 | * Status: Experimental | 6 | * Status: Experimental |
7 | * Author: Dag Brattli <dag@brattli.net> | 7 | * Author: Dag Brattli <dag@brattli.net> |
@@ -9,6 +9,9 @@ | |||
9 | * Copyright (C) 2000, Roman Weissgaerber <weissg@vienna.at> | 9 | * Copyright (C) 2000, Roman Weissgaerber <weissg@vienna.at> |
10 | * Copyright (C) 2001, Dag Brattli <dag@brattli.net> | 10 | * Copyright (C) 2001, Dag Brattli <dag@brattli.net> |
11 | * Copyright (C) 2001, Jean Tourrilhes <jt@hpl.hp.com> | 11 | * Copyright (C) 2001, Jean Tourrilhes <jt@hpl.hp.com> |
12 | * Copyright (C) 2004, SigmaTel, Inc. <irquality@sigmatel.com> | ||
13 | * Copyright (C) 2005, Milan Beno <beno@pobox.sk> | ||
14 | * Copyright (C) 2006, Nick Fedchik <nick@fedchik.org.ua> | ||
12 | * | 15 | * |
13 | * This program is free software; you can redistribute it and/or modify | 16 | * This program is free software; you can redistribute it and/or modify |
14 | * it under the terms of the GNU General Public License as published by | 17 | * it under the terms of the GNU General Public License as published by |
@@ -61,6 +64,7 @@ | |||
61 | #include <linux/slab.h> | 64 | #include <linux/slab.h> |
62 | #include <linux/rtnetlink.h> | 65 | #include <linux/rtnetlink.h> |
63 | #include <linux/usb.h> | 66 | #include <linux/usb.h> |
67 | #include <linux/firmware.h> | ||
64 | 68 | ||
65 | #include "irda-usb.h" | 69 | #include "irda-usb.h" |
66 | 70 | ||
@@ -78,8 +82,12 @@ static struct usb_device_id dongles[] = { | |||
78 | { USB_DEVICE(0x50f, 0x180), .driver_info = IUC_SPEED_BUG | IUC_NO_WINDOW }, | 82 | { USB_DEVICE(0x50f, 0x180), .driver_info = IUC_SPEED_BUG | IUC_NO_WINDOW }, |
79 | /* Extended Systems, Inc., XTNDAccess IrDA USB (ESI-9685) */ | 83 | /* Extended Systems, Inc., XTNDAccess IrDA USB (ESI-9685) */ |
80 | { 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 */ | ||
86 | { USB_DEVICE(0x66f, 0x4210), .driver_info = IUC_STIR_4210 | IUC_SPEED_BUG }, | ||
87 | { USB_DEVICE(0x66f, 0x4220), .driver_info = IUC_STIR_4210 | IUC_SPEED_BUG }, | ||
88 | { USB_DEVICE(0x66f, 0x4116), .driver_info = IUC_STIR_4210 | IUC_SPEED_BUG }, | ||
81 | { .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS | | 89 | { .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS | |
82 | USB_DEVICE_ID_MATCH_INT_SUBCLASS, | 90 | USB_DEVICE_ID_MATCH_INT_SUBCLASS, |
83 | .bInterfaceClass = USB_CLASS_APP_SPEC, | 91 | .bInterfaceClass = USB_CLASS_APP_SPEC, |
84 | .bInterfaceSubClass = USB_CLASS_IRDA, | 92 | .bInterfaceSubClass = USB_CLASS_IRDA, |
85 | .driver_info = IUC_DEFAULT, }, | 93 | .driver_info = IUC_DEFAULT, }, |
@@ -99,6 +107,7 @@ MODULE_DEVICE_TABLE(usb, dongles); | |||
99 | 107 | ||
100 | /*------------------------------------------------------------------*/ | 108 | /*------------------------------------------------------------------*/ |
101 | 109 | ||
110 | static void irda_usb_init_qos(struct irda_usb_cb *self) ; | ||
102 | static struct irda_class_desc *irda_usb_find_class_desc(struct usb_interface *intf); | 111 | static struct irda_class_desc *irda_usb_find_class_desc(struct usb_interface *intf); |
103 | static void irda_usb_disconnect(struct usb_interface *intf); | 112 | static void irda_usb_disconnect(struct usb_interface *intf); |
104 | static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self); | 113 | static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self); |
@@ -141,7 +150,24 @@ static void irda_usb_build_header(struct irda_usb_cb *self, | |||
141 | __u8 *header, | 150 | __u8 *header, |
142 | int force) | 151 | int force) |
143 | { | 152 | { |
144 | /* Set the negotiated link speed */ | 153 | /* Here we check if we have an STIR421x chip, |
154 | * and if either speed or xbofs (or both) needs | ||
155 | * to be changed. | ||
156 | */ | ||
157 | if (self->capability & IUC_STIR_4210 && | ||
158 | ((self->new_speed != -1) || (self->new_xbofs != -1))) { | ||
159 | |||
160 | /* With STIR421x, speed and xBOFs must be set at the same | ||
161 | * time, even if only one of them changes. | ||
162 | */ | ||
163 | if (self->new_speed == -1) | ||
164 | self->new_speed = self->speed ; | ||
165 | |||
166 | if (self->new_xbofs == -1) | ||
167 | self->new_xbofs = self->xbofs ; | ||
168 | } | ||
169 | |||
170 | /* Set the link speed */ | ||
145 | if (self->new_speed != -1) { | 171 | if (self->new_speed != -1) { |
146 | /* Hum... Ugly hack :-( | 172 | /* Hum... Ugly hack :-( |
147 | * Some device are not compliant with the spec and change | 173 | * Some device are not compliant with the spec and change |
@@ -191,7 +217,11 @@ static void irda_usb_build_header(struct irda_usb_cb *self, | |||
191 | *header = SPEED_4000000; | 217 | *header = SPEED_4000000; |
192 | self->new_xbofs = 0; | 218 | self->new_xbofs = 0; |
193 | break; | 219 | break; |
194 | } | 220 | case 16000000: |
221 | *header = SPEED_16000000; | ||
222 | self->new_xbofs = 0; | ||
223 | break; | ||
224 | } | ||
195 | } else | 225 | } else |
196 | /* No change */ | 226 | /* No change */ |
197 | *header = 0; | 227 | *header = 0; |
@@ -235,6 +265,32 @@ static void irda_usb_build_header(struct irda_usb_cb *self, | |||
235 | } | 265 | } |
236 | } | 266 | } |
237 | 267 | ||
268 | /* | ||
269 | * calculate turnaround time for SigmaTel header | ||
270 | */ | ||
271 | static __u8 get_turnaround_time(struct sk_buff *skb) | ||
272 | { | ||
273 | int turnaround_time = irda_get_mtt(skb); | ||
274 | |||
275 | if ( turnaround_time == 0 ) | ||
276 | return 0; | ||
277 | else if ( turnaround_time <= 10 ) | ||
278 | return 1; | ||
279 | else if ( turnaround_time <= 50 ) | ||
280 | return 2; | ||
281 | else if ( turnaround_time <= 100 ) | ||
282 | return 3; | ||
283 | else if ( turnaround_time <= 500 ) | ||
284 | return 4; | ||
285 | else if ( turnaround_time <= 1000 ) | ||
286 | return 5; | ||
287 | else if ( turnaround_time <= 5000 ) | ||
288 | return 6; | ||
289 | else | ||
290 | return 7; | ||
291 | } | ||
292 | |||
293 | |||
238 | /*------------------------------------------------------------------*/ | 294 | /*------------------------------------------------------------------*/ |
239 | /* | 295 | /* |
240 | * Send a command to change the speed of the dongle | 296 | * Send a command to change the speed of the dongle |
@@ -262,12 +318,18 @@ static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self) | |||
262 | /* Set the new speed and xbofs in this fake frame */ | 318 | /* Set the new speed and xbofs in this fake frame */ |
263 | irda_usb_build_header(self, frame, 1); | 319 | irda_usb_build_header(self, frame, 1); |
264 | 320 | ||
321 | if ( self->capability & IUC_STIR_4210 ) { | ||
322 | if (frame[0] == 0) return ; // do nothing if no change | ||
323 | frame[1] = 0; // other parameters don't change here | ||
324 | frame[2] = 0; | ||
325 | } | ||
326 | |||
265 | /* Submit the 0 length IrDA frame to trigger new speed settings */ | 327 | /* Submit the 0 length IrDA frame to trigger new speed settings */ |
266 | usb_fill_bulk_urb(urb, self->usbdev, | 328 | usb_fill_bulk_urb(urb, self->usbdev, |
267 | usb_sndbulkpipe(self->usbdev, self->bulk_out_ep), | 329 | usb_sndbulkpipe(self->usbdev, self->bulk_out_ep), |
268 | frame, IRDA_USB_SPEED_MTU, | 330 | frame, IRDA_USB_SPEED_MTU, |
269 | speed_bulk_callback, self); | 331 | speed_bulk_callback, self); |
270 | urb->transfer_buffer_length = USB_IRDA_HEADER; | 332 | urb->transfer_buffer_length = self->header_length; |
271 | urb->transfer_flags = 0; | 333 | urb->transfer_flags = 0; |
272 | 334 | ||
273 | /* Irq disabled -> GFP_ATOMIC */ | 335 | /* Irq disabled -> GFP_ATOMIC */ |
@@ -383,16 +445,35 @@ static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev) | |||
383 | * allocation will be done lower in skb_push(). | 445 | * allocation will be done lower in skb_push(). |
384 | * Also, we don't use directly skb_cow(), because it require | 446 | * Also, we don't use directly skb_cow(), because it require |
385 | * headroom >= 16, which force unnecessary copies - Jean II */ | 447 | * headroom >= 16, which force unnecessary copies - Jean II */ |
386 | if (skb_headroom(skb) < USB_IRDA_HEADER) { | 448 | if (skb_headroom(skb) < self->header_length) { |
387 | IRDA_DEBUG(0, "%s(), Insuficient skb headroom.\n", __FUNCTION__); | 449 | IRDA_DEBUG(0, "%s(), Insuficient skb headroom.\n", __FUNCTION__); |
388 | if (skb_cow(skb, USB_IRDA_HEADER)) { | 450 | if (skb_cow(skb, self->header_length)) { |
389 | IRDA_WARNING("%s(), failed skb_cow() !!!\n", __FUNCTION__); | 451 | IRDA_WARNING("%s(), failed skb_cow() !!!\n", __FUNCTION__); |
390 | goto drop; | 452 | goto drop; |
391 | } | 453 | } |
392 | } | 454 | } |
393 | 455 | ||
394 | /* Change setting for next frame */ | 456 | /* Change setting for next frame */ |
395 | irda_usb_build_header(self, skb_push(skb, USB_IRDA_HEADER), 0); | 457 | |
458 | if ( self->capability & IUC_STIR_4210 ) { | ||
459 | __u8 turnaround_time; | ||
460 | __u8* frame; | ||
461 | turnaround_time = get_turnaround_time( skb ); | ||
462 | frame= skb_push(skb, self->header_length); | ||
463 | irda_usb_build_header(self, frame, 0); | ||
464 | frame[2] = turnaround_time; | ||
465 | if ((skb->len != 0) && | ||
466 | ((skb->len % 128) == 0) && | ||
467 | ((skb->len % 512) != 0)) { | ||
468 | /* add extra byte for special SigmaTel feature */ | ||
469 | frame[1] = 1; | ||
470 | skb_put(skb, 1); | ||
471 | } else { | ||
472 | frame[1] = 0; | ||
473 | } | ||
474 | } else { | ||
475 | irda_usb_build_header(self, skb_push(skb, self->header_length), 0); | ||
476 | } | ||
396 | 477 | ||
397 | /* FIXME: Make macro out of this one */ | 478 | /* FIXME: Make macro out of this one */ |
398 | ((struct irda_skb_cb *)skb->cb)->context = self; | 479 | ((struct irda_skb_cb *)skb->cb)->context = self; |
@@ -795,7 +876,7 @@ static void irda_usb_receive(struct urb *urb, struct pt_regs *regs) | |||
795 | } | 876 | } |
796 | 877 | ||
797 | /* Check for empty frames */ | 878 | /* Check for empty frames */ |
798 | if (urb->actual_length <= USB_IRDA_HEADER) { | 879 | if (urb->actual_length <= self->header_length) { |
799 | IRDA_WARNING("%s(), empty frame!\n", __FUNCTION__); | 880 | IRDA_WARNING("%s(), empty frame!\n", __FUNCTION__); |
800 | goto done; | 881 | goto done; |
801 | } | 882 | } |
@@ -816,7 +897,11 @@ static void irda_usb_receive(struct urb *urb, struct pt_regs *regs) | |||
816 | docopy = (urb->actual_length < IRDA_RX_COPY_THRESHOLD); | 897 | docopy = (urb->actual_length < IRDA_RX_COPY_THRESHOLD); |
817 | 898 | ||
818 | /* Allocate a new skb */ | 899 | /* Allocate a new skb */ |
819 | newskb = dev_alloc_skb(docopy ? urb->actual_length : IRDA_SKB_MAX_MTU); | 900 | if ( self->capability & IUC_STIR_4210 ) |
901 | newskb = dev_alloc_skb(docopy ? urb->actual_length : IRDA_SKB_MAX_MTU + USB_IRDA_SIGMATEL_HEADER); | ||
902 | else | ||
903 | newskb = dev_alloc_skb(docopy ? urb->actual_length : IRDA_SKB_MAX_MTU); | ||
904 | |||
820 | if (!newskb) { | 905 | if (!newskb) { |
821 | self->stats.rx_dropped++; | 906 | self->stats.rx_dropped++; |
822 | /* We could deliver the current skb, but this would stall | 907 | /* We could deliver the current skb, but this would stall |
@@ -845,7 +930,7 @@ static void irda_usb_receive(struct urb *urb, struct pt_regs *regs) | |||
845 | 930 | ||
846 | /* Set proper length on skb & remove USB-IrDA header */ | 931 | /* Set proper length on skb & remove USB-IrDA header */ |
847 | skb_put(dataskb, urb->actual_length); | 932 | skb_put(dataskb, urb->actual_length); |
848 | skb_pull(dataskb, USB_IRDA_HEADER); | 933 | skb_pull(dataskb, self->header_length); |
849 | 934 | ||
850 | /* Ask the networking layer to queue the packet for the IrDA stack */ | 935 | /* Ask the networking layer to queue the packet for the IrDA stack */ |
851 | dataskb->dev = self->netdev; | 936 | dataskb->dev = self->netdev; |
@@ -937,6 +1022,191 @@ static int irda_usb_is_receiving(struct irda_usb_cb *self) | |||
937 | return 0; /* For now */ | 1022 | return 0; /* For now */ |
938 | } | 1023 | } |
939 | 1024 | ||
1025 | |||
1026 | #define STIR421X_PATCH_PRODUCT_VERSION_STR "Product Version: " | ||
1027 | #define STIR421X_PATCH_COMPONENT_VERSION_STR "Component Version: " | ||
1028 | #define STIR421X_PATCH_DATA_TAG_STR "STMP" | ||
1029 | #define STIR421X_PATCH_FILE_VERSION_MAX_OFFSET 512 /* version info is before here */ | ||
1030 | #define STIR421X_PATCH_FILE_IMAGE_MAX_OFFSET 512 /* patch image starts before here */ | ||
1031 | #define STIR421X_PATCH_FILE_END_OF_HEADER_TAG 0x1A /* marks end of patch file header (PC DOS text file EOF character) */ | ||
1032 | |||
1033 | /* | ||
1034 | * Known firmware patches for STIR421x dongles | ||
1035 | */ | ||
1036 | static char * stir421x_patches[] = { | ||
1037 | "42101001.sb", | ||
1038 | "42101002.sb", | ||
1039 | }; | ||
1040 | |||
1041 | static int stir421x_get_patch_version(unsigned char * patch, const unsigned long patch_len) | ||
1042 | { | ||
1043 | unsigned int version_offset; | ||
1044 | unsigned long version_major, version_minor, version_build; | ||
1045 | unsigned char * version_start; | ||
1046 | int version_found = 0; | ||
1047 | |||
1048 | for (version_offset = 0; | ||
1049 | version_offset < STIR421X_PATCH_FILE_END_OF_HEADER_TAG; | ||
1050 | version_offset++) { | ||
1051 | if (!memcmp(patch + version_offset, | ||
1052 | STIR421X_PATCH_PRODUCT_VERSION_STR, | ||
1053 | sizeof(STIR421X_PATCH_PRODUCT_VERSION_STR) - 1)) { | ||
1054 | version_found = 1; | ||
1055 | version_start = patch + | ||
1056 | version_offset + | ||
1057 | sizeof(STIR421X_PATCH_PRODUCT_VERSION_STR) - 1; | ||
1058 | break; | ||
1059 | } | ||
1060 | } | ||
1061 | |||
1062 | /* We couldn't find a product version on this patch */ | ||
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 | |||
1087 | static 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 | |||
1138 | |||
1139 | static int stir421x_patch_device(struct irda_usb_cb *self) | ||
1140 | { | ||
1141 | unsigned int i, patch_found = 0, data_found = 0, data_offset; | ||
1142 | int patch_version, ret = 0; | ||
1143 | const struct firmware *fw_entry; | ||
1144 | |||
1145 | for (i = 0; i < ARRAY_SIZE(stir421x_patches); i++) { | ||
1146 | if(request_firmware(&fw_entry, stir421x_patches[i], &self->usbdev->dev) != 0) { | ||
1147 | IRDA_ERROR( "%s(), Patch %s is not available\n", __FUNCTION__, stir421x_patches[i]); | ||
1148 | continue; | ||
1149 | } | ||
1150 | |||
1151 | /* We found a patch from userspace */ | ||
1152 | patch_version = stir421x_get_patch_version (fw_entry->data, fw_entry->size); | ||
1153 | |||
1154 | if (patch_version < 0) { | ||
1155 | /* Couldn't fetch a version, let's move on to the next file */ | ||
1156 | IRDA_ERROR("%s(), version parsing failed\n", __FUNCTION__); | ||
1157 | ret = patch_version; | ||
1158 | release_firmware(fw_entry); | ||
1159 | continue; | ||
1160 | } | ||
1161 | |||
1162 | if (patch_version != self->usbdev->descriptor.bcdDevice) { | ||
1163 | /* Patch version and device don't match */ | ||
1164 | IRDA_ERROR ("%s(), wrong patch version (%d <-> %d)\n", | ||
1165 | __FUNCTION__, | ||
1166 | patch_version, self->usbdev->descriptor.bcdDevice); | ||
1167 | ret = -EINVAL; | ||
1168 | release_firmware(fw_entry); | ||
1169 | continue; | ||
1170 | } | ||
1171 | |||
1172 | /* If we're here, we've found a correct patch */ | ||
1173 | patch_found = 1; | ||
1174 | break; | ||
1175 | |||
1176 | } | ||
1177 | |||
1178 | /* We couldn't find a valid firmware, let's leave */ | ||
1179 | if (!patch_found) | ||
1180 | return ret; | ||
1181 | |||
1182 | /* The actual image starts after the "STMP" keyword */ | ||
1183 | for (data_offset = 0; data_offset < STIR421X_PATCH_FILE_IMAGE_MAX_OFFSET; data_offset++) { | ||
1184 | if (!memcmp(fw_entry->data + data_offset, | ||
1185 | STIR421X_PATCH_DATA_TAG_STR, | ||
1186 | sizeof(STIR421X_PATCH_FILE_IMAGE_MAX_OFFSET))) { | ||
1187 | IRDA_DEBUG(2, "%s(), found patch data for STIR421x at offset %d\n", | ||
1188 | __FUNCTION__, data_offset); | ||
1189 | data_found = 1; | ||
1190 | break; | ||
1191 | } | ||
1192 | } | ||
1193 | |||
1194 | /* We couldn't find "STMP" from the header */ | ||
1195 | if (!data_found) | ||
1196 | return -EINVAL; | ||
1197 | |||
1198 | /* Let's upload the patch to the target */ | ||
1199 | ret = stir421x_upload_patch(self, | ||
1200 | &fw_entry->data[data_offset + sizeof(STIR421X_PATCH_FILE_IMAGE_MAX_OFFSET)], | ||
1201 | fw_entry->size - (data_offset + sizeof(STIR421X_PATCH_FILE_IMAGE_MAX_OFFSET))); | ||
1202 | |||
1203 | release_firmware(fw_entry); | ||
1204 | |||
1205 | return ret; | ||
1206 | |||
1207 | } | ||
1208 | |||
1209 | |||
940 | /********************** IRDA DEVICE CALLBACKS **********************/ | 1210 | /********************** IRDA DEVICE CALLBACKS **********************/ |
941 | /* | 1211 | /* |
942 | * Main calls from the IrDA/Network subsystem. | 1212 | * Main calls from the IrDA/Network subsystem. |
@@ -972,6 +1242,11 @@ static int irda_usb_net_open(struct net_device *netdev) | |||
972 | return -1; | 1242 | return -1; |
973 | } | 1243 | } |
974 | 1244 | ||
1245 | if(self->needspatch) { | ||
1246 | IRDA_WARNING("%s(), device needs patch\n", __FUNCTION__) ; | ||
1247 | return -EIO ; | ||
1248 | } | ||
1249 | |||
975 | /* Initialise default speed and xbofs value | 1250 | /* Initialise default speed and xbofs value |
976 | * (IrLAP will change that soon) */ | 1251 | * (IrLAP will change that soon) */ |
977 | self->speed = -1; | 1252 | self->speed = -1; |
@@ -1050,7 +1325,7 @@ static int irda_usb_net_close(struct net_device *netdev) | |||
1050 | del_timer(&self->rx_defer_timer); | 1325 | del_timer(&self->rx_defer_timer); |
1051 | 1326 | ||
1052 | /* Deallocate all the Rx path buffers (URBs and skb) */ | 1327 | /* Deallocate all the Rx path buffers (URBs and skb) */ |
1053 | for (i = 0; i < IU_MAX_RX_URBS; i++) { | 1328 | for (i = 0; i < self->max_rx_urb; i++) { |
1054 | struct urb *urb = self->rx_urb[i]; | 1329 | struct urb *urb = self->rx_urb[i]; |
1055 | struct sk_buff *skb = (struct sk_buff *) urb->context; | 1330 | struct sk_buff *skb = (struct sk_buff *) urb->context; |
1056 | /* Cancel the receive command */ | 1331 | /* Cancel the receive command */ |
@@ -1426,8 +1701,22 @@ static int irda_usb_probe(struct usb_interface *intf, | |||
1426 | spin_lock_init(&self->lock); | 1701 | spin_lock_init(&self->lock); |
1427 | init_timer(&self->rx_defer_timer); | 1702 | init_timer(&self->rx_defer_timer); |
1428 | 1703 | ||
1704 | self->capability = id->driver_info; | ||
1705 | self->needspatch = ((self->capability & IUC_STIR_4210) != 0) ; | ||
1706 | |||
1429 | /* Create all of the needed urbs */ | 1707 | /* Create all of the needed urbs */ |
1430 | for (i = 0; i < IU_MAX_RX_URBS; i++) { | 1708 | if (self->capability & IUC_STIR_4210) { |
1709 | self->max_rx_urb = IU_SIGMATEL_MAX_RX_URBS; | ||
1710 | self->header_length = USB_IRDA_SIGMATEL_HEADER; | ||
1711 | } else { | ||
1712 | self->max_rx_urb = IU_MAX_RX_URBS; | ||
1713 | self->header_length = USB_IRDA_HEADER; | ||
1714 | } | ||
1715 | |||
1716 | self->rx_urb = kzalloc(self->max_rx_urb * sizeof(struct urb *), | ||
1717 | GFP_KERNEL); | ||
1718 | |||
1719 | for (i = 0; i < self->max_rx_urb; i++) { | ||
1431 | self->rx_urb[i] = usb_alloc_urb(0, GFP_KERNEL); | 1720 | self->rx_urb[i] = usb_alloc_urb(0, GFP_KERNEL); |
1432 | if (!self->rx_urb[i]) { | 1721 | if (!self->rx_urb[i]) { |
1433 | goto err_out_1; | 1722 | goto err_out_1; |
@@ -1479,17 +1768,28 @@ static int irda_usb_probe(struct usb_interface *intf, | |||
1479 | goto err_out_3; | 1768 | goto err_out_3; |
1480 | } | 1769 | } |
1481 | 1770 | ||
1771 | self->usbdev = dev; | ||
1772 | |||
1482 | /* Find IrDA class descriptor */ | 1773 | /* Find IrDA class descriptor */ |
1483 | irda_desc = irda_usb_find_class_desc(intf); | 1774 | irda_desc = irda_usb_find_class_desc(intf); |
1484 | ret = -ENODEV; | 1775 | ret = -ENODEV; |
1485 | if (irda_desc == NULL) | 1776 | if (irda_desc == NULL) |
1486 | goto err_out_3; | 1777 | goto err_out_3; |
1487 | 1778 | ||
1779 | if (self->needspatch) { | ||
1780 | ret = usb_control_msg (self->usbdev, usb_sndctrlpipe (self->usbdev, 0), | ||
1781 | 0x02, 0x40, 0, 0, 0, 0, msecs_to_jiffies(500)); | ||
1782 | if (ret < 0) { | ||
1783 | IRDA_DEBUG (0, "usb_control_msg failed %d\n", ret); | ||
1784 | goto err_out_3; | ||
1785 | } else { | ||
1786 | mdelay(10); | ||
1787 | } | ||
1788 | } | ||
1789 | |||
1488 | self->irda_desc = irda_desc; | 1790 | self->irda_desc = irda_desc; |
1489 | self->present = 1; | 1791 | self->present = 1; |
1490 | self->netopen = 0; | 1792 | self->netopen = 0; |
1491 | self->capability = id->driver_info; | ||
1492 | self->usbdev = dev; | ||
1493 | self->usbintf = intf; | 1793 | self->usbintf = intf; |
1494 | 1794 | ||
1495 | /* Allocate the buffer for speed changes */ | 1795 | /* Allocate the buffer for speed changes */ |
@@ -1508,6 +1808,28 @@ static int irda_usb_probe(struct usb_interface *intf, | |||
1508 | 1808 | ||
1509 | IRDA_MESSAGE("IrDA: Registered device %s\n", net->name); | 1809 | IRDA_MESSAGE("IrDA: Registered device %s\n", net->name); |
1510 | usb_set_intfdata(intf, self); | 1810 | usb_set_intfdata(intf, self); |
1811 | |||
1812 | if (self->needspatch) { | ||
1813 | /* Now we fetch and upload the firmware patch */ | ||
1814 | ret = stir421x_patch_device(self); | ||
1815 | self->needspatch = (ret < 0); | ||
1816 | if (ret < 0) { | ||
1817 | printk("patch_device failed\n"); | ||
1818 | goto err_out_4; | ||
1819 | } | ||
1820 | |||
1821 | /* replace IrDA class descriptor with what patched device is now reporting */ | ||
1822 | irda_desc = irda_usb_find_class_desc (self->usbintf); | ||
1823 | if (irda_desc == NULL) { | ||
1824 | ret = -ENODEV; | ||
1825 | goto err_out_4; | ||
1826 | } | ||
1827 | if (self->irda_desc) | ||
1828 | kfree (self->irda_desc); | ||
1829 | self->irda_desc = irda_desc; | ||
1830 | irda_usb_init_qos(self); | ||
1831 | } | ||
1832 | |||
1511 | return 0; | 1833 | return 0; |
1512 | 1834 | ||
1513 | err_out_4: | 1835 | err_out_4: |
@@ -1518,7 +1840,7 @@ err_out_3: | |||
1518 | err_out_2: | 1840 | err_out_2: |
1519 | usb_free_urb(self->tx_urb); | 1841 | usb_free_urb(self->tx_urb); |
1520 | err_out_1: | 1842 | err_out_1: |
1521 | for (i = 0; i < IU_MAX_RX_URBS; i++) { | 1843 | for (i = 0; i < self->max_rx_urb; i++) { |
1522 | if (self->rx_urb[i]) | 1844 | if (self->rx_urb[i]) |
1523 | usb_free_urb(self->rx_urb[i]); | 1845 | usb_free_urb(self->rx_urb[i]); |
1524 | } | 1846 | } |
@@ -1571,7 +1893,7 @@ static void irda_usb_disconnect(struct usb_interface *intf) | |||
1571 | /*netif_device_detach(self->netdev);*/ | 1893 | /*netif_device_detach(self->netdev);*/ |
1572 | netif_stop_queue(self->netdev); | 1894 | netif_stop_queue(self->netdev); |
1573 | /* Stop all the receive URBs. Must be synchronous. */ | 1895 | /* Stop all the receive URBs. Must be synchronous. */ |
1574 | for (i = 0; i < IU_MAX_RX_URBS; i++) | 1896 | for (i = 0; i < self->max_rx_urb; i++) |
1575 | usb_kill_urb(self->rx_urb[i]); | 1897 | usb_kill_urb(self->rx_urb[i]); |
1576 | /* Cancel Tx and speed URB. | 1898 | /* Cancel Tx and speed URB. |
1577 | * Make sure it's synchronous to avoid races. */ | 1899 | * Make sure it's synchronous to avoid races. */ |
@@ -1586,8 +1908,9 @@ static void irda_usb_disconnect(struct usb_interface *intf) | |||
1586 | self->usbintf = NULL; | 1908 | self->usbintf = NULL; |
1587 | 1909 | ||
1588 | /* Clean up our urbs */ | 1910 | /* Clean up our urbs */ |
1589 | for (i = 0; i < IU_MAX_RX_URBS; i++) | 1911 | for (i = 0; i < self->max_rx_urb; i++) |
1590 | usb_free_urb(self->rx_urb[i]); | 1912 | usb_free_urb(self->rx_urb[i]); |
1913 | kfree(self->rx_urb); | ||
1591 | /* Clean up Tx and speed URB */ | 1914 | /* Clean up Tx and speed URB */ |
1592 | usb_free_urb(self->tx_urb); | 1915 | usb_free_urb(self->tx_urb); |
1593 | usb_free_urb(self->speed_urb); | 1916 | usb_free_urb(self->speed_urb); |
@@ -1648,6 +1971,6 @@ module_exit(usb_irda_cleanup); | |||
1648 | */ | 1971 | */ |
1649 | module_param(qos_mtt_bits, int, 0); | 1972 | module_param(qos_mtt_bits, int, 0); |
1650 | MODULE_PARM_DESC(qos_mtt_bits, "Minimum Turn Time"); | 1973 | MODULE_PARM_DESC(qos_mtt_bits, "Minimum Turn Time"); |
1651 | MODULE_AUTHOR("Roman Weissgaerber <weissg@vienna.at>, Dag Brattli <dag@brattli.net> and Jean Tourrilhes <jt@hpl.hp.com>"); | 1974 | MODULE_AUTHOR("Roman Weissgaerber <weissg@vienna.at>, Dag Brattli <dag@brattli.net>, Jean Tourrilhes <jt@hpl.hp.com> and Nick Fedchik <nick@fedchik.org.ua>"); |
1652 | MODULE_DESCRIPTION("IrDA-USB Dongle Driver"); | 1975 | MODULE_DESCRIPTION("IrDA-USB Dongle Driver"); |
1653 | MODULE_LICENSE("GPL"); | 1976 | MODULE_LICENSE("GPL"); |