diff options
author | Nick Fedchik <nfedchik@atlantic-link.com.ua> | 2006-06-11 23:56:02 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-06-18 00:30:26 -0400 |
commit | 8ef80aef118e405f2b6505f623830e6e73224f85 (patch) | |
tree | 6abecac69d73eb3ffb884e29eb6ecc3c1d39cb7e /drivers/net/irda/irda-usb.c | |
parent | f8d596211291a8d98efa47ae0261326218f310cf (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>
Diffstat (limited to 'drivers/net/irda/irda-usb.c')
-rw-r--r-- | drivers/net/irda/irda-usb.c | 327 |
1 files changed, 141 insertions, 186 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 | */ |
1036 | static char * stir421x_patches[] = { | 1042 | static 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 | |||
1041 | static 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 | |||
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 | 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 | */ | ||
1139 | static int stir421x_patch_device(struct irda_usb_cb *self) | 1088 | static 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 | ||