diff options
Diffstat (limited to 'drivers/isdn/capi/kcapi.c')
-rw-r--r-- | drivers/isdn/capi/kcapi.c | 291 |
1 files changed, 205 insertions, 86 deletions
diff --git a/drivers/isdn/capi/kcapi.c b/drivers/isdn/capi/kcapi.c index e08914d33be1..a99f7e3f8f51 100644 --- a/drivers/isdn/capi/kcapi.c +++ b/drivers/isdn/capi/kcapi.c | |||
@@ -61,11 +61,12 @@ static char capi_manufakturer[64] = "AVM Berlin"; | |||
61 | LIST_HEAD(capi_drivers); | 61 | LIST_HEAD(capi_drivers); |
62 | DEFINE_MUTEX(capi_drivers_lock); | 62 | DEFINE_MUTEX(capi_drivers_lock); |
63 | 63 | ||
64 | struct capi_ctr *capi_controller[CAPI_MAXCONTR]; | ||
65 | DEFINE_MUTEX(capi_controller_lock); | ||
66 | |||
64 | static DEFINE_RWLOCK(application_lock); | 67 | static DEFINE_RWLOCK(application_lock); |
65 | static DEFINE_MUTEX(controller_mutex); | ||
66 | 68 | ||
67 | struct capi20_appl *capi_applications[CAPI_MAXAPPL]; | 69 | struct capi20_appl *capi_applications[CAPI_MAXAPPL]; |
68 | struct capi_ctr *capi_controller[CAPI_MAXCONTR]; | ||
69 | 70 | ||
70 | static int ncontrollers; | 71 | static int ncontrollers; |
71 | 72 | ||
@@ -171,13 +172,15 @@ static void notify_up(u32 contr) | |||
171 | struct capi_ctr *ctr; | 172 | struct capi_ctr *ctr; |
172 | u16 applid; | 173 | u16 applid; |
173 | 174 | ||
175 | mutex_lock(&capi_controller_lock); | ||
176 | |||
174 | if (showcapimsgs & 1) | 177 | if (showcapimsgs & 1) |
175 | printk(KERN_DEBUG "kcapi: notify up contr %d\n", contr); | 178 | printk(KERN_DEBUG "kcapi: notify up contr %d\n", contr); |
176 | 179 | ||
177 | ctr = get_capi_ctr_by_nr(contr); | 180 | ctr = get_capi_ctr_by_nr(contr); |
178 | if (ctr) { | 181 | if (ctr) { |
179 | if (ctr->state == CAPI_CTR_RUNNING) | 182 | if (ctr->state == CAPI_CTR_RUNNING) |
180 | return; | 183 | goto unlock_out; |
181 | 184 | ||
182 | ctr->state = CAPI_CTR_RUNNING; | 185 | ctr->state = CAPI_CTR_RUNNING; |
183 | 186 | ||
@@ -187,19 +190,24 @@ static void notify_up(u32 contr) | |||
187 | continue; | 190 | continue; |
188 | register_appl(ctr, applid, &ap->rparam); | 191 | register_appl(ctr, applid, &ap->rparam); |
189 | } | 192 | } |
193 | |||
194 | wake_up_interruptible_all(&ctr->state_wait_queue); | ||
190 | } else | 195 | } else |
191 | printk(KERN_WARNING "%s: invalid contr %d\n", __func__, contr); | 196 | printk(KERN_WARNING "%s: invalid contr %d\n", __func__, contr); |
197 | |||
198 | unlock_out: | ||
199 | mutex_unlock(&capi_controller_lock); | ||
192 | } | 200 | } |
193 | 201 | ||
194 | static void ctr_down(struct capi_ctr *ctr) | 202 | static void ctr_down(struct capi_ctr *ctr, int new_state) |
195 | { | 203 | { |
196 | struct capi20_appl *ap; | 204 | struct capi20_appl *ap; |
197 | u16 applid; | 205 | u16 applid; |
198 | 206 | ||
199 | if (ctr->state == CAPI_CTR_DETECTED) | 207 | if (ctr->state == CAPI_CTR_DETECTED || ctr->state == CAPI_CTR_DETACHED) |
200 | return; | 208 | return; |
201 | 209 | ||
202 | ctr->state = CAPI_CTR_DETECTED; | 210 | ctr->state = new_state; |
203 | 211 | ||
204 | memset(ctr->manu, 0, sizeof(ctr->manu)); | 212 | memset(ctr->manu, 0, sizeof(ctr->manu)); |
205 | memset(&ctr->version, 0, sizeof(ctr->version)); | 213 | memset(&ctr->version, 0, sizeof(ctr->version)); |
@@ -211,20 +219,26 @@ static void ctr_down(struct capi_ctr *ctr) | |||
211 | if (ap && !ap->release_in_progress) | 219 | if (ap && !ap->release_in_progress) |
212 | capi_ctr_put(ctr); | 220 | capi_ctr_put(ctr); |
213 | } | 221 | } |
222 | |||
223 | wake_up_interruptible_all(&ctr->state_wait_queue); | ||
214 | } | 224 | } |
215 | 225 | ||
216 | static void notify_down(u32 contr) | 226 | static void notify_down(u32 contr) |
217 | { | 227 | { |
218 | struct capi_ctr *ctr; | 228 | struct capi_ctr *ctr; |
219 | 229 | ||
230 | mutex_lock(&capi_controller_lock); | ||
231 | |||
220 | if (showcapimsgs & 1) | 232 | if (showcapimsgs & 1) |
221 | printk(KERN_DEBUG "kcapi: notify down contr %d\n", contr); | 233 | printk(KERN_DEBUG "kcapi: notify down contr %d\n", contr); |
222 | 234 | ||
223 | ctr = get_capi_ctr_by_nr(contr); | 235 | ctr = get_capi_ctr_by_nr(contr); |
224 | if (ctr) | 236 | if (ctr) |
225 | ctr_down(ctr); | 237 | ctr_down(ctr, CAPI_CTR_DETECTED); |
226 | else | 238 | else |
227 | printk(KERN_WARNING "%s: invalid contr %d\n", __func__, contr); | 239 | printk(KERN_WARNING "%s: invalid contr %d\n", __func__, contr); |
240 | |||
241 | mutex_unlock(&capi_controller_lock); | ||
228 | } | 242 | } |
229 | 243 | ||
230 | static int | 244 | static int |
@@ -436,6 +450,9 @@ EXPORT_SYMBOL(capi_ctr_down); | |||
436 | * @ctr: controller descriptor structure. | 450 | * @ctr: controller descriptor structure. |
437 | * | 451 | * |
438 | * Called by hardware driver to stop data flow. | 452 | * Called by hardware driver to stop data flow. |
453 | * | ||
454 | * Note: The caller is responsible for synchronizing concurrent state changes | ||
455 | * as well as invocations of capi_ctr_handle_message. | ||
439 | */ | 456 | */ |
440 | 457 | ||
441 | void capi_ctr_suspend_output(struct capi_ctr *ctr) | 458 | void capi_ctr_suspend_output(struct capi_ctr *ctr) |
@@ -454,6 +471,9 @@ EXPORT_SYMBOL(capi_ctr_suspend_output); | |||
454 | * @ctr: controller descriptor structure. | 471 | * @ctr: controller descriptor structure. |
455 | * | 472 | * |
456 | * Called by hardware driver to resume data flow. | 473 | * Called by hardware driver to resume data flow. |
474 | * | ||
475 | * Note: The caller is responsible for synchronizing concurrent state changes | ||
476 | * as well as invocations of capi_ctr_handle_message. | ||
457 | */ | 477 | */ |
458 | 478 | ||
459 | void capi_ctr_resume_output(struct capi_ctr *ctr) | 479 | void capi_ctr_resume_output(struct capi_ctr *ctr) |
@@ -481,21 +501,19 @@ int attach_capi_ctr(struct capi_ctr *ctr) | |||
481 | { | 501 | { |
482 | int i; | 502 | int i; |
483 | 503 | ||
484 | mutex_lock(&controller_mutex); | 504 | mutex_lock(&capi_controller_lock); |
485 | 505 | ||
486 | for (i = 0; i < CAPI_MAXCONTR; i++) { | 506 | for (i = 0; i < CAPI_MAXCONTR; i++) { |
487 | if (!capi_controller[i]) | 507 | if (!capi_controller[i]) |
488 | break; | 508 | break; |
489 | } | 509 | } |
490 | if (i == CAPI_MAXCONTR) { | 510 | if (i == CAPI_MAXCONTR) { |
491 | mutex_unlock(&controller_mutex); | 511 | mutex_unlock(&capi_controller_lock); |
492 | printk(KERN_ERR "kcapi: out of controller slots\n"); | 512 | printk(KERN_ERR "kcapi: out of controller slots\n"); |
493 | return -EBUSY; | 513 | return -EBUSY; |
494 | } | 514 | } |
495 | capi_controller[i] = ctr; | 515 | capi_controller[i] = ctr; |
496 | 516 | ||
497 | mutex_unlock(&controller_mutex); | ||
498 | |||
499 | ctr->nrecvctlpkt = 0; | 517 | ctr->nrecvctlpkt = 0; |
500 | ctr->nrecvdatapkt = 0; | 518 | ctr->nrecvdatapkt = 0; |
501 | ctr->nsentctlpkt = 0; | 519 | ctr->nsentctlpkt = 0; |
@@ -504,11 +522,15 @@ int attach_capi_ctr(struct capi_ctr *ctr) | |||
504 | ctr->state = CAPI_CTR_DETECTED; | 522 | ctr->state = CAPI_CTR_DETECTED; |
505 | ctr->blocked = 0; | 523 | ctr->blocked = 0; |
506 | ctr->traceflag = showcapimsgs; | 524 | ctr->traceflag = showcapimsgs; |
525 | init_waitqueue_head(&ctr->state_wait_queue); | ||
507 | 526 | ||
508 | sprintf(ctr->procfn, "capi/controllers/%d", ctr->cnr); | 527 | sprintf(ctr->procfn, "capi/controllers/%d", ctr->cnr); |
509 | ctr->procent = proc_create_data(ctr->procfn, 0, NULL, ctr->proc_fops, ctr); | 528 | ctr->procent = proc_create_data(ctr->procfn, 0, NULL, ctr->proc_fops, ctr); |
510 | 529 | ||
511 | ncontrollers++; | 530 | ncontrollers++; |
531 | |||
532 | mutex_unlock(&capi_controller_lock); | ||
533 | |||
512 | printk(KERN_NOTICE "kcapi: controller [%03d]: %s attached\n", | 534 | printk(KERN_NOTICE "kcapi: controller [%03d]: %s attached\n", |
513 | ctr->cnr, ctr->name); | 535 | ctr->cnr, ctr->name); |
514 | return 0; | 536 | return 0; |
@@ -527,19 +549,29 @@ EXPORT_SYMBOL(attach_capi_ctr); | |||
527 | 549 | ||
528 | int detach_capi_ctr(struct capi_ctr *ctr) | 550 | int detach_capi_ctr(struct capi_ctr *ctr) |
529 | { | 551 | { |
530 | ctr_down(ctr); | 552 | int err = 0; |
531 | 553 | ||
532 | ncontrollers--; | 554 | mutex_lock(&capi_controller_lock); |
533 | 555 | ||
534 | if (ctr->procent) { | 556 | ctr_down(ctr, CAPI_CTR_DETACHED); |
535 | remove_proc_entry(ctr->procfn, NULL); | 557 | |
536 | ctr->procent = NULL; | 558 | if (capi_controller[ctr->cnr - 1] != ctr) { |
559 | err = -EINVAL; | ||
560 | goto unlock_out; | ||
537 | } | 561 | } |
538 | capi_controller[ctr->cnr - 1] = NULL; | 562 | capi_controller[ctr->cnr - 1] = NULL; |
563 | ncontrollers--; | ||
564 | |||
565 | if (ctr->procent) | ||
566 | remove_proc_entry(ctr->procfn, NULL); | ||
567 | |||
539 | printk(KERN_NOTICE "kcapi: controller [%03d]: %s unregistered\n", | 568 | printk(KERN_NOTICE "kcapi: controller [%03d]: %s unregistered\n", |
540 | ctr->cnr, ctr->name); | 569 | ctr->cnr, ctr->name); |
541 | 570 | ||
542 | return 0; | 571 | unlock_out: |
572 | mutex_unlock(&capi_controller_lock); | ||
573 | |||
574 | return err; | ||
543 | } | 575 | } |
544 | 576 | ||
545 | EXPORT_SYMBOL(detach_capi_ctr); | 577 | EXPORT_SYMBOL(detach_capi_ctr); |
@@ -589,13 +621,21 @@ EXPORT_SYMBOL(unregister_capi_driver); | |||
589 | 621 | ||
590 | u16 capi20_isinstalled(void) | 622 | u16 capi20_isinstalled(void) |
591 | { | 623 | { |
624 | u16 ret = CAPI_REGNOTINSTALLED; | ||
592 | int i; | 625 | int i; |
593 | for (i = 0; i < CAPI_MAXCONTR; i++) { | 626 | |
627 | mutex_lock(&capi_controller_lock); | ||
628 | |||
629 | for (i = 0; i < CAPI_MAXCONTR; i++) | ||
594 | if (capi_controller[i] && | 630 | if (capi_controller[i] && |
595 | capi_controller[i]->state == CAPI_CTR_RUNNING) | 631 | capi_controller[i]->state == CAPI_CTR_RUNNING) { |
596 | return CAPI_NOERROR; | 632 | ret = CAPI_NOERROR; |
597 | } | 633 | break; |
598 | return CAPI_REGNOTINSTALLED; | 634 | } |
635 | |||
636 | mutex_unlock(&capi_controller_lock); | ||
637 | |||
638 | return ret; | ||
599 | } | 639 | } |
600 | 640 | ||
601 | EXPORT_SYMBOL(capi20_isinstalled); | 641 | EXPORT_SYMBOL(capi20_isinstalled); |
@@ -648,14 +688,16 @@ u16 capi20_register(struct capi20_appl *ap) | |||
648 | 688 | ||
649 | write_unlock_irqrestore(&application_lock, flags); | 689 | write_unlock_irqrestore(&application_lock, flags); |
650 | 690 | ||
651 | mutex_lock(&controller_mutex); | 691 | mutex_lock(&capi_controller_lock); |
692 | |||
652 | for (i = 0; i < CAPI_MAXCONTR; i++) { | 693 | for (i = 0; i < CAPI_MAXCONTR; i++) { |
653 | if (!capi_controller[i] || | 694 | if (!capi_controller[i] || |
654 | capi_controller[i]->state != CAPI_CTR_RUNNING) | 695 | capi_controller[i]->state != CAPI_CTR_RUNNING) |
655 | continue; | 696 | continue; |
656 | register_appl(capi_controller[i], applid, &ap->rparam); | 697 | register_appl(capi_controller[i], applid, &ap->rparam); |
657 | } | 698 | } |
658 | mutex_unlock(&controller_mutex); | 699 | |
700 | mutex_unlock(&capi_controller_lock); | ||
659 | 701 | ||
660 | if (showcapimsgs & 1) { | 702 | if (showcapimsgs & 1) { |
661 | printk(KERN_DEBUG "kcapi: appl %d up\n", applid); | 703 | printk(KERN_DEBUG "kcapi: appl %d up\n", applid); |
@@ -688,14 +730,16 @@ u16 capi20_release(struct capi20_appl *ap) | |||
688 | capi_applications[ap->applid - 1] = NULL; | 730 | capi_applications[ap->applid - 1] = NULL; |
689 | write_unlock_irqrestore(&application_lock, flags); | 731 | write_unlock_irqrestore(&application_lock, flags); |
690 | 732 | ||
691 | mutex_lock(&controller_mutex); | 733 | mutex_lock(&capi_controller_lock); |
734 | |||
692 | for (i = 0; i < CAPI_MAXCONTR; i++) { | 735 | for (i = 0; i < CAPI_MAXCONTR; i++) { |
693 | if (!capi_controller[i] || | 736 | if (!capi_controller[i] || |
694 | capi_controller[i]->state != CAPI_CTR_RUNNING) | 737 | capi_controller[i]->state != CAPI_CTR_RUNNING) |
695 | continue; | 738 | continue; |
696 | release_appl(capi_controller[i], ap->applid); | 739 | release_appl(capi_controller[i], ap->applid); |
697 | } | 740 | } |
698 | mutex_unlock(&controller_mutex); | 741 | |
742 | mutex_unlock(&capi_controller_lock); | ||
699 | 743 | ||
700 | flush_scheduled_work(); | 744 | flush_scheduled_work(); |
701 | skb_queue_purge(&ap->recv_queue); | 745 | skb_queue_purge(&ap->recv_queue); |
@@ -734,6 +778,12 @@ u16 capi20_put_message(struct capi20_appl *ap, struct sk_buff *skb) | |||
734 | || !capi_cmd_valid(CAPIMSG_COMMAND(skb->data)) | 778 | || !capi_cmd_valid(CAPIMSG_COMMAND(skb->data)) |
735 | || !capi_subcmd_valid(CAPIMSG_SUBCOMMAND(skb->data))) | 779 | || !capi_subcmd_valid(CAPIMSG_SUBCOMMAND(skb->data))) |
736 | return CAPI_ILLCMDORSUBCMDORMSGTOSMALL; | 780 | return CAPI_ILLCMDORSUBCMDORMSGTOSMALL; |
781 | |||
782 | /* | ||
783 | * The controller reference is protected by the existence of the | ||
784 | * application passed to us. We assume that the caller properly | ||
785 | * synchronizes this service with capi20_release. | ||
786 | */ | ||
737 | ctr = get_capi_ctr_by_nr(CAPIMSG_CONTROLLER(skb->data)); | 787 | ctr = get_capi_ctr_by_nr(CAPIMSG_CONTROLLER(skb->data)); |
738 | if (!ctr || ctr->state != CAPI_CTR_RUNNING) { | 788 | if (!ctr || ctr->state != CAPI_CTR_RUNNING) { |
739 | ctr = get_capi_ctr_by_nr(1); /* XXX why? */ | 789 | ctr = get_capi_ctr_by_nr(1); /* XXX why? */ |
@@ -798,16 +848,24 @@ EXPORT_SYMBOL(capi20_put_message); | |||
798 | u16 capi20_get_manufacturer(u32 contr, u8 *buf) | 848 | u16 capi20_get_manufacturer(u32 contr, u8 *buf) |
799 | { | 849 | { |
800 | struct capi_ctr *ctr; | 850 | struct capi_ctr *ctr; |
851 | u16 ret; | ||
801 | 852 | ||
802 | if (contr == 0) { | 853 | if (contr == 0) { |
803 | strlcpy(buf, capi_manufakturer, CAPI_MANUFACTURER_LEN); | 854 | strlcpy(buf, capi_manufakturer, CAPI_MANUFACTURER_LEN); |
804 | return CAPI_NOERROR; | 855 | return CAPI_NOERROR; |
805 | } | 856 | } |
857 | |||
858 | mutex_lock(&capi_controller_lock); | ||
859 | |||
806 | ctr = get_capi_ctr_by_nr(contr); | 860 | ctr = get_capi_ctr_by_nr(contr); |
807 | if (!ctr || ctr->state != CAPI_CTR_RUNNING) | 861 | if (ctr && ctr->state == CAPI_CTR_RUNNING) { |
808 | return CAPI_REGNOTINSTALLED; | 862 | strlcpy(buf, ctr->manu, CAPI_MANUFACTURER_LEN); |
809 | strlcpy(buf, ctr->manu, CAPI_MANUFACTURER_LEN); | 863 | ret = CAPI_NOERROR; |
810 | return CAPI_NOERROR; | 864 | } else |
865 | ret = CAPI_REGNOTINSTALLED; | ||
866 | |||
867 | mutex_unlock(&capi_controller_lock); | ||
868 | return ret; | ||
811 | } | 869 | } |
812 | 870 | ||
813 | EXPORT_SYMBOL(capi20_get_manufacturer); | 871 | EXPORT_SYMBOL(capi20_get_manufacturer); |
@@ -825,17 +883,24 @@ EXPORT_SYMBOL(capi20_get_manufacturer); | |||
825 | u16 capi20_get_version(u32 contr, struct capi_version *verp) | 883 | u16 capi20_get_version(u32 contr, struct capi_version *verp) |
826 | { | 884 | { |
827 | struct capi_ctr *ctr; | 885 | struct capi_ctr *ctr; |
886 | u16 ret; | ||
828 | 887 | ||
829 | if (contr == 0) { | 888 | if (contr == 0) { |
830 | *verp = driver_version; | 889 | *verp = driver_version; |
831 | return CAPI_NOERROR; | 890 | return CAPI_NOERROR; |
832 | } | 891 | } |
892 | |||
893 | mutex_lock(&capi_controller_lock); | ||
894 | |||
833 | ctr = get_capi_ctr_by_nr(contr); | 895 | ctr = get_capi_ctr_by_nr(contr); |
834 | if (!ctr || ctr->state != CAPI_CTR_RUNNING) | 896 | if (ctr && ctr->state == CAPI_CTR_RUNNING) { |
835 | return CAPI_REGNOTINSTALLED; | 897 | memcpy(verp, &ctr->version, sizeof(capi_version)); |
898 | ret = CAPI_NOERROR; | ||
899 | } else | ||
900 | ret = CAPI_REGNOTINSTALLED; | ||
836 | 901 | ||
837 | memcpy(verp, &ctr->version, sizeof(capi_version)); | 902 | mutex_unlock(&capi_controller_lock); |
838 | return CAPI_NOERROR; | 903 | return ret; |
839 | } | 904 | } |
840 | 905 | ||
841 | EXPORT_SYMBOL(capi20_get_version); | 906 | EXPORT_SYMBOL(capi20_get_version); |
@@ -853,17 +918,24 @@ EXPORT_SYMBOL(capi20_get_version); | |||
853 | u16 capi20_get_serial(u32 contr, u8 *serial) | 918 | u16 capi20_get_serial(u32 contr, u8 *serial) |
854 | { | 919 | { |
855 | struct capi_ctr *ctr; | 920 | struct capi_ctr *ctr; |
921 | u16 ret; | ||
856 | 922 | ||
857 | if (contr == 0) { | 923 | if (contr == 0) { |
858 | strlcpy(serial, driver_serial, CAPI_SERIAL_LEN); | 924 | strlcpy(serial, driver_serial, CAPI_SERIAL_LEN); |
859 | return CAPI_NOERROR; | 925 | return CAPI_NOERROR; |
860 | } | 926 | } |
927 | |||
928 | mutex_lock(&capi_controller_lock); | ||
929 | |||
861 | ctr = get_capi_ctr_by_nr(contr); | 930 | ctr = get_capi_ctr_by_nr(contr); |
862 | if (!ctr || ctr->state != CAPI_CTR_RUNNING) | 931 | if (ctr && ctr->state == CAPI_CTR_RUNNING) { |
863 | return CAPI_REGNOTINSTALLED; | 932 | strlcpy(serial, ctr->serial, CAPI_SERIAL_LEN); |
933 | ret = CAPI_NOERROR; | ||
934 | } else | ||
935 | ret = CAPI_REGNOTINSTALLED; | ||
864 | 936 | ||
865 | strlcpy(serial, ctr->serial, CAPI_SERIAL_LEN); | 937 | mutex_unlock(&capi_controller_lock); |
866 | return CAPI_NOERROR; | 938 | return ret; |
867 | } | 939 | } |
868 | 940 | ||
869 | EXPORT_SYMBOL(capi20_get_serial); | 941 | EXPORT_SYMBOL(capi20_get_serial); |
@@ -881,21 +953,64 @@ EXPORT_SYMBOL(capi20_get_serial); | |||
881 | u16 capi20_get_profile(u32 contr, struct capi_profile *profp) | 953 | u16 capi20_get_profile(u32 contr, struct capi_profile *profp) |
882 | { | 954 | { |
883 | struct capi_ctr *ctr; | 955 | struct capi_ctr *ctr; |
956 | u16 ret; | ||
884 | 957 | ||
885 | if (contr == 0) { | 958 | if (contr == 0) { |
886 | profp->ncontroller = ncontrollers; | 959 | profp->ncontroller = ncontrollers; |
887 | return CAPI_NOERROR; | 960 | return CAPI_NOERROR; |
888 | } | 961 | } |
962 | |||
963 | mutex_lock(&capi_controller_lock); | ||
964 | |||
889 | ctr = get_capi_ctr_by_nr(contr); | 965 | ctr = get_capi_ctr_by_nr(contr); |
890 | if (!ctr || ctr->state != CAPI_CTR_RUNNING) | 966 | if (ctr && ctr->state == CAPI_CTR_RUNNING) { |
891 | return CAPI_REGNOTINSTALLED; | 967 | memcpy(profp, &ctr->profile, sizeof(struct capi_profile)); |
968 | ret = CAPI_NOERROR; | ||
969 | } else | ||
970 | ret = CAPI_REGNOTINSTALLED; | ||
892 | 971 | ||
893 | memcpy(profp, &ctr->profile, sizeof(struct capi_profile)); | 972 | mutex_unlock(&capi_controller_lock); |
894 | return CAPI_NOERROR; | 973 | return ret; |
895 | } | 974 | } |
896 | 975 | ||
897 | EXPORT_SYMBOL(capi20_get_profile); | 976 | EXPORT_SYMBOL(capi20_get_profile); |
898 | 977 | ||
978 | /* Must be called with capi_controller_lock held. */ | ||
979 | static int wait_on_ctr_state(struct capi_ctr *ctr, unsigned int state) | ||
980 | { | ||
981 | DEFINE_WAIT(wait); | ||
982 | int retval = 0; | ||
983 | |||
984 | ctr = capi_ctr_get(ctr); | ||
985 | if (!ctr) | ||
986 | return -ESRCH; | ||
987 | |||
988 | for (;;) { | ||
989 | prepare_to_wait(&ctr->state_wait_queue, &wait, | ||
990 | TASK_INTERRUPTIBLE); | ||
991 | |||
992 | if (ctr->state == state) | ||
993 | break; | ||
994 | if (ctr->state == CAPI_CTR_DETACHED) { | ||
995 | retval = -ESRCH; | ||
996 | break; | ||
997 | } | ||
998 | if (signal_pending(current)) { | ||
999 | retval = -EINTR; | ||
1000 | break; | ||
1001 | } | ||
1002 | |||
1003 | mutex_unlock(&capi_controller_lock); | ||
1004 | schedule(); | ||
1005 | mutex_lock(&capi_controller_lock); | ||
1006 | } | ||
1007 | finish_wait(&ctr->state_wait_queue, &wait); | ||
1008 | |||
1009 | capi_ctr_put(ctr); | ||
1010 | |||
1011 | return retval; | ||
1012 | } | ||
1013 | |||
899 | #ifdef AVMB1_COMPAT | 1014 | #ifdef AVMB1_COMPAT |
900 | static int old_capi_manufacturer(unsigned int cmd, void __user *data) | 1015 | static int old_capi_manufacturer(unsigned int cmd, void __user *data) |
901 | { | 1016 | { |
@@ -973,27 +1088,30 @@ static int old_capi_manufacturer(unsigned int cmd, void __user *data) | |||
973 | sizeof(avmb1_loadandconfigdef))) | 1088 | sizeof(avmb1_loadandconfigdef))) |
974 | return -EFAULT; | 1089 | return -EFAULT; |
975 | } | 1090 | } |
1091 | |||
1092 | mutex_lock(&capi_controller_lock); | ||
1093 | |||
976 | ctr = get_capi_ctr_by_nr(ldef.contr); | 1094 | ctr = get_capi_ctr_by_nr(ldef.contr); |
977 | if (!ctr) | 1095 | if (!ctr) { |
978 | return -EINVAL; | 1096 | retval = -EINVAL; |
979 | ctr = capi_ctr_get(ctr); | 1097 | goto load_unlock_out; |
980 | if (!ctr) | 1098 | } |
981 | return -ESRCH; | 1099 | |
982 | if (ctr->load_firmware == NULL) { | 1100 | if (ctr->load_firmware == NULL) { |
983 | printk(KERN_DEBUG "kcapi: load: no load function\n"); | 1101 | printk(KERN_DEBUG "kcapi: load: no load function\n"); |
984 | capi_ctr_put(ctr); | 1102 | retval = -ESRCH; |
985 | return -ESRCH; | 1103 | goto load_unlock_out; |
986 | } | 1104 | } |
987 | 1105 | ||
988 | if (ldef.t4file.len <= 0) { | 1106 | if (ldef.t4file.len <= 0) { |
989 | printk(KERN_DEBUG "kcapi: load: invalid parameter: length of t4file is %d ?\n", ldef.t4file.len); | 1107 | printk(KERN_DEBUG "kcapi: load: invalid parameter: length of t4file is %d ?\n", ldef.t4file.len); |
990 | capi_ctr_put(ctr); | 1108 | retval = -EINVAL; |
991 | return -EINVAL; | 1109 | goto load_unlock_out; |
992 | } | 1110 | } |
993 | if (ldef.t4file.data == NULL) { | 1111 | if (ldef.t4file.data == NULL) { |
994 | printk(KERN_DEBUG "kcapi: load: invalid parameter: dataptr is 0\n"); | 1112 | printk(KERN_DEBUG "kcapi: load: invalid parameter: dataptr is 0\n"); |
995 | capi_ctr_put(ctr); | 1113 | retval = -EINVAL; |
996 | return -EINVAL; | 1114 | goto load_unlock_out; |
997 | } | 1115 | } |
998 | 1116 | ||
999 | ldata.firmware.user = 1; | 1117 | ldata.firmware.user = 1; |
@@ -1005,52 +1123,47 @@ static int old_capi_manufacturer(unsigned int cmd, void __user *data) | |||
1005 | 1123 | ||
1006 | if (ctr->state != CAPI_CTR_DETECTED) { | 1124 | if (ctr->state != CAPI_CTR_DETECTED) { |
1007 | printk(KERN_INFO "kcapi: load: contr=%d not in detect state\n", ldef.contr); | 1125 | printk(KERN_INFO "kcapi: load: contr=%d not in detect state\n", ldef.contr); |
1008 | capi_ctr_put(ctr); | 1126 | retval = -EBUSY; |
1009 | return -EBUSY; | 1127 | goto load_unlock_out; |
1010 | } | 1128 | } |
1011 | ctr->state = CAPI_CTR_LOADING; | 1129 | ctr->state = CAPI_CTR_LOADING; |
1012 | 1130 | ||
1013 | retval = ctr->load_firmware(ctr, &ldata); | 1131 | retval = ctr->load_firmware(ctr, &ldata); |
1014 | |||
1015 | if (retval) { | 1132 | if (retval) { |
1016 | ctr->state = CAPI_CTR_DETECTED; | 1133 | ctr->state = CAPI_CTR_DETECTED; |
1017 | capi_ctr_put(ctr); | 1134 | goto load_unlock_out; |
1018 | return retval; | ||
1019 | } | 1135 | } |
1020 | 1136 | ||
1021 | while (ctr->state != CAPI_CTR_RUNNING) { | 1137 | retval = wait_on_ctr_state(ctr, CAPI_CTR_RUNNING); |
1022 | |||
1023 | msleep_interruptible(100); /* 0.1 sec */ | ||
1024 | 1138 | ||
1025 | if (signal_pending(current)) { | 1139 | load_unlock_out: |
1026 | capi_ctr_put(ctr); | 1140 | mutex_unlock(&capi_controller_lock); |
1027 | return -EINTR; | 1141 | return retval; |
1028 | } | ||
1029 | } | ||
1030 | capi_ctr_put(ctr); | ||
1031 | return 0; | ||
1032 | 1142 | ||
1033 | case AVMB1_RESETCARD: | 1143 | case AVMB1_RESETCARD: |
1034 | if (copy_from_user(&rdef, data, sizeof(avmb1_resetdef))) | 1144 | if (copy_from_user(&rdef, data, sizeof(avmb1_resetdef))) |
1035 | return -EFAULT; | 1145 | return -EFAULT; |
1146 | |||
1147 | retval = 0; | ||
1148 | |||
1149 | mutex_lock(&capi_controller_lock); | ||
1150 | |||
1036 | ctr = get_capi_ctr_by_nr(rdef.contr); | 1151 | ctr = get_capi_ctr_by_nr(rdef.contr); |
1037 | if (!ctr) | 1152 | if (!ctr) { |
1038 | return -ESRCH; | 1153 | retval = -ESRCH; |
1154 | goto reset_unlock_out; | ||
1155 | } | ||
1039 | 1156 | ||
1040 | if (ctr->state == CAPI_CTR_DETECTED) | 1157 | if (ctr->state == CAPI_CTR_DETECTED) |
1041 | return 0; | 1158 | goto reset_unlock_out; |
1042 | 1159 | ||
1043 | ctr->reset_ctr(ctr); | 1160 | ctr->reset_ctr(ctr); |
1044 | 1161 | ||
1045 | while (ctr->state > CAPI_CTR_DETECTED) { | 1162 | retval = wait_on_ctr_state(ctr, CAPI_CTR_DETECTED); |
1046 | |||
1047 | msleep_interruptible(100); /* 0.1 sec */ | ||
1048 | |||
1049 | if (signal_pending(current)) | ||
1050 | return -EINTR; | ||
1051 | } | ||
1052 | return 0; | ||
1053 | 1163 | ||
1164 | reset_unlock_out: | ||
1165 | mutex_unlock(&capi_controller_lock); | ||
1166 | return retval; | ||
1054 | } | 1167 | } |
1055 | return -EINVAL; | 1168 | return -EINVAL; |
1056 | } | 1169 | } |
@@ -1068,6 +1181,7 @@ static int old_capi_manufacturer(unsigned int cmd, void __user *data) | |||
1068 | int capi20_manufacturer(unsigned int cmd, void __user *data) | 1181 | int capi20_manufacturer(unsigned int cmd, void __user *data) |
1069 | { | 1182 | { |
1070 | struct capi_ctr *ctr; | 1183 | struct capi_ctr *ctr; |
1184 | int retval; | ||
1071 | 1185 | ||
1072 | switch (cmd) { | 1186 | switch (cmd) { |
1073 | #ifdef AVMB1_COMPAT | 1187 | #ifdef AVMB1_COMPAT |
@@ -1085,14 +1199,20 @@ int capi20_manufacturer(unsigned int cmd, void __user *data) | |||
1085 | if (copy_from_user(&fdef, data, sizeof(kcapi_flagdef))) | 1199 | if (copy_from_user(&fdef, data, sizeof(kcapi_flagdef))) |
1086 | return -EFAULT; | 1200 | return -EFAULT; |
1087 | 1201 | ||
1202 | mutex_lock(&capi_controller_lock); | ||
1203 | |||
1088 | ctr = get_capi_ctr_by_nr(fdef.contr); | 1204 | ctr = get_capi_ctr_by_nr(fdef.contr); |
1089 | if (!ctr) | 1205 | if (ctr) { |
1090 | return -ESRCH; | 1206 | ctr->traceflag = fdef.flag; |
1207 | printk(KERN_INFO "kcapi: contr [%03d] set trace=%d\n", | ||
1208 | ctr->cnr, ctr->traceflag); | ||
1209 | retval = 0; | ||
1210 | } else | ||
1211 | retval = -ESRCH; | ||
1212 | |||
1213 | mutex_unlock(&capi_controller_lock); | ||
1091 | 1214 | ||
1092 | ctr->traceflag = fdef.flag; | 1215 | return retval; |
1093 | printk(KERN_INFO "kcapi: contr [%03d] set trace=%d\n", | ||
1094 | ctr->cnr, ctr->traceflag); | ||
1095 | return 0; | ||
1096 | } | 1216 | } |
1097 | case KCAPI_CMD_ADDCARD: | 1217 | case KCAPI_CMD_ADDCARD: |
1098 | { | 1218 | { |
@@ -1100,7 +1220,6 @@ int capi20_manufacturer(unsigned int cmd, void __user *data) | |||
1100 | struct capi_driver *driver = NULL; | 1220 | struct capi_driver *driver = NULL; |
1101 | capicardparams cparams; | 1221 | capicardparams cparams; |
1102 | kcapi_carddef cdef; | 1222 | kcapi_carddef cdef; |
1103 | int retval; | ||
1104 | 1223 | ||
1105 | if ((retval = copy_from_user(&cdef, data, sizeof(cdef)))) | 1224 | if ((retval = copy_from_user(&cdef, data, sizeof(cdef)))) |
1106 | return retval; | 1225 | return retval; |