diff options
Diffstat (limited to 'drivers/net/irda')
-rw-r--r-- | drivers/net/irda/irda-usb.c | 365 | ||||
-rw-r--r-- | drivers/net/irda/irda-usb.h | 43 | ||||
-rw-r--r-- | drivers/net/irda/smsc-ircc2.c | 523 |
3 files changed, 897 insertions, 34 deletions
diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c index 6e2ec56cde0b..96bdb73c2283 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,8 +1808,32 @@ 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_5; | ||
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_5; | ||
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 | ||
1835 | err_out_5: | ||
1836 | unregister_netdev(self->netdev); | ||
1513 | err_out_4: | 1837 | err_out_4: |
1514 | kfree(self->speed_buff); | 1838 | kfree(self->speed_buff); |
1515 | err_out_3: | 1839 | err_out_3: |
@@ -1518,7 +1842,7 @@ err_out_3: | |||
1518 | err_out_2: | 1842 | err_out_2: |
1519 | usb_free_urb(self->tx_urb); | 1843 | usb_free_urb(self->tx_urb); |
1520 | err_out_1: | 1844 | err_out_1: |
1521 | for (i = 0; i < IU_MAX_RX_URBS; i++) { | 1845 | for (i = 0; i < self->max_rx_urb; i++) { |
1522 | if (self->rx_urb[i]) | 1846 | if (self->rx_urb[i]) |
1523 | usb_free_urb(self->rx_urb[i]); | 1847 | usb_free_urb(self->rx_urb[i]); |
1524 | } | 1848 | } |
@@ -1571,7 +1895,7 @@ static void irda_usb_disconnect(struct usb_interface *intf) | |||
1571 | /*netif_device_detach(self->netdev);*/ | 1895 | /*netif_device_detach(self->netdev);*/ |
1572 | netif_stop_queue(self->netdev); | 1896 | netif_stop_queue(self->netdev); |
1573 | /* Stop all the receive URBs. Must be synchronous. */ | 1897 | /* Stop all the receive URBs. Must be synchronous. */ |
1574 | for (i = 0; i < IU_MAX_RX_URBS; i++) | 1898 | for (i = 0; i < self->max_rx_urb; i++) |
1575 | usb_kill_urb(self->rx_urb[i]); | 1899 | usb_kill_urb(self->rx_urb[i]); |
1576 | /* Cancel Tx and speed URB. | 1900 | /* Cancel Tx and speed URB. |
1577 | * Make sure it's synchronous to avoid races. */ | 1901 | * Make sure it's synchronous to avoid races. */ |
@@ -1586,8 +1910,9 @@ static void irda_usb_disconnect(struct usb_interface *intf) | |||
1586 | self->usbintf = NULL; | 1910 | self->usbintf = NULL; |
1587 | 1911 | ||
1588 | /* Clean up our urbs */ | 1912 | /* Clean up our urbs */ |
1589 | for (i = 0; i < IU_MAX_RX_URBS; i++) | 1913 | for (i = 0; i < self->max_rx_urb; i++) |
1590 | usb_free_urb(self->rx_urb[i]); | 1914 | usb_free_urb(self->rx_urb[i]); |
1915 | kfree(self->rx_urb); | ||
1591 | /* Clean up Tx and speed URB */ | 1916 | /* Clean up Tx and speed URB */ |
1592 | usb_free_urb(self->tx_urb); | 1917 | usb_free_urb(self->tx_urb); |
1593 | usb_free_urb(self->speed_urb); | 1918 | usb_free_urb(self->speed_urb); |
@@ -1648,6 +1973,6 @@ module_exit(usb_irda_cleanup); | |||
1648 | */ | 1973 | */ |
1649 | module_param(qos_mtt_bits, int, 0); | 1974 | module_param(qos_mtt_bits, int, 0); |
1650 | MODULE_PARM_DESC(qos_mtt_bits, "Minimum Turn Time"); | 1975 | 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>"); | 1976 | 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"); | 1977 | MODULE_DESCRIPTION("IrDA-USB Dongle Driver"); |
1653 | MODULE_LICENSE("GPL"); | 1978 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/net/irda/irda-usb.h b/drivers/net/irda/irda-usb.h index 4026af42dd47..d833db52cebf 100644 --- a/drivers/net/irda/irda-usb.h +++ b/drivers/net/irda/irda-usb.h | |||
@@ -1,7 +1,7 @@ | |||
1 | /***************************************************************************** | 1 | /***************************************************************************** |
2 | * | 2 | * |
3 | * Filename: irda-usb.h | 3 | * Filename: irda-usb.h |
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) 2001, Roman Weissgaerber <weissg@vienna.at> | 9 | * Copyright (C) 2001, Roman Weissgaerber <weissg@vienna.at> |
10 | * Copyright (C) 2000, Dag Brattli <dag@brattli.net> | 10 | * Copyright (C) 2000, 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 |
@@ -31,6 +34,9 @@ | |||
31 | #include <net/irda/irda.h> | 34 | #include <net/irda/irda.h> |
32 | #include <net/irda/irda_device.h> /* struct irlap_cb */ | 35 | #include <net/irda/irda_device.h> /* struct irlap_cb */ |
33 | 36 | ||
37 | #define PATCH_FILE_SIZE_MAX 65536 | ||
38 | #define PATCH_FILE_SIZE_MIN 80 | ||
39 | |||
34 | #define RX_COPY_THRESHOLD 200 | 40 | #define RX_COPY_THRESHOLD 200 |
35 | #define IRDA_USB_MAX_MTU 2051 | 41 | #define IRDA_USB_MAX_MTU 2051 |
36 | #define IRDA_USB_SPEED_MTU 64 /* Weird, but work like this */ | 42 | #define IRDA_USB_SPEED_MTU 64 /* Weird, but work like this */ |
@@ -79,15 +85,16 @@ | |||
79 | /* Inbound header */ | 85 | /* Inbound header */ |
80 | #define MEDIA_BUSY 0x80 | 86 | #define MEDIA_BUSY 0x80 |
81 | 87 | ||
82 | #define SPEED_2400 0x01 | 88 | #define SPEED_2400 0x01 |
83 | #define SPEED_9600 0x02 | 89 | #define SPEED_9600 0x02 |
84 | #define SPEED_19200 0x03 | 90 | #define SPEED_19200 0x03 |
85 | #define SPEED_38400 0x04 | 91 | #define SPEED_38400 0x04 |
86 | #define SPEED_57600 0x05 | 92 | #define SPEED_57600 0x05 |
87 | #define SPEED_115200 0x06 | 93 | #define SPEED_115200 0x06 |
88 | #define SPEED_576000 0x07 | 94 | #define SPEED_576000 0x07 |
89 | #define SPEED_1152000 0x08 | 95 | #define SPEED_1152000 0x08 |
90 | #define SPEED_4000000 0x09 | 96 | #define SPEED_4000000 0x09 |
97 | #define SPEED_16000000 0x0a | ||
91 | 98 | ||
92 | /* Basic capabilities */ | 99 | /* Basic capabilities */ |
93 | #define IUC_DEFAULT 0x00 /* Basic device compliant with 1.0 spec */ | 100 | #define IUC_DEFAULT 0x00 /* Basic device compliant with 1.0 spec */ |
@@ -100,11 +107,14 @@ | |||
100 | #define IUC_SMALL_PKT 0x10 /* Device doesn't behave with big Rx packets */ | 107 | #define IUC_SMALL_PKT 0x10 /* Device doesn't behave with big Rx packets */ |
101 | #define IUC_MAX_WINDOW 0x20 /* Device underestimate the Rx window */ | 108 | #define IUC_MAX_WINDOW 0x20 /* Device underestimate the Rx window */ |
102 | #define IUC_MAX_XBOFS 0x40 /* Device need more xbofs than advertised */ | 109 | #define IUC_MAX_XBOFS 0x40 /* Device need more xbofs than advertised */ |
110 | #define IUC_STIR_4210 0x80 /* SigmaTel 4210/4220/4116 VFIR */ | ||
103 | 111 | ||
104 | /* USB class definitions */ | 112 | /* USB class definitions */ |
105 | #define USB_IRDA_HEADER 0x01 | 113 | #define USB_IRDA_HEADER 0x01 |
106 | #define USB_CLASS_IRDA 0x02 /* USB_CLASS_APP_SPEC subclass */ | 114 | #define USB_CLASS_IRDA 0x02 /* USB_CLASS_APP_SPEC subclass */ |
107 | #define USB_DT_IRDA 0x21 | 115 | #define USB_DT_IRDA 0x21 |
116 | #define USB_IRDA_SIGMATEL_HEADER 0x03 | ||
117 | #define IU_SIGMATEL_MAX_RX_URBS (IU_MAX_ACTIVE_RX_URBS + USB_IRDA_SIGMATEL_HEADER) | ||
108 | 118 | ||
109 | struct irda_class_desc { | 119 | struct irda_class_desc { |
110 | __u8 bLength; | 120 | __u8 bLength; |
@@ -123,6 +133,7 @@ struct irda_class_desc { | |||
123 | * (6.2.5, USB-IrDA class spec 1.0) */ | 133 | * (6.2.5, USB-IrDA class spec 1.0) */ |
124 | 134 | ||
125 | #define IU_REQ_GET_CLASS_DESC 0x06 | 135 | #define IU_REQ_GET_CLASS_DESC 0x06 |
136 | #define STIR421X_MAX_PATCH_DOWNLOAD_SIZE 1023 | ||
126 | 137 | ||
127 | struct irda_usb_cb { | 138 | struct irda_usb_cb { |
128 | struct irda_class_desc *irda_desc; | 139 | struct irda_class_desc *irda_desc; |
@@ -136,7 +147,8 @@ struct irda_usb_cb { | |||
136 | __u16 bulk_out_mtu; /* Max Tx packet size in bytes */ | 147 | __u16 bulk_out_mtu; /* Max Tx packet size in bytes */ |
137 | __u8 bulk_int_ep; /* Interrupt Endpoint assignments */ | 148 | __u8 bulk_int_ep; /* Interrupt Endpoint assignments */ |
138 | 149 | ||
139 | struct urb *rx_urb[IU_MAX_RX_URBS]; /* URBs used to receive data frames */ | 150 | __u8 max_rx_urb; |
151 | struct urb **rx_urb; /* URBs used to receive data frames */ | ||
140 | struct urb *idle_rx_urb; /* Pointer to idle URB in Rx path */ | 152 | struct urb *idle_rx_urb; /* Pointer to idle URB in Rx path */ |
141 | struct urb *tx_urb; /* URB used to send data frames */ | 153 | struct urb *tx_urb; /* URB used to send data frames */ |
142 | struct urb *speed_urb; /* URB used to send speed commands */ | 154 | struct urb *speed_urb; /* URB used to send speed commands */ |
@@ -157,6 +169,9 @@ struct irda_usb_cb { | |||
157 | __u32 speed; /* Current speed */ | 169 | __u32 speed; /* Current speed */ |
158 | __s32 new_speed; /* speed we need to set */ | 170 | __s32 new_speed; /* speed we need to set */ |
159 | 171 | ||
172 | __u8 header_length; /* USB-IrDA frame header size */ | ||
173 | int needspatch; /* device needs firmware patch */ | ||
174 | |||
160 | struct timer_list rx_defer_timer; /* Wait for Rx error to clear */ | 175 | struct timer_list rx_defer_timer; /* Wait for Rx error to clear */ |
161 | }; | 176 | }; |
162 | 177 | ||
diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c index ec94ecdb103d..58f76cefbc83 100644 --- a/drivers/net/irda/smsc-ircc2.c +++ b/drivers/net/irda/smsc-ircc2.c | |||
@@ -11,6 +11,7 @@ | |||
11 | * Copyright (c) 2002 Daniele Peri | 11 | * Copyright (c) 2002 Daniele Peri |
12 | * All Rights Reserved. | 12 | * All Rights Reserved. |
13 | * Copyright (c) 2002 Jean Tourrilhes | 13 | * Copyright (c) 2002 Jean Tourrilhes |
14 | * Copyright (c) 2006 Linus Walleij | ||
14 | * | 15 | * |
15 | * | 16 | * |
16 | * Based on smc-ircc.c: | 17 | * Based on smc-ircc.c: |
@@ -61,6 +62,9 @@ | |||
61 | 62 | ||
62 | #include <linux/spinlock.h> | 63 | #include <linux/spinlock.h> |
63 | #include <linux/pm.h> | 64 | #include <linux/pm.h> |
65 | #ifdef CONFIG_PCI | ||
66 | #include <linux/pci.h> | ||
67 | #endif | ||
64 | 68 | ||
65 | #include <net/irda/wrapper.h> | 69 | #include <net/irda/wrapper.h> |
66 | #include <net/irda/irda.h> | 70 | #include <net/irda/irda.h> |
@@ -100,6 +104,22 @@ MODULE_PARM_DESC(ircc_transceiver, "Transceiver type"); | |||
100 | 104 | ||
101 | /* Types */ | 105 | /* Types */ |
102 | 106 | ||
107 | #ifdef CONFIG_PCI | ||
108 | struct smsc_ircc_subsystem_configuration { | ||
109 | unsigned short vendor; /* PCI vendor ID */ | ||
110 | unsigned short device; /* PCI vendor ID */ | ||
111 | unsigned short subvendor; /* PCI subsystem vendor ID */ | ||
112 | unsigned short subdevice; /* PCI sybsystem device ID */ | ||
113 | unsigned short sir_io; /* I/O port for SIR */ | ||
114 | unsigned short fir_io; /* I/O port for FIR */ | ||
115 | unsigned char fir_irq; /* FIR IRQ */ | ||
116 | unsigned char fir_dma; /* FIR DMA */ | ||
117 | unsigned short cfg_base; /* I/O port for chip configuration */ | ||
118 | int (*preconfigure)(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf); /* Preconfig function */ | ||
119 | const char *name; /* name shown as info */ | ||
120 | }; | ||
121 | #endif | ||
122 | |||
103 | struct smsc_transceiver { | 123 | struct smsc_transceiver { |
104 | char *name; | 124 | char *name; |
105 | void (*set_for_speed)(int fir_base, u32 speed); | 125 | void (*set_for_speed)(int fir_base, u32 speed); |
@@ -202,6 +222,18 @@ static int __init smsc_superio_flat(const struct smsc_chip *chips, unsigned shor | |||
202 | static int __init smsc_superio_paged(const struct smsc_chip *chips, unsigned short cfg_base, char *type); | 222 | static int __init smsc_superio_paged(const struct smsc_chip *chips, unsigned short cfg_base, char *type); |
203 | static int __init smsc_superio_fdc(unsigned short cfg_base); | 223 | static int __init smsc_superio_fdc(unsigned short cfg_base); |
204 | static int __init smsc_superio_lpc(unsigned short cfg_base); | 224 | static int __init smsc_superio_lpc(unsigned short cfg_base); |
225 | #ifdef CONFIG_PCI | ||
226 | static int __init preconfigure_smsc_chip(struct smsc_ircc_subsystem_configuration *conf); | ||
227 | static int __init preconfigure_through_82801(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf); | ||
228 | static void __init preconfigure_ali_port(struct pci_dev *dev, | ||
229 | unsigned short port); | ||
230 | static int __init preconfigure_through_ali(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf); | ||
231 | static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg, | ||
232 | unsigned short ircc_fir, | ||
233 | unsigned short ircc_sir, | ||
234 | unsigned char ircc_dma, | ||
235 | unsigned char ircc_irq); | ||
236 | #endif | ||
205 | 237 | ||
206 | /* Transceivers specific functions */ | 238 | /* Transceivers specific functions */ |
207 | 239 | ||
@@ -353,6 +385,13 @@ static int __init smsc_ircc_init(void) | |||
353 | return ret; | 385 | return ret; |
354 | } | 386 | } |
355 | 387 | ||
388 | #ifdef CONFIG_PCI | ||
389 | if (smsc_ircc_preconfigure_subsystems(ircc_cfg, ircc_fir, ircc_sir, ircc_dma, ircc_irq) < 0) { | ||
390 | /* Ignore errors from preconfiguration */ | ||
391 | IRDA_ERROR("%s, Preconfiguration failed !\n", driver_name); | ||
392 | } | ||
393 | #endif | ||
394 | |||
356 | dev_count = 0; | 395 | dev_count = 0; |
357 | 396 | ||
358 | if (ircc_fir > 0 && ircc_sir > 0) { | 397 | if (ircc_fir > 0 && ircc_sir > 0) { |
@@ -2285,6 +2324,490 @@ static int __init smsc_superio_lpc(unsigned short cfg_base) | |||
2285 | return ret; | 2324 | return ret; |
2286 | } | 2325 | } |
2287 | 2326 | ||
2327 | /* | ||
2328 | * Look for some specific subsystem setups that need | ||
2329 | * pre-configuration not properly done by the BIOS (especially laptops) | ||
2330 | * This code is based in part on smcinit.c, tosh1800-smcinit.c | ||
2331 | * and tosh2450-smcinit.c. The table lists the device entries | ||
2332 | * for ISA bridges with an LPC (Low Pin Count) controller which | ||
2333 | * handles the communication with the SMSC device. After the LPC | ||
2334 | * controller is initialized through PCI, the SMSC device is initialized | ||
2335 | * through a dedicated port in the ISA port-mapped I/O area, this latter | ||
2336 | * area is used to configure the SMSC device with default | ||
2337 | * SIR and FIR I/O ports, DMA and IRQ. Different vendors have | ||
2338 | * used different sets of parameters and different control port | ||
2339 | * addresses making a subsystem device table necessary. | ||
2340 | */ | ||
2341 | #ifdef CONFIG_PCI | ||
2342 | #define PCIID_VENDOR_INTEL 0x8086 | ||
2343 | #define PCIID_VENDOR_ALI 0x10b9 | ||
2344 | static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __devinitdata = { | ||
2345 | { | ||
2346 | .vendor = PCIID_VENDOR_INTEL, /* Intel 82801DBM LPC bridge */ | ||
2347 | .device = 0x24cc, | ||
2348 | .subvendor = 0x103c, | ||
2349 | .subdevice = 0x088c, | ||
2350 | /* Quite certain these are the same for nc8000 as for nc6000 */ | ||
2351 | .sir_io = 0x02f8, | ||
2352 | .fir_io = 0x0130, | ||
2353 | .fir_irq = 0x05, | ||
2354 | .fir_dma = 0x03, | ||
2355 | .cfg_base = 0x004e, | ||
2356 | .preconfigure = preconfigure_through_82801, | ||
2357 | .name = "HP nc8000", | ||
2358 | }, | ||
2359 | { | ||
2360 | .vendor = PCIID_VENDOR_INTEL, /* Intel 82801DBM LPC bridge */ | ||
2361 | .device = 0x24cc, | ||
2362 | .subvendor = 0x103c, | ||
2363 | .subdevice = 0x0890, | ||
2364 | .sir_io = 0x02f8, | ||
2365 | .fir_io = 0x0130, | ||
2366 | .fir_irq = 0x05, | ||
2367 | .fir_dma = 0x03, | ||
2368 | .cfg_base = 0x004e, | ||
2369 | .preconfigure = preconfigure_through_82801, | ||
2370 | .name = "HP nc6000", | ||
2371 | }, | ||
2372 | { | ||
2373 | /* Intel 82801DB/DBL (ICH4/ICH4-L) LPC Interface Bridge */ | ||
2374 | .vendor = PCIID_VENDOR_INTEL, | ||
2375 | .device = 0x24c0, | ||
2376 | .subvendor = 0x1179, | ||
2377 | .subdevice = 0xffff, /* 0xffff is "any" */ | ||
2378 | .sir_io = 0x03f8, | ||
2379 | .fir_io = 0x0130, | ||
2380 | .fir_irq = 0x07, | ||
2381 | .fir_dma = 0x01, | ||
2382 | .cfg_base = 0x002e, | ||
2383 | .preconfigure = preconfigure_through_82801, | ||
2384 | .name = "Toshiba laptop with Intel 82801DB/DBL LPC bridge", | ||
2385 | }, | ||
2386 | { | ||
2387 | .vendor = PCIID_VENDOR_INTEL, /* Intel 82801CAM ISA bridge */ | ||
2388 | .device = 0x248c, | ||
2389 | .subvendor = 0x1179, | ||
2390 | .subdevice = 0xffff, /* 0xffff is "any" */ | ||
2391 | .sir_io = 0x03f8, | ||
2392 | .fir_io = 0x0130, | ||
2393 | .fir_irq = 0x03, | ||
2394 | .fir_dma = 0x03, | ||
2395 | .cfg_base = 0x002e, | ||
2396 | .preconfigure = preconfigure_through_82801, | ||
2397 | .name = "Toshiba laptop with Intel 82801CAM ISA bridge", | ||
2398 | }, | ||
2399 | { | ||
2400 | /* 82801DBM (ICH4-M) LPC Interface Bridge */ | ||
2401 | .vendor = PCIID_VENDOR_INTEL, | ||
2402 | .device = 0x24cc, | ||
2403 | .subvendor = 0x1179, | ||
2404 | .subdevice = 0xffff, /* 0xffff is "any" */ | ||
2405 | .sir_io = 0x03f8, | ||
2406 | .fir_io = 0x0130, | ||
2407 | .fir_irq = 0x03, | ||
2408 | .fir_dma = 0x03, | ||
2409 | .cfg_base = 0x002e, | ||
2410 | .preconfigure = preconfigure_through_82801, | ||
2411 | .name = "Toshiba laptop with Intel 8281DBM LPC bridge", | ||
2412 | }, | ||
2413 | { | ||
2414 | /* ALi M1533/M1535 PCI to ISA Bridge [Aladdin IV/V/V+] */ | ||
2415 | .vendor = PCIID_VENDOR_ALI, | ||
2416 | .device = 0x1533, | ||
2417 | .subvendor = 0x1179, | ||
2418 | .subdevice = 0xffff, /* 0xffff is "any" */ | ||
2419 | .sir_io = 0x02e8, | ||
2420 | .fir_io = 0x02f8, | ||
2421 | .fir_irq = 0x07, | ||
2422 | .fir_dma = 0x03, | ||
2423 | .cfg_base = 0x002e, | ||
2424 | .preconfigure = preconfigure_through_ali, | ||
2425 | .name = "Toshiba laptop with ALi ISA bridge", | ||
2426 | }, | ||
2427 | { } // Terminator | ||
2428 | }; | ||
2429 | |||
2430 | |||
2431 | /* | ||
2432 | * This sets up the basic SMSC parameters | ||
2433 | * (FIR port, SIR port, FIR DMA, FIR IRQ) | ||
2434 | * through the chip configuration port. | ||
2435 | */ | ||
2436 | static int __init preconfigure_smsc_chip(struct | ||
2437 | smsc_ircc_subsystem_configuration | ||
2438 | *conf) | ||
2439 | { | ||
2440 | unsigned short iobase = conf->cfg_base; | ||
2441 | unsigned char tmpbyte; | ||
2442 | |||
2443 | outb(LPC47N227_CFGACCESSKEY, iobase); // enter configuration state | ||
2444 | outb(SMSCSIOFLAT_DEVICEID_REG, iobase); // set for device ID | ||
2445 | tmpbyte = inb(iobase +1); // Read device ID | ||
2446 | IRDA_DEBUG(0, | ||
2447 | "Detected Chip id: 0x%02x, setting up registers...\n", | ||
2448 | tmpbyte); | ||
2449 | |||
2450 | /* Disable UART1 and set up SIR I/O port */ | ||
2451 | outb(0x24, iobase); // select CR24 - UART1 base addr | ||
2452 | outb(0x00, iobase + 1); // disable UART1 | ||
2453 | outb(SMSCSIOFLAT_UART2BASEADDR_REG, iobase); // select CR25 - UART2 base addr | ||
2454 | outb( (conf->sir_io >> 2), iobase + 1); // bits 2-9 of 0x3f8 | ||
2455 | tmpbyte = inb(iobase + 1); | ||
2456 | if (tmpbyte != (conf->sir_io >> 2) ) { | ||
2457 | IRDA_WARNING("ERROR: could not configure SIR ioport.\n"); | ||
2458 | IRDA_WARNING("Try to supply ircc_cfg argument.\n"); | ||
2459 | return -ENXIO; | ||
2460 | } | ||
2461 | |||
2462 | /* Set up FIR IRQ channel for UART2 */ | ||
2463 | outb(SMSCSIOFLAT_UARTIRQSELECT_REG, iobase); // select CR28 - UART1,2 IRQ select | ||
2464 | tmpbyte = inb(iobase + 1); | ||
2465 | tmpbyte &= SMSCSIOFLAT_UART1IRQSELECT_MASK; // Do not touch the UART1 portion | ||
2466 | tmpbyte |= (conf->fir_irq & SMSCSIOFLAT_UART2IRQSELECT_MASK); | ||
2467 | outb(tmpbyte, iobase + 1); | ||
2468 | tmpbyte = inb(iobase + 1) & SMSCSIOFLAT_UART2IRQSELECT_MASK; | ||
2469 | if (tmpbyte != conf->fir_irq) { | ||
2470 | IRDA_WARNING("ERROR: could not configure FIR IRQ channel.\n"); | ||
2471 | return -ENXIO; | ||
2472 | } | ||
2473 | |||
2474 | /* Set up FIR I/O port */ | ||
2475 | outb(SMSCSIOFLAT_FIRBASEADDR_REG, iobase); // CR2B - SCE (FIR) base addr | ||
2476 | outb((conf->fir_io >> 3), iobase + 1); | ||
2477 | tmpbyte = inb(iobase + 1); | ||
2478 | if (tmpbyte != (conf->fir_io >> 3) ) { | ||
2479 | IRDA_WARNING("ERROR: could not configure FIR I/O port.\n"); | ||
2480 | return -ENXIO; | ||
2481 | } | ||
2482 | |||
2483 | /* Set up FIR DMA channel */ | ||
2484 | outb(SMSCSIOFLAT_FIRDMASELECT_REG, iobase); // CR2C - SCE (FIR) DMA select | ||
2485 | outb((conf->fir_dma & LPC47N227_FIRDMASELECT_MASK), iobase + 1); // DMA | ||
2486 | tmpbyte = inb(iobase + 1) & LPC47N227_FIRDMASELECT_MASK; | ||
2487 | if (tmpbyte != (conf->fir_dma & LPC47N227_FIRDMASELECT_MASK)) { | ||
2488 | IRDA_WARNING("ERROR: could not configure FIR DMA channel.\n"); | ||
2489 | return -ENXIO; | ||
2490 | } | ||
2491 | |||
2492 | outb(SMSCSIOFLAT_UARTMODE0C_REG, iobase); // CR0C - UART mode | ||
2493 | tmpbyte = inb(iobase + 1); | ||
2494 | tmpbyte &= ~SMSCSIOFLAT_UART2MODE_MASK | | ||
2495 | SMSCSIOFLAT_UART2MODE_VAL_IRDA; | ||
2496 | outb(tmpbyte, iobase + 1); // enable IrDA (HPSIR) mode, high speed | ||
2497 | |||
2498 | outb(LPC47N227_APMBOOTDRIVE_REG, iobase); // CR07 - Auto Pwr Mgt/boot drive sel | ||
2499 | tmpbyte = inb(iobase + 1); | ||
2500 | outb(tmpbyte | LPC47N227_UART2AUTOPWRDOWN_MASK, iobase + 1); // enable UART2 autopower down | ||
2501 | |||
2502 | /* This one was not part of tosh1800 */ | ||
2503 | outb(0x0a, iobase); // CR0a - ecp fifo / ir mux | ||
2504 | tmpbyte = inb(iobase + 1); | ||
2505 | outb(tmpbyte | 0x40, iobase + 1); // send active device to ir port | ||
2506 | |||
2507 | outb(LPC47N227_UART12POWER_REG, iobase); // CR02 - UART 1,2 power | ||
2508 | tmpbyte = inb(iobase + 1); | ||
2509 | outb(tmpbyte | LPC47N227_UART2POWERDOWN_MASK, iobase + 1); // UART2 power up mode, UART1 power down | ||
2510 | |||
2511 | outb(LPC47N227_FDCPOWERVALIDCONF_REG, iobase); // CR00 - FDC Power/valid config cycle | ||
2512 | tmpbyte = inb(iobase + 1); | ||
2513 | outb(tmpbyte | LPC47N227_VALID_MASK, iobase + 1); // valid config cycle done | ||
2514 | |||
2515 | outb(LPC47N227_CFGEXITKEY, iobase); // Exit configuration | ||
2516 | |||
2517 | return 0; | ||
2518 | } | ||
2519 | |||
2520 | /* 82801CAM generic registers */ | ||
2521 | #define VID 0x00 | ||
2522 | #define DID 0x02 | ||
2523 | #define PIRQ_A_D_ROUT 0x60 | ||
2524 | #define SIRQ_CNTL 0x64 | ||
2525 | #define PIRQ_E_H_ROUT 0x68 | ||
2526 | #define PCI_DMA_C 0x90 | ||
2527 | /* LPC-specific registers */ | ||
2528 | #define COM_DEC 0xe0 | ||
2529 | #define GEN1_DEC 0xe4 | ||
2530 | #define LPC_EN 0xe6 | ||
2531 | #define GEN2_DEC 0xec | ||
2532 | /* | ||
2533 | * Sets up the I/O range using the 82801CAM ISA bridge, 82801DBM LPC bridge | ||
2534 | * or Intel 82801DB/DBL (ICH4/ICH4-L) LPC Interface Bridge. | ||
2535 | * They all work the same way! | ||
2536 | */ | ||
2537 | static int __init preconfigure_through_82801(struct pci_dev *dev, | ||
2538 | struct | ||
2539 | smsc_ircc_subsystem_configuration | ||
2540 | *conf) | ||
2541 | { | ||
2542 | unsigned short tmpword; | ||
2543 | unsigned char tmpbyte; | ||
2544 | |||
2545 | IRDA_MESSAGE("Setting up Intel 82801 controller and SMSC device\n"); | ||
2546 | /* | ||
2547 | * Select the range for the COMA COM port (SIR) | ||
2548 | * Register COM_DEC: | ||
2549 | * Bit 7: reserved | ||
2550 | * Bit 6-4, COMB decode range | ||
2551 | * Bit 3: reserved | ||
2552 | * Bit 2-0, COMA decode range | ||
2553 | * | ||
2554 | * Decode ranges: | ||
2555 | * 000 = 0x3f8-0x3ff (COM1) | ||
2556 | * 001 = 0x2f8-0x2ff (COM2) | ||
2557 | * 010 = 0x220-0x227 | ||
2558 | * 011 = 0x228-0x22f | ||
2559 | * 100 = 0x238-0x23f | ||
2560 | * 101 = 0x2e8-0x2ef (COM4) | ||
2561 | * 110 = 0x338-0x33f | ||
2562 | * 111 = 0x3e8-0x3ef (COM3) | ||
2563 | */ | ||
2564 | pci_read_config_byte(dev, COM_DEC, &tmpbyte); | ||
2565 | tmpbyte &= 0xf8; /* mask COMA bits */ | ||
2566 | switch(conf->sir_io) { | ||
2567 | case 0x3f8: | ||
2568 | tmpbyte |= 0x00; | ||
2569 | break; | ||
2570 | case 0x2f8: | ||
2571 | tmpbyte |= 0x01; | ||
2572 | break; | ||
2573 | case 0x220: | ||
2574 | tmpbyte |= 0x02; | ||
2575 | break; | ||
2576 | case 0x228: | ||
2577 | tmpbyte |= 0x03; | ||
2578 | break; | ||
2579 | case 0x238: | ||
2580 | tmpbyte |= 0x04; | ||
2581 | break; | ||
2582 | case 0x2e8: | ||
2583 | tmpbyte |= 0x05; | ||
2584 | break; | ||
2585 | case 0x338: | ||
2586 | tmpbyte |= 0x06; | ||
2587 | break; | ||
2588 | case 0x3e8: | ||
2589 | tmpbyte |= 0x07; | ||
2590 | break; | ||
2591 | default: | ||
2592 | tmpbyte |= 0x01; /* COM2 default */ | ||
2593 | } | ||
2594 | IRDA_DEBUG(1, "COM_DEC (write): 0x%02x\n", tmpbyte); | ||
2595 | pci_write_config_byte(dev, COM_DEC, tmpbyte); | ||
2596 | |||
2597 | /* Enable Low Pin Count interface */ | ||
2598 | pci_read_config_word(dev, LPC_EN, &tmpword); | ||
2599 | /* These seem to be set up at all times, | ||
2600 | * just make sure it is properly set. | ||
2601 | */ | ||
2602 | switch(conf->cfg_base) { | ||
2603 | case 0x04e: | ||
2604 | tmpword |= 0x2000; | ||
2605 | break; | ||
2606 | case 0x02e: | ||
2607 | tmpword |= 0x1000; | ||
2608 | break; | ||
2609 | case 0x062: | ||
2610 | tmpword |= 0x0800; | ||
2611 | break; | ||
2612 | case 0x060: | ||
2613 | tmpword |= 0x0400; | ||
2614 | break; | ||
2615 | default: | ||
2616 | IRDA_WARNING("Uncommon I/O base address: 0x%04x\n", | ||
2617 | conf->cfg_base); | ||
2618 | break; | ||
2619 | } | ||
2620 | tmpword &= 0xfffd; /* disable LPC COMB */ | ||
2621 | tmpword |= 0x0001; /* set bit 0 : enable LPC COMA addr range (GEN2) */ | ||
2622 | IRDA_DEBUG(1, "LPC_EN (write): 0x%04x\n", tmpword); | ||
2623 | pci_write_config_word(dev, LPC_EN, tmpword); | ||
2624 | |||
2625 | /* | ||
2626 | * Configure LPC DMA channel | ||
2627 | * PCI_DMA_C bits: | ||
2628 | * Bit 15-14: DMA channel 7 select | ||
2629 | * Bit 13-12: DMA channel 6 select | ||
2630 | * Bit 11-10: DMA channel 5 select | ||
2631 | * Bit 9-8: Reserved | ||
2632 | * Bit 7-6: DMA channel 3 select | ||
2633 | * Bit 5-4: DMA channel 2 select | ||
2634 | * Bit 3-2: DMA channel 1 select | ||
2635 | * Bit 1-0: DMA channel 0 select | ||
2636 | * 00 = Reserved value | ||
2637 | * 01 = PC/PCI DMA | ||
2638 | * 10 = Reserved value | ||
2639 | * 11 = LPC I/F DMA | ||
2640 | */ | ||
2641 | pci_read_config_word(dev, PCI_DMA_C, &tmpword); | ||
2642 | switch(conf->fir_dma) { | ||
2643 | case 0x07: | ||
2644 | tmpword |= 0xc000; | ||
2645 | break; | ||
2646 | case 0x06: | ||
2647 | tmpword |= 0x3000; | ||
2648 | break; | ||
2649 | case 0x05: | ||
2650 | tmpword |= 0x0c00; | ||
2651 | break; | ||
2652 | case 0x03: | ||
2653 | tmpword |= 0x00c0; | ||
2654 | break; | ||
2655 | case 0x02: | ||
2656 | tmpword |= 0x0030; | ||
2657 | break; | ||
2658 | case 0x01: | ||
2659 | tmpword |= 0x000c; | ||
2660 | break; | ||
2661 | case 0x00: | ||
2662 | tmpword |= 0x0003; | ||
2663 | break; | ||
2664 | default: | ||
2665 | break; /* do not change settings */ | ||
2666 | } | ||
2667 | IRDA_DEBUG(1, "PCI_DMA_C (write): 0x%04x\n", tmpword); | ||
2668 | pci_write_config_word(dev, PCI_DMA_C, tmpword); | ||
2669 | |||
2670 | /* | ||
2671 | * GEN2_DEC bits: | ||
2672 | * Bit 15-4: Generic I/O range | ||
2673 | * Bit 3-1: reserved (read as 0) | ||
2674 | * Bit 0: enable GEN2 range on LPC I/F | ||
2675 | */ | ||
2676 | tmpword = conf->fir_io & 0xfff8; | ||
2677 | tmpword |= 0x0001; | ||
2678 | IRDA_DEBUG(1, "GEN2_DEC (write): 0x%04x\n", tmpword); | ||
2679 | pci_write_config_word(dev, GEN2_DEC, tmpword); | ||
2680 | |||
2681 | /* Pre-configure chip */ | ||
2682 | return preconfigure_smsc_chip(conf); | ||
2683 | } | ||
2684 | |||
2685 | /* | ||
2686 | * Pre-configure a certain port on the ALi 1533 bridge. | ||
2687 | * This is based on reverse-engineering since ALi does not | ||
2688 | * provide any data sheet for the 1533 chip. | ||
2689 | */ | ||
2690 | static void __init preconfigure_ali_port(struct pci_dev *dev, | ||
2691 | unsigned short port) | ||
2692 | { | ||
2693 | unsigned char reg; | ||
2694 | /* These bits obviously control the different ports */ | ||
2695 | unsigned char mask; | ||
2696 | unsigned char tmpbyte; | ||
2697 | |||
2698 | switch(port) { | ||
2699 | case 0x0130: | ||
2700 | case 0x0178: | ||
2701 | reg = 0xb0; | ||
2702 | mask = 0x80; | ||
2703 | break; | ||
2704 | case 0x03f8: | ||
2705 | reg = 0xb4; | ||
2706 | mask = 0x80; | ||
2707 | break; | ||
2708 | case 0x02f8: | ||
2709 | reg = 0xb4; | ||
2710 | mask = 0x30; | ||
2711 | break; | ||
2712 | case 0x02e8: | ||
2713 | reg = 0xb4; | ||
2714 | mask = 0x08; | ||
2715 | break; | ||
2716 | default: | ||
2717 | IRDA_ERROR("Failed to configure unsupported port on ALi 1533 bridge: 0x%04x\n", port); | ||
2718 | return; | ||
2719 | } | ||
2720 | |||
2721 | pci_read_config_byte(dev, reg, &tmpbyte); | ||
2722 | /* Turn on the right bits */ | ||
2723 | tmpbyte |= mask; | ||
2724 | pci_write_config_byte(dev, reg, tmpbyte); | ||
2725 | IRDA_MESSAGE("Activated ALi 1533 ISA bridge port 0x%04x.\n", port); | ||
2726 | return; | ||
2727 | } | ||
2728 | |||
2729 | static int __init preconfigure_through_ali(struct pci_dev *dev, | ||
2730 | struct | ||
2731 | smsc_ircc_subsystem_configuration | ||
2732 | *conf) | ||
2733 | { | ||
2734 | /* Configure the two ports on the ALi 1533 */ | ||
2735 | preconfigure_ali_port(dev, conf->sir_io); | ||
2736 | preconfigure_ali_port(dev, conf->fir_io); | ||
2737 | |||
2738 | /* Pre-configure chip */ | ||
2739 | return preconfigure_smsc_chip(conf); | ||
2740 | } | ||
2741 | |||
2742 | static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg, | ||
2743 | unsigned short ircc_fir, | ||
2744 | unsigned short ircc_sir, | ||
2745 | unsigned char ircc_dma, | ||
2746 | unsigned char ircc_irq) | ||
2747 | { | ||
2748 | struct pci_dev *dev = NULL; | ||
2749 | unsigned short ss_vendor = 0x0000; | ||
2750 | unsigned short ss_device = 0x0000; | ||
2751 | int ret = 0; | ||
2752 | |||
2753 | dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev); | ||
2754 | |||
2755 | while (dev != NULL) { | ||
2756 | struct smsc_ircc_subsystem_configuration *conf; | ||
2757 | |||
2758 | /* | ||
2759 | * Cache the subsystem vendor/device: | ||
2760 | * some manufacturers fail to set this for all components, | ||
2761 | * so we save it in case there is just 0x0000 0x0000 on the | ||
2762 | * device we want to check. | ||
2763 | */ | ||
2764 | if (dev->subsystem_vendor != 0x0000U) { | ||
2765 | ss_vendor = dev->subsystem_vendor; | ||
2766 | ss_device = dev->subsystem_device; | ||
2767 | } | ||
2768 | conf = subsystem_configurations; | ||
2769 | for( ; conf->subvendor; conf++) { | ||
2770 | if(conf->vendor == dev->vendor && | ||
2771 | conf->device == dev->device && | ||
2772 | conf->subvendor == ss_vendor && | ||
2773 | /* Sometimes these are cached values */ | ||
2774 | (conf->subdevice == ss_device || | ||
2775 | conf->subdevice == 0xffff)) { | ||
2776 | struct smsc_ircc_subsystem_configuration | ||
2777 | tmpconf; | ||
2778 | |||
2779 | memcpy(&tmpconf, conf, | ||
2780 | sizeof(struct smsc_ircc_subsystem_configuration)); | ||
2781 | |||
2782 | /* | ||
2783 | * Override the default values with anything | ||
2784 | * passed in as parameter | ||
2785 | */ | ||
2786 | if (ircc_cfg != 0) | ||
2787 | tmpconf.cfg_base = ircc_cfg; | ||
2788 | if (ircc_fir != 0) | ||
2789 | tmpconf.fir_io = ircc_fir; | ||
2790 | if (ircc_sir != 0) | ||
2791 | tmpconf.sir_io = ircc_sir; | ||
2792 | if (ircc_dma != 0xff) | ||
2793 | tmpconf.fir_dma = ircc_dma; | ||
2794 | if (ircc_irq != 0xff) | ||
2795 | tmpconf.fir_irq = ircc_irq; | ||
2796 | |||
2797 | IRDA_MESSAGE("Detected unconfigured %s SMSC IrDA chip, pre-configuring device.\n", conf->name); | ||
2798 | if (conf->preconfigure) | ||
2799 | ret = conf->preconfigure(dev, &tmpconf); | ||
2800 | else | ||
2801 | ret = -ENODEV; | ||
2802 | } | ||
2803 | } | ||
2804 | dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev); | ||
2805 | } | ||
2806 | |||
2807 | return ret; | ||
2808 | } | ||
2809 | #endif // CONFIG_PCI | ||
2810 | |||
2288 | /************************************************ | 2811 | /************************************************ |
2289 | * | 2812 | * |
2290 | * Transceivers specific functions | 2813 | * Transceivers specific functions |