Lines Matching +full:cpu +full:- +full:viewed

1 // SPDX-License-Identifier: GPL-2.0-or-later
5 * Copyright (C) 1995-1997 Jan "Yenya" Kasprzak <kas@fi.muni.cz>
20 * For Linux-specific utilities, see below in the "Software info" section.
24 * is a 2-port intelligent (with its own 8-bit CPU) synchronous serial card
28 * "scythe") is a next-generation sync/async board with two interfaces
29 * - currently any of V.24, X.21, V.35 and V.36 can be selected.
30 * It has a 16-bit SAB80166 CPU and can do up to 10 Mb/s per channel.
31 * The 8-channels version is in development.
34 * COSA can be also a bus-mastering device.
39 * The CVS tree of Linux driver can be viewed there, as well as the
40 * firmware binaries and user-space utilities for downloading the firmware
43 * The Linux driver (unlike the present *BSD drivers :-) can work even
52 * interested in the SMP and/or muliti-channel success/failure reports
53 * (I wonder if I did the locking properly :-).
95 /* Per-channel data structure */
98 int usage; /* Usage count; >0 for chrdev, -1 for netdev */
100 struct cosa_data *cosa; /* Pointer to the per-card structure */
126 /* cosa->firmware_status bits */
133 char name[COSA_MAX_NAME]; /* Card name - e.g "cosa0" */
177 * macro doesn't like anything other than the raw number as an argument :-(
180 /* #define MAX_CARDS (1 << (8-CARD_MINOR_BITS)) */
185 #define DRIVER_TXMAP_MASK 0x0c /* FIXME: 0xfc for 8-channel version */
188 * for cosa->rxtx - indicates whether either transmit or receive is
216 static int irq[MAX_CARDS+1] = { -1, -1, -1, -1, -1, -1, 0, };
247 #define is_8bit(cosa) (!(cosa->datareg & 0x08))
249 #define cosa_getstatus(cosa) (cosa_inb(cosa->statusreg))
250 #define cosa_putstatus(cosa, stat) (cosa_outb(stat, cosa->statusreg))
251 #define cosa_getdata16(cosa) (cosa_inw(cosa->datareg))
252 #define cosa_getdata8(cosa) (cosa_inb(cosa->datareg))
253 #define cosa_putdata16(cosa, dt) (cosa_outw(dt, cosa->datareg))
254 #define cosa_putdata8(cosa, dt) (cosa_outb(dt, cosa->datareg))
342 return (struct channel_data *)dev_to_hdlc(dev)->priv; in dev_to_chan()
345 /* ---------- Initialization stuff ---------- */
354 err = -EIO; in cosa_init()
360 err = -EIO; in cosa_init()
365 cosa_cards[i].num = -1; in cosa_init()
371 err = -ENODEV; in cosa_init()
401 for (cosa = cosa_cards; nr_cards--; cosa++) { in cosa_exit()
402 /* Clean up the per-channel data */ in cosa_exit()
403 for (i = 0; i < cosa->nchannels; i++) { in cosa_exit()
404 /* Chardev driver has no alloc'd per-channel data */ in cosa_exit()
405 unregister_hdlc_device(cosa->chan[i].netdev); in cosa_exit()
406 free_netdev(cosa->chan[i].netdev); in cosa_exit()
408 /* Clean up the per-card data */ in cosa_exit()
409 kfree(cosa->chan); in cosa_exit()
410 kfree(cosa->bouncebuf); in cosa_exit()
411 free_irq(cosa->irq, cosa); in cosa_exit()
412 free_dma(cosa->dma); in cosa_exit()
413 release_region(cosa->datareg, is_8bit(cosa) ? 2 : 4); in cosa_exit()
435 /* IRQ should be 2-7 or 10-15; negative IRQ means autoprobe */ in cosa_probe()
438 return -1; in cosa_probe()
444 return -1; in cosa_probe()
446 /* DMA should be 0,1 or 3-7 */ in cosa_probe()
449 return -1; in cosa_probe()
451 /* and finally, on 16-bit COSA DMA should be 4-7 and in cosa_probe()
456 return -1; in cosa_probe()
459 cosa->dma = dma; in cosa_probe()
460 cosa->datareg = base; in cosa_probe()
461 cosa->statusreg = is_8bit(cosa)?base+1:base+2; in cosa_probe()
462 spin_lock_init(&cosa->lock); in cosa_probe()
465 return -1; in cosa_probe()
467 if (cosa_reset_and_read_id(cosa, cosa->id_string) < 0) { in cosa_probe()
469 err = -1; in cosa_probe()
474 if (!strncmp(cosa->id_string, "SRP", 3)) in cosa_probe()
475 cosa->type = "srp"; in cosa_probe()
476 else if (!strncmp(cosa->id_string, "COSA", 4)) in cosa_probe()
477 cosa->type = is_8bit(cosa)? "cosa8": "cosa16"; in cosa_probe()
483 err = -1; in cosa_probe()
488 if (!request_region(base, is_8bit(cosa)?2:4, cosa->type)) { in cosa_probe()
490 return -1; in cosa_probe()
515 irq, cosa->datareg); in cosa_probe()
516 err = -1; in cosa_probe()
521 cosa->datareg); in cosa_probe()
522 /* return -1; */ in cosa_probe()
526 cosa->irq = irq; in cosa_probe()
527 cosa->num = nr_cards; in cosa_probe()
528 cosa->usage = 0; in cosa_probe()
529 cosa->nchannels = 2; /* FIXME: how to determine this? */ in cosa_probe()
531 if (request_irq(cosa->irq, cosa_interrupt, 0, cosa->type, cosa)) { in cosa_probe()
532 err = -1; in cosa_probe()
535 if (request_dma(cosa->dma, cosa->type)) { in cosa_probe()
536 err = -1; in cosa_probe()
540 cosa->bouncebuf = kmalloc(COSA_MTU, GFP_KERNEL|GFP_DMA); in cosa_probe()
541 if (!cosa->bouncebuf) { in cosa_probe()
542 err = -ENOMEM; in cosa_probe()
545 sprintf(cosa->name, "cosa%d", cosa->num); in cosa_probe()
547 /* Initialize the per-channel data */ in cosa_probe()
548 cosa->chan = kcalloc(cosa->nchannels, sizeof(struct channel_data), GFP_KERNEL); in cosa_probe()
549 if (!cosa->chan) { in cosa_probe()
550 err = -ENOMEM; in cosa_probe()
554 for (i = 0; i < cosa->nchannels; i++) { in cosa_probe()
555 struct channel_data *chan = &cosa->chan[i]; in cosa_probe()
557 chan->cosa = cosa; in cosa_probe()
558 chan->num = i; in cosa_probe()
559 sprintf(chan->name, "cosa%dc%d", chan->cosa->num, i); in cosa_probe()
562 mutex_init(&chan->rlock); in cosa_probe()
563 sema_init(&chan->wsem, 1); in cosa_probe()
566 if (!(chan->netdev = alloc_hdlcdev(chan))) { in cosa_probe()
567 pr_warn("%s: alloc_hdlcdev failed\n", chan->name); in cosa_probe()
568 err = -ENOMEM; in cosa_probe()
571 dev_to_hdlc(chan->netdev)->attach = cosa_net_attach; in cosa_probe()
572 dev_to_hdlc(chan->netdev)->xmit = cosa_net_tx; in cosa_probe()
573 chan->netdev->netdev_ops = &cosa_ops; in cosa_probe()
574 chan->netdev->watchdog_timeo = TX_TIMEOUT; in cosa_probe()
575 chan->netdev->base_addr = chan->cosa->datareg; in cosa_probe()
576 chan->netdev->irq = chan->cosa->irq; in cosa_probe()
577 chan->netdev->dma = chan->cosa->dma; in cosa_probe()
578 err = register_hdlc_device(chan->netdev); in cosa_probe()
580 netdev_warn(chan->netdev, in cosa_probe()
582 free_netdev(chan->netdev); in cosa_probe()
588 cosa->num, cosa->id_string, cosa->type, in cosa_probe()
589 cosa->datareg, cosa->irq, cosa->dma, cosa->nchannels); in cosa_probe()
594 while (i-- > 0) { in cosa_probe()
595 unregister_hdlc_device(cosa->chan[i].netdev); in cosa_probe()
596 free_netdev(cosa->chan[i].netdev); in cosa_probe()
598 kfree(cosa->chan); in cosa_probe()
600 kfree(cosa->bouncebuf); in cosa_probe()
602 free_dma(cosa->dma); in cosa_probe()
604 free_irq(cosa->irq, cosa); in cosa_probe()
606 release_region(cosa->datareg,is_8bit(cosa)?2:4); in cosa_probe()
607 pr_notice("cosa%d: allocating resources failed\n", cosa->num); in cosa_probe()
612 /*---------- network device ---------- */
619 return -EINVAL; in cosa_net_attach()
628 if (!(chan->cosa->firmware_status & COSA_FW_START)) { in cosa_net_open()
630 chan->cosa->name, chan->cosa->firmware_status); in cosa_net_open()
631 return -EPERM; in cosa_net_open()
633 spin_lock_irqsave(&chan->cosa->lock, flags); in cosa_net_open()
634 if (chan->usage != 0) { in cosa_net_open()
636 chan->name, chan->usage); in cosa_net_open()
637 spin_unlock_irqrestore(&chan->cosa->lock, flags); in cosa_net_open()
638 return -EBUSY; in cosa_net_open()
640 chan->setup_rx = cosa_net_setup_rx; in cosa_net_open()
641 chan->tx_done = cosa_net_tx_done; in cosa_net_open()
642 chan->rx_done = cosa_net_rx_done; in cosa_net_open()
643 chan->usage = -1; in cosa_net_open()
644 chan->cosa->usage++; in cosa_net_open()
645 spin_unlock_irqrestore(&chan->cosa->lock, flags); in cosa_net_open()
649 spin_lock_irqsave(&chan->cosa->lock, flags); in cosa_net_open()
650 chan->usage = 0; in cosa_net_open()
651 chan->cosa->usage--; in cosa_net_open()
652 spin_unlock_irqrestore(&chan->cosa->lock, flags); in cosa_net_open()
668 chan->tx_skb = skb; in cosa_net_tx()
669 cosa_start_tx(chan, skb->data, skb->len); in cosa_net_tx()
677 if (test_bit(RXBIT, &chan->cosa->rxtx)) { in cosa_net_timeout()
678 chan->netdev->stats.rx_errors++; in cosa_net_timeout()
679 chan->netdev->stats.rx_missed_errors++; in cosa_net_timeout()
681 chan->netdev->stats.tx_errors++; in cosa_net_timeout()
682 chan->netdev->stats.tx_aborted_errors++; in cosa_net_timeout()
684 cosa_kick(chan->cosa); in cosa_net_timeout()
685 if (chan->tx_skb) { in cosa_net_timeout()
686 dev_kfree_skb(chan->tx_skb); in cosa_net_timeout()
687 chan->tx_skb = NULL; in cosa_net_timeout()
700 spin_lock_irqsave(&chan->cosa->lock, flags); in cosa_net_close()
701 if (chan->rx_skb) { in cosa_net_close()
702 kfree_skb(chan->rx_skb); in cosa_net_close()
703 chan->rx_skb = NULL; in cosa_net_close()
705 if (chan->tx_skb) { in cosa_net_close()
706 kfree_skb(chan->tx_skb); in cosa_net_close()
707 chan->tx_skb = NULL; in cosa_net_close()
709 chan->usage = 0; in cosa_net_close()
710 chan->cosa->usage--; in cosa_net_close()
711 spin_unlock_irqrestore(&chan->cosa->lock, flags); in cosa_net_close()
718 * We can safely fall back to non-dma-able memory, because we have in cosa_net_setup_rx()
719 * the cosa->bouncebuf pre-allocated. in cosa_net_setup_rx()
721 kfree_skb(chan->rx_skb); in cosa_net_setup_rx()
722 chan->rx_skb = dev_alloc_skb(size); in cosa_net_setup_rx()
723 if (chan->rx_skb == NULL) { in cosa_net_setup_rx()
724 pr_notice("%s: Memory squeeze, dropping packet\n", chan->name); in cosa_net_setup_rx()
725 chan->netdev->stats.rx_dropped++; in cosa_net_setup_rx()
728 netif_trans_update(chan->netdev); in cosa_net_setup_rx()
729 return skb_put(chan->rx_skb, size); in cosa_net_setup_rx()
734 if (!chan->rx_skb) { in cosa_net_rx_done()
735 pr_warn("%s: rx_done with empty skb!\n", chan->name); in cosa_net_rx_done()
736 chan->netdev->stats.rx_errors++; in cosa_net_rx_done()
737 chan->netdev->stats.rx_frame_errors++; in cosa_net_rx_done()
740 chan->rx_skb->protocol = hdlc_type_trans(chan->rx_skb, chan->netdev); in cosa_net_rx_done()
741 chan->rx_skb->dev = chan->netdev; in cosa_net_rx_done()
742 skb_reset_mac_header(chan->rx_skb); in cosa_net_rx_done()
743 chan->netdev->stats.rx_packets++; in cosa_net_rx_done()
744 chan->netdev->stats.rx_bytes += chan->cosa->rxsize; in cosa_net_rx_done()
745 netif_rx(chan->rx_skb); in cosa_net_rx_done()
746 chan->rx_skb = NULL; in cosa_net_rx_done()
753 if (!chan->tx_skb) { in cosa_net_tx_done()
754 pr_warn("%s: tx_done with empty skb!\n", chan->name); in cosa_net_tx_done()
755 chan->netdev->stats.tx_errors++; in cosa_net_tx_done()
756 chan->netdev->stats.tx_aborted_errors++; in cosa_net_tx_done()
759 dev_consume_skb_irq(chan->tx_skb); in cosa_net_tx_done()
760 chan->tx_skb = NULL; in cosa_net_tx_done()
761 chan->netdev->stats.tx_packets++; in cosa_net_tx_done()
762 chan->netdev->stats.tx_bytes += size; in cosa_net_tx_done()
763 netif_wake_queue(chan->netdev); in cosa_net_tx_done()
767 /*---------- Character device ---------- */
774 struct channel_data *chan = file->private_data; in cosa_read()
775 struct cosa_data *cosa = chan->cosa; in cosa_read()
778 if (!(cosa->firmware_status & COSA_FW_START)) { in cosa_read()
780 cosa->name, cosa->firmware_status); in cosa_read()
781 return -EPERM; in cosa_read()
783 if (mutex_lock_interruptible(&chan->rlock)) in cosa_read()
784 return -ERESTARTSYS; in cosa_read()
786 chan->rxdata = kmalloc(COSA_MTU, GFP_DMA|GFP_KERNEL); in cosa_read()
787 if (chan->rxdata == NULL) { in cosa_read()
788 mutex_unlock(&chan->rlock); in cosa_read()
789 return -ENOMEM; in cosa_read()
792 chan->rx_status = 0; in cosa_read()
794 spin_lock_irqsave(&cosa->lock, flags); in cosa_read()
795 add_wait_queue(&chan->rxwaitq, &wait); in cosa_read()
796 while (!chan->rx_status) { in cosa_read()
798 spin_unlock_irqrestore(&cosa->lock, flags); in cosa_read()
800 spin_lock_irqsave(&cosa->lock, flags); in cosa_read()
801 if (signal_pending(current) && chan->rx_status == 0) { in cosa_read()
802 chan->rx_status = 1; in cosa_read()
803 remove_wait_queue(&chan->rxwaitq, &wait); in cosa_read()
805 spin_unlock_irqrestore(&cosa->lock, flags); in cosa_read()
806 mutex_unlock(&chan->rlock); in cosa_read()
807 return -ERESTARTSYS; in cosa_read()
810 remove_wait_queue(&chan->rxwaitq, &wait); in cosa_read()
812 kbuf = chan->rxdata; in cosa_read()
813 count = chan->rxsize; in cosa_read()
814 spin_unlock_irqrestore(&cosa->lock, flags); in cosa_read()
815 mutex_unlock(&chan->rlock); in cosa_read()
819 return -EFAULT; in cosa_read()
828 chan->rxsize = size; in chrdev_setup_rx()
829 return chan->rxdata; in chrdev_setup_rx()
834 if (chan->rx_status) { /* Reader has died */ in chrdev_rx_done()
835 kfree(chan->rxdata); in chrdev_rx_done()
836 up(&chan->wsem); in chrdev_rx_done()
838 chan->rx_status = 1; in chrdev_rx_done()
839 wake_up_interruptible(&chan->rxwaitq); in chrdev_rx_done()
848 struct channel_data *chan = file->private_data; in cosa_write()
849 struct cosa_data *cosa = chan->cosa; in cosa_write()
853 if (!(cosa->firmware_status & COSA_FW_START)) { in cosa_write()
855 cosa->name, cosa->firmware_status); in cosa_write()
856 return -EPERM; in cosa_write()
858 if (down_interruptible(&chan->wsem)) in cosa_write()
859 return -ERESTARTSYS; in cosa_write()
867 up(&chan->wsem); in cosa_write()
868 return -ENOMEM; in cosa_write()
871 up(&chan->wsem); in cosa_write()
873 return -EFAULT; in cosa_write()
875 chan->tx_status=0; in cosa_write()
878 spin_lock_irqsave(&cosa->lock, flags); in cosa_write()
879 add_wait_queue(&chan->txwaitq, &wait); in cosa_write()
880 while (!chan->tx_status) { in cosa_write()
882 spin_unlock_irqrestore(&cosa->lock, flags); in cosa_write()
884 spin_lock_irqsave(&cosa->lock, flags); in cosa_write()
885 if (signal_pending(current) && chan->tx_status == 0) { in cosa_write()
886 chan->tx_status = 1; in cosa_write()
887 remove_wait_queue(&chan->txwaitq, &wait); in cosa_write()
889 chan->tx_status = 1; in cosa_write()
890 spin_unlock_irqrestore(&cosa->lock, flags); in cosa_write()
891 up(&chan->wsem); in cosa_write()
893 return -ERESTARTSYS; in cosa_write()
896 remove_wait_queue(&chan->txwaitq, &wait); in cosa_write()
898 up(&chan->wsem); in cosa_write()
899 spin_unlock_irqrestore(&cosa->lock, flags); in cosa_write()
906 if (chan->tx_status) { /* Writer was interrupted */ in chrdev_tx_done()
907 kfree(chan->txbuf); in chrdev_tx_done()
908 up(&chan->wsem); in chrdev_tx_done()
910 chan->tx_status = 1; in chrdev_tx_done()
911 wake_up_interruptible(&chan->txwaitq); in chrdev_tx_done()
932 ret = -ENODEV; in cosa_open()
938 & ((1<<CARD_MINOR_BITS)-1)) >= cosa->nchannels) { in cosa_open()
939 ret = -ENODEV; in cosa_open()
942 chan = cosa->chan + n; in cosa_open()
944 file->private_data = chan; in cosa_open()
946 spin_lock_irqsave(&cosa->lock, flags); in cosa_open()
948 if (chan->usage < 0) { /* in netdev mode */ in cosa_open()
949 spin_unlock_irqrestore(&cosa->lock, flags); in cosa_open()
950 ret = -EBUSY; in cosa_open()
953 cosa->usage++; in cosa_open()
954 chan->usage++; in cosa_open()
956 chan->tx_done = chrdev_tx_done; in cosa_open()
957 chan->setup_rx = chrdev_setup_rx; in cosa_open()
958 chan->rx_done = chrdev_rx_done; in cosa_open()
959 spin_unlock_irqrestore(&cosa->lock, flags); in cosa_open()
967 struct channel_data *channel = file->private_data; in cosa_release()
971 cosa = channel->cosa; in cosa_release()
972 spin_lock_irqsave(&cosa->lock, flags); in cosa_release()
973 cosa->usage--; in cosa_release()
974 channel->usage--; in cosa_release()
975 spin_unlock_irqrestore(&cosa->lock, flags); in cosa_release()
992 /* ---------- Ioctls ---------- */
1001 if (cosa->usage > 1) in cosa_reset()
1002 pr_info("cosa%d: WARNING: reset requested with cosa->usage > 1 (%d). Odd things may happen.\n", in cosa_reset()
1003 cosa->num, cosa->usage); in cosa_reset()
1004 cosa->firmware_status &= ~(COSA_FW_RESET|COSA_FW_START); in cosa_reset()
1006 pr_notice("cosa%d: reset failed\n", cosa->num); in cosa_reset()
1007 return -EIO; in cosa_reset()
1009 pr_info("cosa%d: resetting device: %s\n", cosa->num, idstring); in cosa_reset()
1010 cosa->firmware_status |= COSA_FW_RESET; in cosa_reset()
1014 /* High-level function to download data into COSA memory. Calls download() */
1020 if (cosa->usage > 1) in cosa_download()
1021 …pr_info("%s: WARNING: download of microcode requested with cosa->usage > 1 (%d). Odd things may ha… in cosa_download()
1022 cosa->name, cosa->usage); in cosa_download()
1023 if (!(cosa->firmware_status & COSA_FW_RESET)) { in cosa_download()
1025 cosa->name, cosa->firmware_status); in cosa_download()
1026 return -EPERM; in cosa_download()
1030 return -EFAULT; in cosa_download()
1033 return -EINVAL; in cosa_download()
1035 return -EINVAL; in cosa_download()
1039 cosa->firmware_status &= ~(COSA_FW_RESET|COSA_FW_DOWNLOAD); in cosa_download()
1044 cosa->num, i); in cosa_download()
1045 return -EIO; in cosa_download()
1047 pr_info("cosa%d: downloading microcode - 0x%04x bytes at 0x%04x\n", in cosa_download()
1048 cosa->num, d.len, d.addr); in cosa_download()
1049 cosa->firmware_status |= COSA_FW_RESET|COSA_FW_DOWNLOAD; in cosa_download()
1053 /* High-level function to read COSA memory. Calls readmem() */
1059 if (cosa->usage > 1) in cosa_readmem()
1060 pr_info("cosa%d: WARNING: readmem requested with cosa->usage > 1 (%d). Odd things may happen.\n", in cosa_readmem()
1061 cosa->num, cosa->usage); in cosa_readmem()
1062 if (!(cosa->firmware_status & COSA_FW_RESET)) { in cosa_readmem()
1064 cosa->name, cosa->firmware_status); in cosa_readmem()
1065 return -EPERM; in cosa_readmem()
1069 return -EFAULT; in cosa_readmem()
1072 cosa->firmware_status &= ~COSA_FW_RESET; in cosa_readmem()
1076 pr_notice("cosa%d: reading memory failed: %d\n", cosa->num, i); in cosa_readmem()
1077 return -EIO; in cosa_readmem()
1079 pr_info("cosa%d: reading card memory - 0x%04x bytes at 0x%04x\n", in cosa_readmem()
1080 cosa->num, d.len, d.addr); in cosa_readmem()
1081 cosa->firmware_status |= COSA_FW_RESET; in cosa_readmem()
1085 /* High-level function to start microcode. Calls startmicrocode(). */
1090 if (cosa->usage > 1) in cosa_start()
1091 …pr_info("cosa%d: WARNING: start microcode requested with cosa->usage > 1 (%d). Odd things may happ… in cosa_start()
1092 cosa->num, cosa->usage); in cosa_start()
1094 if ((cosa->firmware_status & (COSA_FW_RESET|COSA_FW_DOWNLOAD)) in cosa_start()
1097 cosa->name, cosa->firmware_status); in cosa_start()
1098 return -EPERM; in cosa_start()
1100 cosa->firmware_status &= ~COSA_FW_RESET; in cosa_start()
1103 cosa->num, address, i); in cosa_start()
1104 return -EIO; in cosa_start()
1106 pr_info("cosa%d: starting microcode at 0x%04x\n", cosa->num, address); in cosa_start()
1107 cosa->startaddr = address; in cosa_start()
1108 cosa->firmware_status |= COSA_FW_START; in cosa_start()
1115 int l = strlen(cosa->id_string)+1; in cosa_getidstr()
1116 if (copy_to_user(string, cosa->id_string, l)) in cosa_getidstr()
1117 return -EFAULT; in cosa_getidstr()
1124 int l = strlen(cosa->type)+1; in cosa_gettype()
1125 if (copy_to_user(string, cosa->type, l)) in cosa_gettype()
1126 return -EFAULT; in cosa_gettype()
1137 return -EACCES; in cosa_ioctl_common()
1141 return -EACCES; in cosa_ioctl_common()
1145 return -EACCES; in cosa_ioctl_common()
1150 return -EACCES; in cosa_ioctl_common()
1159 return cosa->nchannels; in cosa_ioctl_common()
1162 return -EACCES; in cosa_ioctl_common()
1164 return -EINVAL; in cosa_ioctl_common()
1166 return -EINVAL; in cosa_ioctl_common()
1167 cosa->busmaster = arg; in cosa_ioctl_common()
1170 return cosa->busmaster; in cosa_ioctl_common()
1172 return -ENOIOCTLCMD; in cosa_ioctl_common()
1179 rv = cosa_ioctl_common(chan->cosa, chan, cmd, in cosa_net_ioctl()
1180 (unsigned long)ifr->ifr_data); in cosa_net_ioctl()
1181 if (rv != -ENOIOCTLCMD) in cosa_net_ioctl()
1189 struct channel_data *channel = file->private_data; in cosa_chardev_ioctl()
1194 cosa = channel->cosa; in cosa_chardev_ioctl()
1201 /*---------- HW layer interface ---------- */
1209 struct cosa_data *cosa = chan->cosa; in cosa_enable_rx()
1211 if (!test_and_set_bit(chan->num, &cosa->rxbitmap)) in cosa_enable_rx()
1217 struct cosa_data *cosa = chan->cosa; in cosa_disable_rx()
1219 if (test_and_clear_bit(chan->num, &cosa->rxbitmap)) in cosa_disable_rx()
1225 * the previous transmit is still unfinished. In this case the non-zero
1231 struct cosa_data *cosa = chan->cosa; in cosa_start_tx()
1237 chan->cosa->num, chan->num, len); in cosa_start_tx()
1242 spin_lock_irqsave(&cosa->lock, flags); in cosa_start_tx()
1243 chan->txbuf = buf; in cosa_start_tx()
1244 chan->txsize = len; in cosa_start_tx()
1246 chan->txsize = COSA_MTU; in cosa_start_tx()
1247 spin_unlock_irqrestore(&cosa->lock, flags); in cosa_start_tx()
1250 set_bit(chan->num, &cosa->txbitmap); in cosa_start_tx()
1261 spin_lock_irqsave(&cosa->lock, flags); in put_driver_status()
1263 status = (cosa->rxbitmap ? DRIVER_RX_READY : 0) in put_driver_status()
1264 | (cosa->txbitmap ? DRIVER_TX_READY : 0) in put_driver_status()
1265 | (cosa->txbitmap? ~(cosa->txbitmap<<DRIVER_TXMAP_SHIFT) in put_driver_status()
1267 if (!cosa->rxtx) { in put_driver_status()
1268 if (cosa->rxbitmap|cosa->txbitmap) { in put_driver_status()
1269 if (!cosa->enabled) { in put_driver_status()
1274 cosa->enabled = 1; in put_driver_status()
1276 } else if (cosa->enabled) { in put_driver_status()
1277 cosa->enabled = 0; in put_driver_status()
1288 spin_unlock_irqrestore(&cosa->lock, flags); in put_driver_status()
1295 status = (cosa->rxbitmap ? DRIVER_RX_READY : 0) in put_driver_status_nolock()
1296 | (cosa->txbitmap ? DRIVER_TX_READY : 0) in put_driver_status_nolock()
1297 | (cosa->txbitmap? ~(cosa->txbitmap<<DRIVER_TXMAP_SHIFT) in put_driver_status_nolock()
1300 if (cosa->rxbitmap|cosa->txbitmap) { in put_driver_status_nolock()
1305 cosa->enabled = 1; in put_driver_status_nolock()
1311 cosa->enabled = 0; in put_driver_status_nolock()
1329 if (test_bit(RXBIT, &cosa->rxtx)) in cosa_kick()
1331 if (test_bit(TXBIT, &cosa->rxtx)) in cosa_kick()
1334 pr_info("%s: %s timeout - restarting\n", cosa->name, s); in cosa_kick()
1335 spin_lock_irqsave(&cosa->lock, flags); in cosa_kick()
1336 cosa->rxtx = 0; in cosa_kick()
1339 disable_dma(cosa->dma); in cosa_kick()
1340 clear_dma_ff(cosa->dma); in cosa_kick()
1352 spin_unlock_irqrestore(&cosa->lock, flags); in cosa_kick()
1356 * Check if the whole buffer is DMA-able. It means it is below the 16M of
1369 chan->name); in cosa_dma_able()
1376 /* ---------- The SRP/COSA ROM monitor functions ---------- */
1380 * drivers need to say 4-digit hex number meaning start address of the microcode
1382 * has to write 4-digit hex number meaning the last byte address ended
1390 if (put_wait_data(cosa, 'w') == -1) return -1; in download()
1391 if ((i=get_wait_data(cosa)) != 'w') { printk("dnld: 0x%04x\n",i); return -2;} in download()
1392 if (get_wait_data(cosa) != '=') return -3; in download()
1394 if (puthexnumber(cosa, address) < 0) return -4; in download()
1395 if (put_wait_data(cosa, ' ') == -1) return -10; in download()
1396 if (get_wait_data(cosa) != ' ') return -11; in download()
1397 if (get_wait_data(cosa) != '=') return -12; in download()
1399 if (puthexnumber(cosa, address+length-1) < 0) return -13; in download()
1400 if (put_wait_data(cosa, ' ') == -1) return -18; in download()
1401 if (get_wait_data(cosa) != ' ') return -19; in download()
1403 while (length--) { in download()
1407 return -23; /* ??? */ in download()
1411 if (put_wait_data(cosa, c) == -1) in download()
1412 return -20; in download()
1416 if (get_wait_data(cosa) != '\r') return -21; in download()
1417 if (get_wait_data(cosa) != '\n') return -22; in download()
1418 if (get_wait_data(cosa) != '.') return -23; in download()
1420 printk(KERN_DEBUG "cosa%d: download completed.\n", cosa->num); in download()
1433 if (put_wait_data(cosa, 'g') == -1) return -1; in startmicrocode()
1434 if (get_wait_data(cosa) != 'g') return -2; in startmicrocode()
1435 if (get_wait_data(cosa) != '=') return -3; in startmicrocode()
1437 if (puthexnumber(cosa, address) < 0) return -4; in startmicrocode()
1438 if (put_wait_data(cosa, '\r') == -1) return -5; in startmicrocode()
1440 if (get_wait_data(cosa) != '\r') return -6; in startmicrocode()
1441 if (get_wait_data(cosa) != '\r') return -7; in startmicrocode()
1442 if (get_wait_data(cosa) != '\n') return -8; in startmicrocode()
1443 if (get_wait_data(cosa) != '\r') return -9; in startmicrocode()
1444 if (get_wait_data(cosa) != '\n') return -10; in startmicrocode()
1446 printk(KERN_DEBUG "cosa%d: microcode started\n", cosa->num); in startmicrocode()
1462 if (put_wait_data(cosa, 'r') == -1) return -1; in readmem()
1463 if ((get_wait_data(cosa)) != 'r') return -2; in readmem()
1464 if ((get_wait_data(cosa)) != '=') return -3; in readmem()
1466 if (puthexnumber(cosa, address) < 0) return -4; in readmem()
1467 if (put_wait_data(cosa, ' ') == -1) return -5; in readmem()
1468 if (get_wait_data(cosa) != ' ') return -6; in readmem()
1469 if (get_wait_data(cosa) != '=') return -7; in readmem()
1471 if (puthexnumber(cosa, address+length-1) < 0) return -8; in readmem()
1472 if (put_wait_data(cosa, ' ') == -1) return -9; in readmem()
1473 if (get_wait_data(cosa) != ' ') return -10; in readmem()
1475 while (length--) { in readmem()
1478 if ((i=get_wait_data(cosa)) == -1) { in readmem()
1480 return -11; in readmem()
1485 return -23; /* ??? */ in readmem()
1492 if (get_wait_data(cosa) != '\r') return -21; in readmem()
1493 if (get_wait_data(cosa) != '\n') return -22; in readmem()
1494 if (get_wait_data(cosa) != '.') return -23; in readmem()
1496 printk(KERN_DEBUG "cosa%d: readmem completed.\n", cosa->num); in readmem()
1525 for (i=0; i<COSA_MAX_ID_STRING-1; i++, prev=curr) { in cosa_reset_and_read_id()
1526 if ((curr = get_wait_data(cosa)) == -1) { in cosa_reset_and_read_id()
1527 return -1; in cosa_reset_and_read_id()
1535 /* Perhaps we should fail when i==COSA_MAX_ID_STRING-1 ? */ in cosa_reset_and_read_id()
1541 /* ---------- Auxiliary routines for COSA/SRP monitor ---------- */
1552 while (--retries) { in get_wait_data()
1559 999-retries); in get_wait_data()
1568 return -1; in get_wait_data()
1579 while (--retries) { in put_wait_data()
1584 pr_info("Putdata: %d retries\n", 999-retries); in put_wait_data()
1594 cosa->num, cosa_getstatus(cosa)); in put_wait_data()
1595 return -1; in put_wait_data()
1601 * negative number on failure (-1,-3,-5,-7) means that put_wait_data() failed,
1602 * (-2,-4,-6,-8) means that reading echo failed.
1612 if (put_wait_data(cosa, temp[i]) == -1) { in puthexnumber()
1614 cosa->num, i); in puthexnumber()
1615 return -1-2*i; in puthexnumber()
1619 cosa->num, i); in puthexnumber()
1620 return -2-2*i; in puthexnumber()
1627 /* ---------- Interrupt routines ---------- */
1631 * At the beginning of transmit - this handled is in tx_interrupt(),
1632 * at the beginning of receive - it is in rx_interrupt() and
1633 * at the end of transmit/receive - it is the eot_interrupt() function.
1639 * In the COSA bus-master mode, we need to tell the card the address of a
1640 * buffer. Unfortunately, COSA may be too slow for us, so we must busy-wait.
1641 * It's time to use the bottom half :-(
1645 * Transmit interrupt routine - called when COSA is willing to obtain
1648 * use the round-robin approach. The newer COSA firmwares have a simple
1649 * flow-control - in the status word has bits 2 and 3 set to 1 means that the
1656 * the TX interrupt but does not mark the channel as ready-to-transmit.
1664 pr_info("cosa%d: SR_DOWN_REQUEST status=0x%04x\n", cosa->num, status); in tx_interrupt()
1666 spin_lock_irqsave(&cosa->lock, flags); in tx_interrupt()
1667 set_bit(TXBIT, &cosa->rxtx); in tx_interrupt()
1668 if (!test_bit(IRQBIT, &cosa->rxtx)) { in tx_interrupt()
1671 if (!cosa->txbitmap) { in tx_interrupt()
1673 cosa->name); in tx_interrupt()
1675 clear_bit(TXBIT, &cosa->rxtx); in tx_interrupt()
1676 spin_unlock_irqrestore(&cosa->lock, flags); in tx_interrupt()
1680 cosa->txchan++; in tx_interrupt()
1682 if (cosa->txchan >= cosa->nchannels) in tx_interrupt()
1683 cosa->txchan = 0; in tx_interrupt()
1684 if (!(cosa->txbitmap & (1<<cosa->txchan))) in tx_interrupt()
1686 if (~status & (1 << (cosa->txchan+DRIVER_TXMAP_SHIFT))) in tx_interrupt()
1688 /* in second pass, accept first ready-to-TX channel */ in tx_interrupt()
1689 if (i > cosa->nchannels) { in tx_interrupt()
1693 "to not-ready channel %d\n", in tx_interrupt()
1694 cosa->name, cosa->txchan); in tx_interrupt()
1700 cosa->txsize = cosa->chan[cosa->txchan].txsize; in tx_interrupt()
1701 if (cosa_dma_able(cosa->chan+cosa->txchan, in tx_interrupt()
1702 cosa->chan[cosa->txchan].txbuf, cosa->txsize)) { in tx_interrupt()
1703 cosa->txbuf = cosa->chan[cosa->txchan].txbuf; in tx_interrupt()
1705 memcpy(cosa->bouncebuf, cosa->chan[cosa->txchan].txbuf, in tx_interrupt()
1706 cosa->txsize); in tx_interrupt()
1707 cosa->txbuf = cosa->bouncebuf; in tx_interrupt()
1712 if (!test_bit(IRQBIT, &cosa->rxtx)) { in tx_interrupt()
1714 cosa_putdata8(cosa, ((cosa->txchan << 5) & 0xe0)| in tx_interrupt()
1715 ((cosa->txsize >> 8) & 0x1f)); in tx_interrupt()
1718 debug_data_out(cosa, ((cosa->txchan << 5) & 0xe0)| in tx_interrupt()
1719 ((cosa->txsize >> 8) & 0x1f)); in tx_interrupt()
1724 set_bit(IRQBIT, &cosa->rxtx); in tx_interrupt()
1725 spin_unlock_irqrestore(&cosa->lock, flags); in tx_interrupt()
1728 clear_bit(IRQBIT, &cosa->rxtx); in tx_interrupt()
1730 cosa_putdata8(cosa, cosa->txsize&0xff); in tx_interrupt()
1733 debug_data_out(cosa, cosa->txsize&0xff); in tx_interrupt()
1738 cosa_putdata16(cosa, ((cosa->txchan<<13) & 0xe000) in tx_interrupt()
1739 | (cosa->txsize & 0x1fff)); in tx_interrupt()
1742 debug_data_out(cosa, ((cosa->txchan<<13) & 0xe000) in tx_interrupt()
1743 | (cosa->txsize & 0x1fff)); in tx_interrupt()
1752 if (cosa->busmaster) { in tx_interrupt()
1753 unsigned long addr = virt_to_bus(cosa->txbuf); in tx_interrupt()
1774 set_dma_mode(cosa->dma, DMA_MODE_CASCADE); in tx_interrupt()
1775 enable_dma(cosa->dma); in tx_interrupt()
1780 disable_dma(cosa->dma); in tx_interrupt()
1781 clear_dma_ff(cosa->dma); in tx_interrupt()
1782 set_dma_mode(cosa->dma, DMA_MODE_WRITE); in tx_interrupt()
1783 set_dma_addr(cosa->dma, virt_to_bus(cosa->txbuf)); in tx_interrupt()
1784 set_dma_count(cosa->dma, cosa->txsize); in tx_interrupt()
1785 enable_dma(cosa->dma); in tx_interrupt()
1792 spin_unlock_irqrestore(&cosa->lock, flags); in tx_interrupt()
1799 pr_info("cosa%d: SR_UP_REQUEST\n", cosa->num); in rx_interrupt()
1802 spin_lock_irqsave(&cosa->lock, flags); in rx_interrupt()
1803 set_bit(RXBIT, &cosa->rxtx); in rx_interrupt()
1806 if (!test_bit(IRQBIT, &cosa->rxtx)) { in rx_interrupt()
1807 set_bit(IRQBIT, &cosa->rxtx); in rx_interrupt()
1809 cosa->rxsize = cosa_getdata8(cosa) <<8; in rx_interrupt()
1811 debug_data_in(cosa, cosa->rxsize >> 8); in rx_interrupt()
1813 spin_unlock_irqrestore(&cosa->lock, flags); in rx_interrupt()
1816 clear_bit(IRQBIT, &cosa->rxtx); in rx_interrupt()
1817 cosa->rxsize |= cosa_getdata8(cosa) & 0xff; in rx_interrupt()
1819 debug_data_in(cosa, cosa->rxsize & 0xff); in rx_interrupt()
1823 cosa->num, cosa->rxsize); in rx_interrupt()
1827 cosa->rxsize = cosa_getdata16(cosa); in rx_interrupt()
1829 debug_data_in(cosa, cosa->rxsize); in rx_interrupt()
1833 cosa->num, cosa->rxsize); in rx_interrupt()
1836 if (((cosa->rxsize & 0xe000) >> 13) >= cosa->nchannels) { in rx_interrupt()
1838 cosa->name, cosa->rxsize); in rx_interrupt()
1839 spin_unlock_irqrestore(&cosa->lock, flags); in rx_interrupt()
1842 cosa->rxchan = cosa->chan + ((cosa->rxsize & 0xe000) >> 13); in rx_interrupt()
1843 cosa->rxsize &= 0x1fff; in rx_interrupt()
1844 spin_unlock_irqrestore(&cosa->lock, flags); in rx_interrupt()
1846 cosa->rxbuf = NULL; in rx_interrupt()
1847 if (cosa->rxchan->setup_rx) in rx_interrupt()
1848 cosa->rxbuf = cosa->rxchan->setup_rx(cosa->rxchan, cosa->rxsize); in rx_interrupt()
1850 if (!cosa->rxbuf) { in rx_interrupt()
1853 cosa->num, cosa->rxchan->num); in rx_interrupt()
1854 cosa->rxbuf = cosa->bouncebuf; in rx_interrupt()
1859 disable_dma(cosa->dma); in rx_interrupt()
1860 clear_dma_ff(cosa->dma); in rx_interrupt()
1861 set_dma_mode(cosa->dma, DMA_MODE_READ); in rx_interrupt()
1862 if (cosa_dma_able(cosa->rxchan, cosa->rxbuf, cosa->rxsize & 0x1fff)) { in rx_interrupt()
1863 set_dma_addr(cosa->dma, virt_to_bus(cosa->rxbuf)); in rx_interrupt()
1865 set_dma_addr(cosa->dma, virt_to_bus(cosa->bouncebuf)); in rx_interrupt()
1867 set_dma_count(cosa->dma, (cosa->rxsize&0x1fff)); in rx_interrupt()
1868 enable_dma(cosa->dma); in rx_interrupt()
1870 spin_lock_irqsave(&cosa->lock, flags); in rx_interrupt()
1879 spin_unlock_irqrestore(&cosa->lock, flags); in rx_interrupt()
1885 spin_lock_irqsave(&cosa->lock, flags); in eot_interrupt()
1887 disable_dma(cosa->dma); in eot_interrupt()
1888 clear_dma_ff(cosa->dma); in eot_interrupt()
1890 if (test_bit(TXBIT, &cosa->rxtx)) { in eot_interrupt()
1891 struct channel_data *chan = cosa->chan+cosa->txchan; in eot_interrupt()
1892 if (chan->tx_done) in eot_interrupt()
1893 if (chan->tx_done(chan, cosa->txsize)) in eot_interrupt()
1894 clear_bit(chan->num, &cosa->txbitmap); in eot_interrupt()
1895 } else if (test_bit(RXBIT, &cosa->rxtx)) { in eot_interrupt()
1900 cosa->num, cosa->rxchan->num, cosa->rxsize); in eot_interrupt()
1901 for (i=0; i<cosa->rxsize; i++) in eot_interrupt()
1902 pr_cont(" %02x", cosa->rxbuf[i]&0xff); in eot_interrupt()
1907 if (cosa->rxbuf == cosa->bouncebuf) in eot_interrupt()
1909 if (!cosa_dma_able(cosa->rxchan, cosa->rxbuf, cosa->rxsize)) in eot_interrupt()
1910 memcpy(cosa->rxbuf, cosa->bouncebuf, cosa->rxsize); in eot_interrupt()
1911 if (cosa->rxchan->rx_done) in eot_interrupt()
1912 if (cosa->rxchan->rx_done(cosa->rxchan)) in eot_interrupt()
1913 clear_bit(cosa->rxchan->num, &cosa->rxbitmap); in eot_interrupt()
1915 pr_notice("cosa%d: unexpected EOT interrupt\n", cosa->num); in eot_interrupt()
1924 cosa->rxtx = 0; in eot_interrupt()
1926 spin_unlock_irqrestore(&cosa->lock, flags); in eot_interrupt()
1937 pr_info("cosa%d: got IRQ, status 0x%02x\n", cosa->num, status & 0xff); in cosa_interrupt()
1959 cosa->num, status & 0xff, count); in cosa_interrupt()
1963 pr_info("%s: %d-times got unknown status in IRQ\n", in cosa_interrupt()
1964 cosa->name, count); in cosa_interrupt()
1966 pr_info("%s: returning from IRQ\n", cosa->name); in cosa_interrupt()
1972 /* ---------- I/O debugging routines ---------- */
1997 pr_info("%s: IO: status -> 0x%02x (%s%s%s%s)\n", in debug_status_in()
1998 cosa->name, in debug_status_in()
2008 pr_info("%s: IO: status <- 0x%02x (%s%s%s%s%s%s)\n", in debug_status_out()
2009 cosa->name, in debug_status_out()
2021 pr_info("%s: IO: data -> 0x%04x\n", cosa->name, data); in debug_data_in()
2026 pr_info("%s: IO: data <- 0x%04x\n", cosa->name, data); in debug_data_out()
2031 pr_info("%s: IO: data <- 0x%04x (%s|%s)\n", in debug_data_cmd()
2032 cosa->name, data, in debug_data_cmd()
2038 /* EOF -- this file has not been truncated */