Changes in / [98caf49:54d4b9e] in mainline
- Location:
- uspace
- Files:
-
- 1 added
- 1 deleted
- 19 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/app/usbinfo/Makefile
r98caf49 r54d4b9e 43 43 dev.c \ 44 44 dump.c \ 45 hid.c \ 45 46 info.c \ 46 47 main.c -
uspace/app/usbinfo/main.c
r98caf49 r54d4b9e 56 56 printf("Usage: %s [options] device [device [device [ ... ]]]\n", 57 57 app_name); 58 printf(_INDENT "The device is a devman path to the device.\n"); 58 printf(_INDENT "The device can be specified in two ways.\n"); 59 printf(_INDENT " o Using its devman path, e.g. /hw/pci0/.../usb00_a1.\n"); 60 printf(_INDENT " o Or using BUS.ADDR numbers as printed by lsusb.\n"); 59 61 60 62 _OPTION("-h --help", "Print this help and exit."); … … 65 67 _OPTION("-s --strings", "Try to print all string descriptors."); 66 68 _OPTION("-S --status", "Get status of the device."); 69 _OPTION("-r --hid-report", "Dump HID report descriptor."); 67 70 68 71 printf("\n"); … … 82 85 {"strings", no_argument, NULL, 's'}, 83 86 {"status", no_argument, NULL, 'S'}, 87 {"hid-report", no_argument, NULL, 'r'}, 84 88 {0, 0, NULL, 0} 85 89 }; 86 static const char *short_options = "himtTsS ";90 static const char *short_options = "himtTsSr"; 87 91 88 92 static usbinfo_action_t actions[] = { … … 115 119 .opt = 'S', 116 120 .action = dump_status, 121 .active = false 122 }, 123 { 124 .opt = 'r', 125 .action = dump_hidreport, 117 126 .active = false 118 127 }, -
uspace/app/usbinfo/usbinfo.h
r98caf49 r54d4b9e 85 85 void dump_strings(usbinfo_device_t *); 86 86 void dump_status(usbinfo_device_t *); 87 void dump_hidreport(usbinfo_device_t *); 87 88 88 89 -
uspace/drv/ohci/root_hub.c
r98caf49 r54d4b9e 251 251 int opResult; 252 252 if (request->ep->transfer_type == USB_TRANSFER_CONTROL) { 253 usb_log_ info("Root hub got CONTROL packet\n");253 usb_log_debug("Root hub got CONTROL packet\n"); 254 254 opResult = process_ctrl_request(instance, request); 255 255 usb_transfer_batch_finish_error(request, opResult); 256 256 } else if (request->ep->transfer_type == USB_TRANSFER_INTERRUPT) { 257 usb_log_ info("Root hub got INTERRUPT packet\n");257 usb_log_debug("Root hub got INTERRUPT packet\n"); 258 258 create_interrupt_mask_in_instance(instance); 259 259 if (is_zeros(instance->interrupt_buffer, -
uspace/drv/usbhid/Makefile
r98caf49 r54d4b9e 43 43 BINARY = usbhid 44 44 45 SUBDRIVER_SOURCES = \ 46 kbd/conv.c \ 47 kbd/kbddev.c \ 48 kbd/kbdrepeat.c \ 49 mouse/mousedev.c \ 50 multimedia/multimedia.c \ 51 multimedia/keymap.c 52 45 53 SOURCES = \ 46 54 main.c \ 47 55 usbhid.c \ 48 56 subdrivers.c \ 49 kbd/conv.c \50 kbd/kbddev.c \51 kbd/kbdrepeat.c \52 57 generic/hiddev.c \ 53 mouse/mousedev.c \ 54 multimedia/multimedia.c \ 55 multimedia/keymap.c \ 56 $(STOLEN_LAYOUT_SOURCES) 58 $(SUBDRIVER_SOURCES) 57 59 58 60 include $(USPACE_PREFIX)/Makefile.common -
uspace/drv/usbhid/generic/hiddev.c
r98caf49 r54d4b9e 231 231 /*----------------------------------------------------------------------------*/ 232 232 233 bool usb_generic_hid_polling_callback(usb_hid_dev_t *hid_dev, void *data, 234 uint8_t *buffer, size_t buffer_size) 235 { 236 usb_log_debug2("usb_hid_polling_callback(%p, %p, %zu)\n", 237 hid_dev, buffer, buffer_size); 238 usb_debug_str_buffer(buffer, buffer_size, 0); 233 bool usb_generic_hid_polling_callback(usb_hid_dev_t *hid_dev, void *data) 234 { 239 235 return true; 240 236 } -
uspace/drv/usbhid/generic/hiddev.h
r98caf49 r54d4b9e 50 50 int usb_generic_hid_init(struct usb_hid_dev *hid_dev, void **data); 51 51 52 bool usb_generic_hid_polling_callback(struct usb_hid_dev *hid_dev, void *data, 53 uint8_t *buffer, size_t buffer_size); 52 bool usb_generic_hid_polling_callback(struct usb_hid_dev *hid_dev, void *data); 54 53 55 54 #endif // USB_HID_HIDDDEV_H_ -
uspace/drv/usbhid/kbd/kbddev.c
r98caf49 r54d4b9e 434 434 * usb_hid_parse_report(). 435 435 */ 436 static void usb_kbd_process_data(usb_hid_dev_t *hid_dev, usb_kbd_t *kbd_dev, 437 uint8_t *buffer, size_t actual_size) 436 static void usb_kbd_process_data(usb_hid_dev_t *hid_dev, usb_kbd_t *kbd_dev) 438 437 { 439 438 assert(hid_dev->report != NULL); 440 439 assert(hid_dev != NULL); 441 440 assert(kbd_dev != NULL); 442 443 usb_log_debug("Calling usb_hid_parse_report() with "444 "buffer %s\n", usb_debug_str_buffer(buffer, actual_size, 0));445 441 446 442 usb_hid_report_path_t *path = usb_hid_report_path(); 447 443 usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_KEYBOARD, 0); 448 444 449 uint8_t report_id; 450 int rc = usb_hid_parse_report(hid_dev->report, buffer, actual_size, 451 &report_id); 452 453 if (rc != EOK) { 454 usb_log_warning("Error in usb_hid_parse_report():" 455 "%s\n", str_error(rc)); 456 } 457 458 usb_hid_report_path_set_report_id (path, report_id); 445 usb_hid_report_path_set_report_id (path, hid_dev->report_id); 459 446 460 447 // fill in the currently pressed keys … … 756 743 /*----------------------------------------------------------------------------*/ 757 744 758 bool usb_kbd_polling_callback(usb_hid_dev_t *hid_dev, void *data, 759 uint8_t *buffer, size_t buffer_size) 760 { 761 if (hid_dev == NULL || buffer == NULL || data == NULL) { 745 bool usb_kbd_polling_callback(usb_hid_dev_t *hid_dev, void *data) 746 { 747 if (hid_dev == NULL/* || buffer == NULL*/ || data == NULL) { 762 748 // do not continue polling (???) 763 749 return false; … … 768 754 769 755 // TODO: add return value from this function 770 usb_kbd_process_data(hid_dev, kbd_dev , buffer, buffer_size);756 usb_kbd_process_data(hid_dev, kbd_dev); 771 757 772 758 return true; … … 804 790 if ((*kbd_dev)->repeat_mtx != NULL) { 805 791 //assert(!fibril_mutex_is_locked((*kbd_dev)->repeat_mtx)); 792 // FIXME - the fibril_mutex_is_locked may not cause 793 // fibril scheduling 806 794 while (fibril_mutex_is_locked((*kbd_dev)->repeat_mtx)) {} 807 795 free((*kbd_dev)->repeat_mtx); -
uspace/drv/usbhid/kbd/kbddev.h
r98caf49 r54d4b9e 125 125 int usb_kbd_init(struct usb_hid_dev *hid_dev, void **data); 126 126 127 bool usb_kbd_polling_callback(struct usb_hid_dev *hid_dev, void *data, 128 uint8_t *buffer, size_t buffer_size); 127 bool usb_kbd_polling_callback(struct usb_hid_dev *hid_dev, void *data); 129 128 130 129 int usb_kbd_is_initialized(const usb_kbd_t *kbd_dev); -
uspace/drv/usbhid/mouse/mousedev.c
r98caf49 r54d4b9e 229 229 /*----------------------------------------------------------------------------*/ 230 230 231 static bool usb_mouse_process_report(usb_hid_dev_t *hid_dev, 232 usb_mouse_t *mouse_dev, uint8_t *buffer, 233 size_t buffer_size) 231 static bool usb_mouse_process_report(usb_hid_dev_t *hid_dev, 232 usb_mouse_t *mouse_dev) 234 233 { 235 234 assert(mouse_dev != NULL); 236 237 usb_log_debug2("got buffer: %s.\n",238 usb_debug_str_buffer(buffer, buffer_size, 0));239 235 240 236 if (mouse_dev->mouse_phone < 0) { … … 243 239 } 244 240 245 /*246 * parse the input report247 */248 249 usb_log_debug(NAME " Calling usb_hid_parse_report() with "250 "buffer %s\n", usb_debug_str_buffer(buffer, buffer_size, 0));251 252 uint8_t report_id;253 254 int rc = usb_hid_parse_report(hid_dev->report, buffer, buffer_size,255 &report_id);256 257 if (rc != EOK) {258 usb_log_warning(NAME "Error in usb_hid_parse_report(): %s\n",259 str_error(rc));260 return true;261 }262 263 241 /* 264 242 * X … … 270 248 USB_HIDUT_USAGE_GENERIC_DESKTOP_X); 271 249 272 usb_hid_report_path_set_report_id(path, report_id);250 usb_hid_report_path_set_report_id(path, hid_dev->report_id); 273 251 274 252 usb_hid_report_field_t *field = usb_hid_report_get_sibling( … … 293 271 USB_HIDUT_USAGE_GENERIC_DESKTOP_Y); 294 272 295 usb_hid_report_path_set_report_id(path, report_id);273 usb_hid_report_path_set_report_id(path, hid_dev->report_id); 296 274 297 275 field = usb_hid_report_get_sibling( … … 321 299 USB_HIDUT_USAGE_GENERIC_DESKTOP_WHEEL); 322 300 323 usb_hid_report_path_set_report_id(path, report_id);301 usb_hid_report_path_set_report_id(path, hid_dev->report_id); 324 302 325 303 field = usb_hid_report_get_sibling( … … 345 323 path = usb_hid_report_path(); 346 324 usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_BUTTON, 0); 347 usb_hid_report_path_set_report_id(path, report_id);325 usb_hid_report_path_set_report_id(path, hid_dev->report_id); 348 326 349 327 field = usb_hid_report_get_sibling( … … 510 488 /*----------------------------------------------------------------------------*/ 511 489 512 bool usb_mouse_polling_callback(usb_hid_dev_t *hid_dev, void *data, 513 uint8_t *buffer, size_t buffer_size) 490 bool usb_mouse_polling_callback(usb_hid_dev_t *hid_dev, void *data) 514 491 { 515 492 usb_log_debug("usb_mouse_polling_callback()\n"); 516 usb_debug_str_buffer(buffer, buffer_size, 0);517 493 518 494 if (hid_dev == NULL || data == NULL) { … … 524 500 usb_mouse_t *mouse_dev = (usb_mouse_t *)data; 525 501 526 return usb_mouse_process_report(hid_dev, mouse_dev, buffer, 527 buffer_size); 502 return usb_mouse_process_report(hid_dev, mouse_dev); 528 503 } 529 504 -
uspace/drv/usbhid/mouse/mousedev.h
r98caf49 r54d4b9e 65 65 int usb_mouse_init(struct usb_hid_dev *hid_dev, void **data); 66 66 67 bool usb_mouse_polling_callback(struct usb_hid_dev *hid_dev, void *data, 68 uint8_t *buffer, size_t buffer_size); 67 bool usb_mouse_polling_callback(struct usb_hid_dev *hid_dev, void *data); 69 68 70 69 void usb_mouse_deinit(struct usb_hid_dev *hid_dev, void *data); -
uspace/drv/usbhid/multimedia/multimedia.c
r98caf49 r54d4b9e 94 94 95 95 usb_multimedia_t *multim_dev = (usb_multimedia_t *)fun->driver_data; 96 //usb_hid_dev_t *hid_dev = (usb_hid_dev_t *)fun->driver_data;97 96 98 97 if (multim_dev == NULL) { … … 274 273 /*----------------------------------------------------------------------------*/ 275 274 276 bool usb_multimedia_polling_callback(struct usb_hid_dev *hid_dev, void *data, 277 uint8_t *buffer, size_t buffer_size) 275 bool usb_multimedia_polling_callback(struct usb_hid_dev *hid_dev, void *data) 278 276 { 279 277 // TODO: checks 280 if (hid_dev == NULL || data == NULL || buffer == NULL) {278 if (hid_dev == NULL || data == NULL) { 281 279 return false; 282 280 } 283 284 usb_log_debug(NAME " usb_lgtch_polling_callback(%p, %p, %zu)\n", 285 hid_dev, buffer, buffer_size); 286 281 287 282 usb_multimedia_t *multim_dev = (usb_multimedia_t *)data; 288 289 usb_log_debug(NAME " Calling usb_hid_parse_report() with "290 "buffer %s\n", usb_debug_str_buffer(buffer, buffer_size, 0));291 283 292 284 usb_hid_report_path_t *path = usb_hid_report_path(); 293 285 usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_CONSUMER, 0); 294 286 295 uint8_t report_id; 296 297 int rc = usb_hid_parse_report(hid_dev->report, buffer, buffer_size, 298 &report_id); 299 300 if (rc != EOK) { 301 usb_log_warning(NAME "Error in usb_hid_parse_report(): %s\n", 302 str_error(rc)); 303 return true; 304 } 305 306 usb_hid_report_path_set_report_id(path, report_id); 287 usb_hid_report_path_set_report_id(path, hid_dev->report_id); 307 288 308 289 usb_hid_report_field_t *field = usb_hid_report_get_sibling( -
uspace/drv/usbhid/multimedia/multimedia.h
r98caf49 r54d4b9e 47 47 void usb_multimedia_deinit(struct usb_hid_dev *hid_dev, void *data); 48 48 49 bool usb_multimedia_polling_callback(struct usb_hid_dev *hid_dev, void *data, 50 uint8_t *buffer, size_t buffer_size); 49 bool usb_multimedia_polling_callback(struct usb_hid_dev *hid_dev, void *data); 51 50 52 51 /*----------------------------------------------------------------------------*/ -
uspace/drv/usbhid/subdrivers.h
r98caf49 r54d4b9e 49 49 /*----------------------------------------------------------------------------*/ 50 50 51 /* TODO: This mapping must contain some other information to get the proper 52 * interface. 51 /** Structure representing the mapping between device requirements and the 52 * subdriver supposed to handle this device. 53 * 54 * By filling in this structure and adding it to the usb_hid_subdrivers array, 55 * a new subdriver mapping will be created and used by the HID driver when it 56 * searches for appropriate subdrivers for a device. 53 57 */ 54 58 typedef struct usb_hid_subdriver_mapping { 59 /** Usage path that the device's Input reports must contain. 60 * 61 * It is an array of pairs <usage_page, usage>, terminated by a <0, 0> 62 * pair. If you do not wish to specify the device in this way, set this 63 * to NULL. 64 */ 55 65 const usb_hid_subdriver_usage_t *usage_path; 66 67 /** Report ID for which the path should apply. */ 56 68 int report_id; 69 70 /** Compare type for the Usage path. */ 57 71 int compare; 72 73 /** Vendor ID (set to -1 if not specified). */ 58 74 int vendor_id; 75 76 /** Product ID (set to -1 if not specified). */ 59 77 int product_id; 78 79 /** Subdriver for controlling this device. */ 60 80 usb_hid_subdriver_t subdriver; 61 81 } usb_hid_subdriver_mapping_t; -
uspace/drv/usbhid/usbhid.c
r98caf49 r54d4b9e 582 582 } 583 583 584 // parse the input report 585 586 int rc = usb_hid_parse_report(hid_dev->report, buffer, buffer_size, 587 &hid_dev->report_id); 588 589 if (rc != EOK) { 590 usb_log_warning("Error in usb_hid_parse_report():" 591 "%s\n", str_error(rc)); 592 } 593 584 594 bool cont = false; 585 595 … … 588 598 if (hid_dev->subdrivers[i].poll != NULL 589 599 && hid_dev->subdrivers[i].poll(hid_dev, 590 hid_dev->subdrivers[i].data , buffer, buffer_size)) {600 hid_dev->subdrivers[i].data)) { 591 601 cont = true; 592 602 } -
uspace/drv/usbhid/usbhid.h
r98caf49 r54d4b9e 46 46 #include <bool.h> 47 47 48 struct usb_hid_dev; 48 typedef struct usb_hid_dev usb_hid_dev_t; 49 typedef struct usb_hid_subdriver usb_hid_subdriver_t; 49 50 50 typedef int (*usb_hid_driver_init_t)(struct usb_hid_dev *, void **data); 51 typedef void (*usb_hid_driver_deinit_t)(struct usb_hid_dev *, void *data); 52 typedef bool (*usb_hid_driver_poll)(struct usb_hid_dev *, void *data, uint8_t *, 53 size_t); 54 typedef int (*usb_hid_driver_poll_ended)(struct usb_hid_dev *, void *data, 55 bool reason); 51 /** Subdriver initialization callback. 52 * 53 * @param dev Backing USB HID device. 54 * @param data Custom subdriver data (pointer where to store them). 55 * @return Error code. 56 */ 57 typedef int (*usb_hid_driver_init_t)(usb_hid_dev_t *dev, void **data); 56 58 57 typedef struct usb_hid_subdriver { 59 /** Subdriver deinitialization callback. 60 * 61 * @param dev Backing USB HID device. 62 * @param data Custom subdriver data. 63 */ 64 typedef void (*usb_hid_driver_deinit_t)(usb_hid_dev_t *dev, void *data); 65 66 /** Subdriver callback on data from device. 67 * 68 * @param dev Backing USB HID device. 69 * @param data Custom subdriver data. 70 * @return Whether to continue polling (typically true always). 71 */ 72 typedef bool (*usb_hid_driver_poll_t)(usb_hid_dev_t *dev, void *data); 73 74 /** Subdriver callback after communication with the device ceased. 75 * 76 * @param dev Backing USB HID device. 77 * @param data Custom subdriver data. 78 * @param ended_due_to_errors Whether communication ended due to errors in 79 * communication (true) or deliberately by driver (false). 80 */ 81 typedef void (*usb_hid_driver_poll_ended_t)(usb_hid_dev_t *dev, void *data, 82 bool ended_due_to_errors); 83 84 struct usb_hid_subdriver { 58 85 /** Function to be called when initializing HID device. */ 59 86 usb_hid_driver_init_t init; … … 61 88 usb_hid_driver_deinit_t deinit; 62 89 /** Function to be called when data arrives from the device. */ 63 usb_hid_driver_poll poll;90 usb_hid_driver_poll_t poll; 64 91 /** Function to be called when polling ends. */ 65 usb_hid_driver_poll_ended poll_end;92 usb_hid_driver_poll_ended_t poll_end; 66 93 /** Arbitrary data needed by the subdriver. */ 67 94 void *data; 68 } usb_hid_subdriver_t;95 }; 69 96 70 97 /*----------------------------------------------------------------------------*/ … … 72 99 * Structure for holding general HID device data. 73 100 */ 74 typedefstruct usb_hid_dev {101 struct usb_hid_dev { 75 102 /** Structure holding generic USB device information. */ 76 103 usb_device_t *usb_dev; … … 94 121 usb_hid_report_t *report; 95 122 123 uint8_t report_id; 124 96 125 uint8_t *input_report; 97 126 … … 100 129 101 130 int report_nr; 102 } usb_hid_dev_t;131 }; 103 132 104 133 /*----------------------------------------------------------------------------*/ -
uspace/lib/usb/src/hc.c
r98caf49 r54d4b9e 98 98 return EBUSY; 99 99 100 async_sess_t *sess = devman_device_connect(EXCHANGE_ SERIALIZE,100 async_sess_t *sess = devman_device_connect(EXCHANGE_ATOMIC, 101 101 connection->hc_handle, 0); 102 102 if (!sess) … … 177 177 { 178 178 async_sess_t *parent_sess = 179 devman_parent_device_connect(EXCHANGE_ SERIALIZE, dev_handle,179 devman_parent_device_connect(EXCHANGE_ATOMIC, dev_handle, 180 180 IPC_FLAG_BLOCKING); 181 181 if (!parent_sess) … … 241 241 { 242 242 async_sess_t *parent_sess = 243 devman_parent_device_connect(EXCHANGE_ SERIALIZE, device_handle,243 devman_parent_device_connect(EXCHANGE_ATOMIC, device_handle, 244 244 IPC_FLAG_BLOCKING); 245 245 if (!parent_sess) -
uspace/lib/usbdev/src/pipes.c
r98caf49 r54d4b9e 81 81 { 82 82 async_sess_t *parent_sess = 83 devman_parent_device_connect(EXCHANGE_ SERIALIZE, device->handle,83 devman_parent_device_connect(EXCHANGE_ATOMIC, device->handle, 84 84 IPC_FLAG_BLOCKING); 85 85 if (!parent_sess) … … 122 122 123 123 async_sess_t *parent_sess = 124 devman_parent_device_connect(EXCHANGE_ SERIALIZE, dev->handle,124 devman_parent_device_connect(EXCHANGE_ATOMIC, dev->handle, 125 125 IPC_FLAG_BLOCKING); 126 126 if (!parent_sess) -
uspace/lib/usbhid/src/hidreq.c
r98caf49 r54d4b9e 82 82 value |= (type << 8); 83 83 84 usb_log_debug("Sending Set _Report request to the device.\n");84 usb_log_debug("Sending Set Report request to the device.\n"); 85 85 86 86 rc = usb_control_request_set(ctrl_pipe, … … 89 89 90 90 if (rc != EOK) { 91 usb_log_warning("Error sending output report to the keyboard:"92 " %s.\n", str_error(rc));91 usb_log_warning("Error sending Set Report request to the " 92 "device: %s.\n", str_error(rc)); 93 93 return rc; 94 94 } … … 129 129 int rc; 130 130 131 usb_log_debug("Sending Set _Protocol request to the device ("131 usb_log_debug("Sending Set Protocol request to the device (" 132 132 "protocol: %d, iface: %d).\n", protocol, iface_no); 133 133 … … 137 137 138 138 if (rc != EOK) { 139 usb_log_warning("Error sending output report to the keyboard:"140 " %s.\n", str_error(rc));139 usb_log_warning("Error sending Set Protocol request to the " 140 "device: %s.\n", str_error(rc)); 141 141 return rc; 142 142 } … … 177 177 int rc; 178 178 179 usb_log_debug("Sending Set _Idle request to the device ("179 usb_log_debug("Sending Set Idle request to the device (" 180 180 "duration: %u, iface: %d).\n", duration, iface_no); 181 181 … … 187 187 188 188 if (rc != EOK) { 189 usb_log_warning("Error sending output report to the keyboard: "189 usb_log_warning("Error sending Set Idle request to the device: " 190 190 "%s.\n", str_error(rc)); 191 191 return rc; … … 235 235 value |= (type << 8); 236 236 237 usb_log_debug("Sending Get _Report request to the device.\n");237 usb_log_debug("Sending Get Report request to the device.\n"); 238 238 239 239 rc = usb_control_request_get(ctrl_pipe, … … 243 243 244 244 if (rc != EOK) { 245 usb_log_warning("Error sending output report to the keyboard: "245 usb_log_warning("Error sending Get Report request to the device: " 246 246 "%s.\n", str_error(rc)); 247 247 return rc; … … 283 283 int rc; 284 284 285 usb_log_debug("Sending Get _Protocol request to the device ("285 usb_log_debug("Sending Get Protocol request to the device (" 286 286 "iface: %d).\n", iface_no); 287 287 … … 294 294 295 295 if (rc != EOK) { 296 usb_log_warning("Error sending output report to the keyboard:"297 " %s.\n", str_error(rc));296 usb_log_warning("Error sending Get Protocol request to the " 297 "device: %s.\n", str_error(rc)); 298 298 return rc; 299 299 } … … 344 344 int rc; 345 345 346 usb_log_debug("Sending Get _Idle request to the device ("346 usb_log_debug("Sending Get Idle request to the device (" 347 347 "iface: %d).\n", iface_no); 348 348 … … 357 357 358 358 if (rc != EOK) { 359 usb_log_warning("Error sending output report to the keyboard: "359 usb_log_warning("Error sending Get Idle request to the device: " 360 360 "%s.\n", str_error(rc)); 361 361 return rc;
Note:
See TracChangeset
for help on using the changeset viewer.