diff -Nru a/CREDITS b/CREDITS --- a/CREDITS Sun Jul 27 10:13:49 2003 +++ b/CREDITS Sun Jul 27 10:13:49 2003 @@ -3185,7 +3185,7 @@ N: Geert Uytterhoeven E: geert@linux-m68k.org W: http://home.tvd.be/cr26864/ -P: 1024/EC4A1EE1 8B 88 38 35 88 1E 95 A1 CD 9E AE DC 4B 4A 2F 41 +P: 1024/862678A6 C51D 361C 0BD1 4C90 B275 C553 6EEA 11BA 8626 78A6 D: m68k/Amiga and PPC/CHRP Longtrail coordinator D: Frame buffer device and XF68_FBDev maintainer D: m68k IDE maintainer @@ -3194,8 +3194,8 @@ D: Atari Falcon chipset IDE D: Amiga Gayle chipset IDE D: mipsel NEC DDB Vrc-5074 -S: C. Huysmansstraat 12 -S: B-3128 Baal +S: Holsbeeksesteenweg 166 +S: B-3010 Kessel-Lo S: Belgium N: Chris Vance diff -Nru a/Documentation/magic-number.txt b/Documentation/magic-number.txt --- a/Documentation/magic-number.txt Sun Jul 27 10:13:47 2003 +++ b/Documentation/magic-number.txt Sun Jul 27 10:13:47 2003 @@ -51,6 +51,13 @@ 03 Nov 2002 +Updated the magic table to Linux 2.5.74. + + Fabian Frederick + + 09 Jul 2003 + + Magic Name Number Structure File =========================================================================== PG_MAGIC 'P' pg_{read,write}_hdr include/linux/pg.h @@ -62,10 +69,12 @@ HDLC_MAGIC 0x239e n_hdlc drivers/char/n_hdlc.c APM_BIOS_MAGIC 0x4101 apm_user arch/i386/kernel/apm.c CYCLADES_MAGIC 0x4359 cyclades_port include/linux/cyclades.h +DB_MAGIC 0x4442 fc_info drivers/net/iph5526_novram.c +DL_MAGIC 0x444d fc_info drivers/net/iph5526_novram.c FASYNC_MAGIC 0x4601 fasync_struct include/linux/fs.h +FF_MAGIC 0x4646 fc_info drivers/net/iph5526_novram.c ISICOM_MAGIC 0x4d54 isi_port include/linux/isicom.h -PTY_MAGIC 0x5001 (none at the moment) - drivers/char/pty.c +PTY_MAGIC 0x5001 drivers/char/pty.c PPP_MAGIC 0x5002 ppp include/linux/if_pppvar.h SERIAL_MAGIC 0x5301 async_struct include/linux/serial.h SSTATE_MAGIC 0x5302 serial_state include/linux/serial.h @@ -81,9 +90,9 @@ MGSLPC_MAGIC 0x5402 mgslpc_info drivers/char/pcmcia/synclink_cs.c TTY_LDISC_MAGIC 0x5403 tty_ldisc include/linux/tty_ldisc.h USB_SERIAL_MAGIC 0x6702 usb_serial drivers/usb/serial/usb-serial.h +FULL_DUPLEX_MAGIC 0x6969 drivers/net/tulip/de2104x.c USB_BLUETOOTH_MAGIC 0x6d02 usb_bluetooth drivers/usb/class/bluetty.c -RFCOMM_TTY_MAGIC 0x6d02 (note at the moment) - net/bluetooth/rfcomm/tty.c +RFCOMM_TTY_MAGIC 0x6d02 net/bluetooth/rfcomm/tty.c USB_SERIAL_PORT_MAGIC 0x7301 usb_serial_port drivers/usb/serial/usb-serial.h CG_MAGIC 0x00090255 ufs_cylinder_group include/linux/ufs_fs.h A2232_MAGIC 0x000a2232 gs_port drivers/char/ser_a2232.h @@ -91,6 +100,7 @@ RPORT_MAGIC 0x00525001 r_port drivers/char/rocket_int.h LSEMAGIC 0x05091998 lse drivers/fc4/fc.c GDTIOCTL_MAGIC 0x06030f07 gdth_iowr_str drivers/scsi/gdth_ioctl.h +RIEBL_MAGIC 0x09051990 drivers/net/atarilance.c RIO_MAGIC 0x12345678 gs_port drivers/char/rio/rio_linux.c SX_MAGIC 0x12345678 gs_port drivers/char/sx.h NBD_REQUEST_MAGIC 0x12560953 nbd_request include/linux/nbd.h @@ -120,6 +130,7 @@ GDA_MAGIC 0x58464552 gda include/asm-mips64/sn/gda.h RED_MAGIC1 0x5a2cf071 (any) mm/slab.c STL_PORTMAGIC 0x5a7182c9 stlport include/linux/stallion.h +EEPROM_MAGIC_VALUE 0X5ab478d2 lanai_dev drivers/atm/lanai.c HDLCDRV_MAGIC 0x5ac6e778 hdlcdrv_state include/linux/hdlcdrv.h EPCA_MAGIC 0x5c6df104 channel include/linux/epca.h PCXX_MAGIC 0x5c6df104 channel drivers/char/pcxx.h @@ -127,9 +138,11 @@ I810_STATE_MAGIC 0x63657373 i810_state sound/oss/i810_audio.c TRIDENT_STATE_MAGIC 0x63657373 trient_state sound/oss/trident.c M3_CARD_MAGIC 0x646e6f50 m3_card sound/oss/maestro3.c +FW_HEADER_MAGIC 0x65726F66 fw_header drivers/atm/fore200e.h SLOT_MAGIC 0x67267321 slot drivers/hotplug/cpqphp.h SLOT_MAGIC 0x67267322 slot drivers/hotplug/acpiphp.h LO_MAGIC 0x68797548 nbd_device include/linux/nbd.h +OPROFILE_MAGIC 0x6f70726f super_block drivers/oprofile/oprofilefs.h M3_STATE_MAGIC 0x734d724d m3_state sound/oss/maestro3.c STL_PANELMAGIC 0x7ef621a1 stlpanel include/linux/stallion.h VMALLOC_MAGIC 0x87654320 snd_alloc_track sound/core/memory.c @@ -137,11 +150,15 @@ PWC_MAGIC 0x89DC10AB pwc_device drivers/usb/media/pwc.h NBD_REPLY_MAGIC 0x96744668 nbd_reply include/linux/nbd.h STL_BOARDMAGIC 0xa2267f52 stlbrd include/linux/stallion.h +ENI155_MAGIC 0xa54b872d midway_eprom drivers/atm/eni.h SCI_MAGIC 0xbabeface gs_port drivers/char/sh-sci.h CODA_MAGIC 0xC0DAC0DA coda_file_info include/linux/coda_fs_i.h +DPMEM_MAGIC 0xc0ffee11 gdt_pci_sram drivers/scsi/gdth.h STLI_PORTMAGIC 0xe671c7a1 stliport include/linux/istallion.h YAM_MAGIC 0xF10A7654 yam_port drivers/net/hamradio/yam.c CCB_MAGIC 0xf2691ad2 ccb drivers/scsi/ncr53c8xx.c +QUEUE_MAGIC_FREE 0xf7e1c9a3 queue_entry drivers/scsi/arm/queue.c +QUEUE_MAGIC_USED 0xf7e1cc33 queue_entry drivers/scsi/arm/queue.c HTB_CMAGIC 0xFEFAFEF1 htb_class net/sched/sch_htb.c NMI_MAGIC 0x48414d4d455201 nmi_s include/asm-mips64/sn/nmi.h diff -Nru a/Documentation/networking/ifenslave.c b/Documentation/networking/ifenslave.c --- a/Documentation/networking/ifenslave.c Sun Jul 27 10:13:42 2003 +++ b/Documentation/networking/ifenslave.c Sun Jul 27 10:13:42 2003 @@ -27,7 +27,7 @@ * - 2001/02/16 Chad N. Tindel : * - Master is now brought down before setting the MAC address. In * the 2.4 kernel you can't change the MAC address while the device is - * up because you get EBUSY. + * up because you get EBUSY. * * - 2001/09/13 Takao Indoh * - Added the ability to change the active interface on a mode 1 bond @@ -44,17 +44,60 @@ * * - 2002/10/31 Tony Cureington : * - If the master does not have a hardware address when the first slave - * is enslaved, the master is assigned the hardware address of that - * slave - there is a comment in bonding.c stating "ifenslave takes - * care of this now." This corrects the problem of slaves having - * different hardware addresses in active-backup mode when + * is enslaved, the master is assigned the hardware address of that + * slave - there is a comment in bonding.c stating "ifenslave takes + * care of this now." This corrects the problem of slaves having + * different hardware addresses in active-backup mode when * multiple interfaces are specified on a single ifenslave command * (ifenslave bond0 eth0 eth1). * + * - 2003/03/18 - Tsippy Mendelson and + * Shmulik Hen + * - Moved setting the slave's mac address and openning it, from + * the application to the driver. This enables support of modes + * that need to use the unique mac address of each slave. + * The driver also takes care of closing the slave and restoring its + * original mac address upon release. + * In addition, block possibility of enslaving before the master is up. + * This prevents putting the system in an undefined state. + * + * - 2003/05/01 - Amir Noam + * - Added ABI version control to restore compatibility between + * new/old ifenslave and new/old bonding. + * - Prevent adding an adapter that is already a slave. + * Fixes the problem of stalling the transmission and leaving + * the slave in a down state. + * + * - 2003/05/01 - Shmulik Hen + * - Prevent enslaving if the bond device is down. + * Fixes the problem of leaving the system in unstable state and + * halting when trying to remove the module. + * - Close socket on all abnormal exists. + * - Add versioning scheme that follows that of the bonding driver. + * current version is 1.0.0 as a base line. + * + * - 2003/05/22 - Jay Vosburgh + * - ifenslave -c was broken; it's now fixed + * - Fixed problem with routes vanishing from master during enslave + * processing. + * + * - 2003/05/27 - Amir Noam + * - Fix backward compatibility issues: + * For drivers not using ABI versions, slave was set down while + * it should be left up before enslaving. + * Also, master was not set down and the default set_mac_address() + * would fail and generate an error message in the system log. + * - For opt_c: slave should not be set to the master's setting + * while it is running. It was already set during enslave. To + * simplify things, it is now handeled separately. */ +#define APP_VERSION "1.0.12" +#define APP_RELDATE "June 30, 2003" +#define APP_NAME "ifenslave" + static char *version = -"ifenslave.c:v0.07 9/9/97 Donald Becker (becker@cesdis.gsfc.nasa.gov).\n" +APP_NAME ".c:v" APP_VERSION " (" APP_RELDATE ") " "\nDonald Becker (becker@cesdis.gsfc.nasa.gov).\n" "detach support added on 2000/10/02 by Willy Tarreau (willy at meta-x.org).\n" "2.4 kernel support added on 2001/02/16 by Chad N. Tindel (ctindel at ieee dot org.\n"; @@ -103,6 +146,12 @@ #include #include +typedef unsigned long long u64; /* hack, so we may include kernel's ethtool.h */ +typedef __uint32_t u32; /* ditto */ +typedef __uint16_t u16; /* ditto */ +typedef __uint8_t u8; /* ditto */ +#include + struct option longopts[] = { /* { name has_arg *flag val } */ {"all-interfaces", 0, 0, 'a'}, /* Show all interfaces. */ @@ -130,18 +179,19 @@ int skfd = -1; /* AF_INET socket for ioctl() calls. */ static void if_print(char *ifname); +static int get_abi_ver(char *master_ifname); int main(int argc, char **argv) { struct ifreq ifr2, if_hwaddr, if_ipaddr, if_metric, if_mtu, if_dstaddr; struct ifreq if_netmask, if_brdaddr, if_flags; - int goterr = 0; + int rv, goterr = 0; int c, errflag = 0; sa_family_t master_family; char **spp, *master_ifname, *slave_ifname; int hwaddr_notset; - int master_up; + int abi_ver = 0; while ((c = getopt_long(argc, argv, "acdfrvV?h", longopts, 0)) != EOF) switch (c) { @@ -207,6 +257,7 @@ char **tempp = spp; if ((master_ifname == NULL)||(slave_ifname == NULL)||(*tempp++ != NULL)) { fprintf(stderr, usage_msg); + (void) close(skfd); return 2; } } @@ -218,6 +269,13 @@ exit(0); } + /* exchange abi version with bonding driver */ + abi_ver = get_abi_ver(master_ifname); + if (abi_ver < 0) { + (void) close(skfd); + exit(1); + } + /* Get the vitals from the master interface. */ { struct ifreq *ifra[7] = { &if_ipaddr, &if_mtu, &if_dstaddr, @@ -242,6 +300,13 @@ } } + /* check if master is up; if not then fail any operation */ + if (!(if_flags.ifr_flags & IFF_UP)) { + fprintf(stderr, "Illegal operation; the specified master interface '%s' is not up.\n", master_ifname); + (void) close(skfd); + exit (1); + } + hwaddr_notset = 1; /* assume master's address not set yet */ for (i = 0; hwaddr_notset && (i < 6); i++) { hwaddr_notset &= ((unsigned char *)if_hwaddr.ifr_hwaddr.sa_data)[i] == 0; @@ -254,7 +319,7 @@ " with ethernet-like network interfaces.\n" " Use the '-f' option to force the operation.\n", master_ifname); - + (void) close(skfd); exit (1); } master_family = if_hwaddr.ifr_hwaddr.sa_family; @@ -278,143 +343,153 @@ fprintf(stderr, "SIOCBONDRELEASE: cannot detach %s from %s. errno=%s.\n", slave_ifname, master_ifname, strerror(errno)); } - else { /* we'll set the interface down to avoid any conflicts due to - same IP/MAC */ + else if (abi_ver < 1) { + /* The driver is using an old ABI, so we'll set the interface + * down to avoid any conflicts due to same IP/MAC + */ strncpy(ifr2.ifr_name, slave_ifname, IFNAMSIZ); if (ioctl(skfd, SIOCGIFFLAGS, &ifr2) < 0) { int saved_errno = errno; fprintf(stderr, "SIOCGIFFLAGS on %s failed: %s\n", slave_ifname, - strerror(saved_errno)); + strerror(saved_errno)); } else { ifr2.ifr_flags &= ~(IFF_UP | IFF_RUNNING); if (ioctl(skfd, SIOCSIFFLAGS, &ifr2) < 0) { int saved_errno = errno; fprintf(stderr, "Shutting down interface %s failed: %s\n", - slave_ifname, strerror(saved_errno)); + slave_ifname, strerror(saved_errno)); } } } - } - else { /* attach a slave interface to the master */ - /* two possibilities : - - if hwaddr_notset, do nothing. The bond will assign the - hwaddr from its first slave. - - if !hwaddr_notset, assign the master's hwaddr to each slave - */ + } else if (opt_c) { /* change primary slave */ + strncpy(if_flags.ifr_name, master_ifname, IFNAMSIZ); + strncpy(if_flags.ifr_slave, slave_ifname, IFNAMSIZ); + if ((ioctl(skfd, SIOCBONDCHANGEACTIVE, &if_flags) < 0) && + (ioctl(skfd, BOND_CHANGE_ACTIVE_OLD, &if_flags) < 0)) { + fprintf(stderr, "SIOCBONDCHANGEACTIVE: %s.\n", strerror(errno)); + } + } else { /* attach a slave interface to the master */ strncpy(ifr2.ifr_name, slave_ifname, IFNAMSIZ); if (ioctl(skfd, SIOCGIFFLAGS, &ifr2) < 0) { int saved_errno = errno; fprintf(stderr, "SIOCGIFFLAGS on %s failed: %s\n", slave_ifname, strerror(saved_errno)); + (void) close(skfd); return 1; } + if ((ifr2.ifr_flags & IFF_SLAVE) && !opt_r) { + fprintf(stderr, "%s is already a slave\n", slave_ifname); + (void) close(skfd); + return 1; + } + + /* if hwaddr_notset, assign the slave hw address to the master */ if (hwaddr_notset) { - /* assign the slave hw address to the - * master since it currently does not + /* assign the slave hw address to the + * master since it currently does not * have one; otherwise, slaves may - * have different hw addresses in - * active-backup mode as seen when enslaving + * have different hw addresses in + * active-backup mode as seen when enslaving * using "ifenslave bond0 eth0 eth1" because * hwaddr_notset is set outside this loop. * TODO: put this and the "else" portion in * a function. */ - goterr = 0; - master_up = 0; - if (if_flags.ifr_flags & IFF_UP) { - if_flags.ifr_flags &= ~IFF_UP; - if (ioctl(skfd, SIOCSIFFLAGS, - &if_flags) < 0) { - goterr = 1; - fprintf(stderr, - "Shutting down " - "interface %s failed: " - "%s\n", - master_ifname, - strerror(errno)); - } else { - /* we took the master down, - * so we must bring it up - */ - master_up = 1; - } + /* get the slaves MAC address */ + strncpy(if_hwaddr.ifr_name, slave_ifname, + IFNAMSIZ); + rv = ioctl(skfd, SIOCGIFHWADDR, &if_hwaddr); + if (-1 == rv) { + fprintf(stderr, "Could not get MAC " + "address of %s: %s\n", + slave_ifname, + strerror(errno)); + strncpy(if_hwaddr.ifr_name, + master_ifname, IFNAMSIZ); + goterr = 1; } if (!goterr) { - /* get the slaves MAC address */ - strncpy(if_hwaddr.ifr_name, - slave_ifname, IFNAMSIZ); - if (ioctl(skfd, SIOCGIFHWADDR, - &if_hwaddr) < 0) { - fprintf(stderr, - "Could not get MAC " - "address of %s: %s\n", - slave_ifname, - strerror(errno)); - strncpy(if_hwaddr.ifr_name, - master_ifname, - IFNAMSIZ); - goterr=1; + if (abi_ver < 1) { + /* In ABI versions older than 1, the + * master's set_mac routine couldn't + * work if it was up, because it + * used the default ethernet set_mac + * function. + */ + /* bring master down */ + if_flags.ifr_flags &= ~IFF_UP; + if (ioctl(skfd, SIOCSIFFLAGS, + &if_flags) < 0) { + goterr = 1; + fprintf(stderr, + "Shutting down " + "interface %s failed: " + "%s\n", + master_ifname, + strerror(errno)); + } } - } - if (!goterr) { - strncpy(if_hwaddr.ifr_name, + strncpy(if_hwaddr.ifr_name, master_ifname, IFNAMSIZ); - if (ioctl(skfd, SIOCSIFHWADDR, + if (ioctl(skfd, SIOCSIFHWADDR, &if_hwaddr) < 0) { - fprintf(stderr, + fprintf(stderr, "Could not set MAC " "address of %s: %s\n", - master_ifname, + master_ifname, strerror(errno)); goterr=1; } else { hwaddr_notset = 0; } - } - if (master_up) { - if_flags.ifr_flags |= IFF_UP; - if (ioctl(skfd, SIOCSIFFLAGS, - &if_flags) < 0) { - fprintf(stderr, - "Bringing up interface " - "%s failed: %s\n", - master_ifname, - strerror(errno)); + if (abi_ver < 1) { + /* bring master back up */ + if_flags.ifr_flags |= IFF_UP; + if (ioctl(skfd, SIOCSIFFLAGS, + &if_flags) < 0) { + fprintf(stderr, + "Bringing up interface " + "%s failed: %s\n", + master_ifname, + strerror(errno)); + } } } + } else if (abi_ver < 1) { /* if (hwaddr_notset) */ - } else { - /* we'll assign master's hwaddr to this slave */ + /* The driver is using an old ABI, so we'll set the interface + * down and assign the master's hwaddr to it + */ if (ifr2.ifr_flags & IFF_UP) { ifr2.ifr_flags &= ~IFF_UP; if (ioctl(skfd, SIOCSIFFLAGS, &ifr2) < 0) { int saved_errno = errno; fprintf(stderr, "Shutting down interface %s failed: %s\n", - slave_ifname, strerror(saved_errno)); + slave_ifname, strerror(saved_errno)); } } - + strncpy(if_hwaddr.ifr_name, slave_ifname, IFNAMSIZ); if (ioctl(skfd, SIOCSIFHWADDR, &if_hwaddr) < 0) { int saved_errno = errno; fprintf(stderr, "SIOCSIFHWADDR on %s failed: %s\n", if_hwaddr.ifr_name, - strerror(saved_errno)); + strerror(saved_errno)); if (saved_errno == EBUSY) fprintf(stderr, " The slave device %s is busy: it must be" - " idle before running this command.\n", slave_ifname); + " idle before running this command.\n", slave_ifname); else if (saved_errno == EOPNOTSUPP) fprintf(stderr, " The slave device you specified does not support" - " setting the MAC address.\n Your kernel likely does not" - " support slave devices.\n"); + " setting the MAC address.\n Your kernel likely does not" + " support slave devices.\n"); else if (saved_errno == EINVAL) fprintf(stderr, " The slave device's address type does not match" - " the master's address type.\n"); + " the master's address type.\n"); } else { if (verbose) { unsigned char *hwaddr = if_hwaddr.ifr_hwaddr.sa_data; @@ -424,10 +499,11 @@ } } } - + if (*spp && !strcmp(*spp, "metric")) { if (*++spp == NULL) { fprintf(stderr, usage_msg); + (void) close(skfd); exit(2); } if_metric.ifr_metric = atoi(*spp); @@ -439,7 +515,7 @@ } spp++; } - + if (strncpy(if_ipaddr.ifr_name, slave_ifname, IFNAMSIZ) <= 0 || ioctl(skfd, SIOCSIFADDR, &if_ipaddr) < 0) { fprintf(stderr, @@ -452,16 +528,16 @@ slave_ifname, ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]); } } - + if (strncpy(if_mtu.ifr_name, slave_ifname, IFNAMSIZ) <= 0 - || ioctl(skfd, SIOCSIFMTU, &if_mtu) < 0) { + || ioctl(skfd, SIOCSIFMTU, &if_mtu) < 0) { fprintf(stderr, "Something broke setting the slave MTU: %s.\n", strerror(errno)); } else { if (verbose) printf("Set the slave's (%s) MTU to %d.\n", slave_ifname, if_mtu.ifr_mtu); } - + if (strncpy(if_dstaddr.ifr_name, slave_ifname, IFNAMSIZ) <= 0 || ioctl(skfd, SIOCSIFDSTADDR, &if_dstaddr) < 0) { fprintf(stderr, "Error setting the slave (%s) with SIOCSIFDSTADDR: %s.\n", @@ -473,7 +549,7 @@ slave_ifname, ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]); } } - + if (strncpy(if_brdaddr.ifr_name, slave_ifname, IFNAMSIZ) <= 0 || ioctl(skfd, SIOCSIFBRDADDR, &if_brdaddr) < 0) { fprintf(stderr, @@ -486,7 +562,7 @@ slave_ifname, ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]); } } - + if (strncpy(if_netmask.ifr_name, slave_ifname, IFNAMSIZ) <= 0 || ioctl(skfd, SIOCSIFNETMASK, &if_netmask) < 0) { fprintf(stderr, @@ -499,34 +575,45 @@ slave_ifname, ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]); } } - - ifr2.ifr_flags |= IFF_UP; /* the interface will need to be up to be bonded */ - if ((ifr2.ifr_flags &= ~(IFF_SLAVE | IFF_MASTER)) == 0 - || strncpy(ifr2.ifr_name, slave_ifname, IFNAMSIZ) <= 0 - || ioctl(skfd, SIOCSIFFLAGS, &ifr2) < 0) { - fprintf(stderr, - "Something broke setting the slave (%s) flags: %s.\n", - slave_ifname, strerror(errno)); + + if (abi_ver < 1) { + + /* The driver is using an old ABI, so we'll set the interface + * up before enslaving it + */ + ifr2.ifr_flags |= IFF_UP; + if ((ifr2.ifr_flags &= ~(IFF_SLAVE | IFF_MASTER)) == 0 + || strncpy(ifr2.ifr_name, slave_ifname, IFNAMSIZ) <= 0 + || ioctl(skfd, SIOCSIFFLAGS, &ifr2) < 0) { + fprintf(stderr, + "Something broke setting the slave (%s) flags: %s.\n", + slave_ifname, strerror(errno)); + } else { + if (verbose) + printf("Set the slave's (%s) flags %4.4x.\n", + slave_ifname, if_flags.ifr_flags); + } } else { - if (verbose) - printf("Set the slave's (%s) flags %4.4x.\n", slave_ifname, if_flags.ifr_flags); + /* the bonding module takes care of setting the slave's mac address + * and opening its interface + */ + if (ifr2.ifr_flags & IFF_UP) { /* the interface will need to be down */ + ifr2.ifr_flags &= ~IFF_UP; + if (ioctl(skfd, SIOCSIFFLAGS, &ifr2) < 0) { + int saved_errno = errno; + fprintf(stderr, "Shutting down interface %s failed: %s\n", + slave_ifname, strerror(saved_errno)); + } + } } - + /* Do the real thing */ - if ( ! opt_r) { + if (!opt_r) { strncpy(if_flags.ifr_name, master_ifname, IFNAMSIZ); strncpy(if_flags.ifr_slave, slave_ifname, IFNAMSIZ); - if (!opt_c) { - if ((ioctl(skfd, SIOCBONDENSLAVE, &if_flags) < 0) && - (ioctl(skfd, BOND_ENSLAVE_OLD, &if_flags) < 0)) { - fprintf(stderr, "SIOCBONDENSLAVE: %s.\n", strerror(errno)); - } - } - else { - if ((ioctl(skfd, SIOCBONDCHANGEACTIVE, &if_flags) < 0) && - (ioctl(skfd, BOND_CHANGE_ACTIVE_OLD, &if_flags) < 0)) { - fprintf(stderr, "SIOCBONDCHANGEACTIVE: %s.\n", strerror(errno)); - } + if ((ioctl(skfd, SIOCBONDENSLAVE, &if_flags) < 0) && + (ioctl(skfd, BOND_ENSLAVE_OLD, &if_flags) < 0)) { + fprintf(stderr, "SIOCBONDENSLAVE: %s.\n", strerror(errno)); } } } @@ -540,7 +627,7 @@ static short mif_flags; -/* Get the interface configuration from the kernel. */ +/* Get the inteface configuration from the kernel. */ static int if_getconfig(char *ifname) { struct ifreq ifr; @@ -639,7 +726,38 @@ } } - +static int get_abi_ver(char *master_ifname) +{ + struct ifreq ifr; + struct ethtool_drvinfo info; + int abi_ver = 0; + + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ); + ifr.ifr_data = (caddr_t)&info; + + info.cmd = ETHTOOL_GDRVINFO; + strncpy(info.driver, "ifenslave", 32); + snprintf(info.fw_version, 32, "%d", BOND_ABI_VERSION); + if (ioctl(skfd, SIOCETHTOOL, &ifr) >= 0) { + char *endptr; + + abi_ver = strtoul(info.fw_version, &endptr, 0); + if (*endptr) { + fprintf(stderr, "Error: got invalid string as an ABI " + "version from the bonding module\n"); + return -1; + } + } + + if (verbose) { + printf("ABI ver is %d\n", abi_ver); + } + return abi_ver; +} + + + /* * Local variables: * version-control: t diff -Nru a/Documentation/nmi_watchdog.txt b/Documentation/nmi_watchdog.txt --- a/Documentation/nmi_watchdog.txt Sun Jul 27 10:13:42 2003 +++ b/Documentation/nmi_watchdog.txt Sun Jul 27 10:13:42 2003 @@ -8,9 +8,20 @@ which get executed even if the system is otherwise locked up hard). This can be used to debug hard kernel lockups. By executing periodic NMI interrupts, the kernel can monitor whether any CPU has locked up, -and print out debugging messages if so. You must enable the NMI -watchdog at boot time with the 'nmi_watchdog=n' boot parameter. Eg. -the relevant lilo.conf entry: +and print out debugging messages if so. + +In order to use the NMI watchdoc, you need to have APIC support in your +kernel. For SMP kernels, APIC support gets compiled in automatically. For +UP, enable either CONFIG_X86_UP_APIC (Processor type and features -> Local +APIC support on uniprocessors) or CONFIG_X86_UP_IOAPIC (Processor type and +features -> IO-APIC support on uniprocessors) in your kernel config. +CONFIG_X86_UP_APIC is for uniprocessor machines without an IO-APIC. +CONFIG_X86_UP_IOAPIC is for uniprocessor with an IO-APIC. [Note: certain +kernel debugging options, such as Kernel Stack Meter or Kernel Tracer, +may implicitly disable the NMI watchdog.] + +To actually enable the NMI watchdog, use the 'nmi_watchdog=N' boot +parameter. Eg. the relevant lilo.conf entry: append="nmi_watchdog=1" diff -Nru a/Documentation/pnp.txt b/Documentation/pnp.txt --- a/Documentation/pnp.txt Sun Jul 27 10:13:41 2003 +++ b/Documentation/pnp.txt Sun Jul 27 10:13:41 2003 @@ -22,7 +22,7 @@ In addition to the standard driverfs file the following are created in each device's directory: id - displays a list of support EISA IDs -possible - displays possible resource configurations +options - displays possible resource configurations resources - displays currently allocated resources and allows resource changes -activating a device @@ -60,7 +60,7 @@ - Notice the string "DISABLED". THis means the device is not active. 3.) check the device's possible configurations (optional) -# cat possible +# cat options Dependent: 01 - Priority acceptable port 0x3f0-0x3f0, align 0x7, size 0x6, 16-bit address decoding port 0x3f7-0x3f7, align 0x0, size 0x1, 16-bit address decoding diff -Nru a/Documentation/zorro.txt b/Documentation/zorro.txt --- a/Documentation/zorro.txt Sun Jul 27 10:13:50 2003 +++ b/Documentation/zorro.txt Sun Jul 27 10:13:50 2003 @@ -57,13 +57,11 @@ functions: request_mem_region() - check_mem_region() (deprecated) release_mem_region() Shortcuts to claim the whole device's address space are provided as well: zorro_request_device - zorro_check_device (deprecated) zorro_release_device diff -Nru a/MAINTAINERS b/MAINTAINERS --- a/MAINTAINERS Sun Jul 27 10:13:47 2003 +++ b/MAINTAINERS Sun Jul 27 10:13:47 2003 @@ -420,8 +420,8 @@ S: Supported COMX/MULTIGATE SYNC SERIAL DRIVERS -P: Gergely Madarasz -M: Gergely Madarasz +P: Pasztor Szilard +M: Pasztor Szilard S: Supported COSA/SRP SYNC SERIAL DRIVER @@ -973,7 +973,7 @@ S: Supported INTERMEZZO FILE SYSTEM -P: Chen Yang +P: Cluster File Systems M: intermezzo-devel@lists.sf.net W: http://www.inter-mezzo.org/ L: intermezzo-discuss@lists.sourceforge.net @@ -1620,8 +1620,8 @@ S: Maintained SCSI SUBSYSTEM -P: Jens Axboe -M: axboe@suse.de +P: James E.J. Bottomley +M: James.Bottomley@HansenPartnership.com L: linux-scsi@vger.kernel.org S: Maintained @@ -1632,8 +1632,8 @@ S: Maintained SCTP PROTOCOL -P: Jon Grimm -M: jgrimm2@us.ibm.com +P: Sridhar Samudrala +M: sri@us.ibm.com L: lksctp-developers@lists.sourceforge.net S: Supported diff -Nru a/Makefile b/Makefile --- a/Makefile Sun Jul 27 10:13:48 2003 +++ b/Makefile Sun Jul 27 10:13:48 2003 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 0 -EXTRAVERSION = -test1 +EXTRAVERSION = -test2 # *DOCUMENTATION* # To see a list of typical targets execute "make help" @@ -781,7 +781,8 @@ tar -cvz $(RCS_TAR_IGNORE) -f $(KERNELPATH).tar.gz $(KERNELPATH)/. ; \ rm $(KERNELPATH) ; \ cd $(TOPDIR) ; \ - $(CONFIG_SHELL) $(srctree)/scripts/mkversion > .version ; \ + $(CONFIG_SHELL) $(srctree)/scripts/mkversion > .tmp_version ; \ + mv -f .tmp_version .version; \ $(RPM) -ta $(TOPDIR)/../$(KERNELPATH).tar.gz ; \ rm $(TOPDIR)/../$(KERNELPATH).tar.gz diff -Nru a/arch/alpha/Makefile b/arch/alpha/Makefile --- a/arch/alpha/Makefile Sun Jul 27 10:13:47 2003 +++ b/arch/alpha/Makefile Sun Jul 27 10:13:47 2003 @@ -11,7 +11,6 @@ NM := $(NM) -B LDFLAGS_vmlinux := -static -N #-relax -LDFLAGS_BLOB := --format binary --oformat elf64-alpha cflags-y := -pipe -mno-fp-regs -ffixed-8 # Determine if we can use the BWX instructions with GAS. diff -Nru a/arch/alpha/kernel/irq.c b/arch/alpha/kernel/irq.c --- a/arch/alpha/kernel/irq.c Sun Jul 27 10:13:50 2003 +++ b/arch/alpha/kernel/irq.c Sun Jul 27 10:13:50 2003 @@ -601,7 +601,7 @@ if ((unsigned) irq > ACTUAL_NR_IRQS && illegal_count < MAX_ILLEGAL_IRQS ) { irq_err_count++; illegal_count++; - printk(KERN_CRIT "device_interrupt: illegal interrupt %d\n", + printk(KERN_CRIT "device_interrupt: invalid interrupt %d\n", irq); return; } diff -Nru a/arch/alpha/lib/strncpy.S b/arch/alpha/lib/strncpy.S --- a/arch/alpha/lib/strncpy.S Sun Jul 27 10:13:47 2003 +++ b/arch/alpha/lib/strncpy.S Sun Jul 27 10:13:47 2003 @@ -16,7 +16,7 @@ .text - .align 3 + .align 4 .globl strncpy .ent strncpy strncpy: @@ -24,13 +24,58 @@ .prologue 0 mov $16, $0 # set return value now - beq $18, 0f - mov $26, $23 # set return address - br __stxncpy # do the work of the copy + beq $18, $zerolen + unop + bsr $23, __stxncpy # do the work of the copy + + unop + bne $18, $multiword # do we have full words left? + subq $24, 1, $3 # nope + subq $27, 1, $4 + + or $3, $24, $3 # clear the bits between the last + or $4, $27, $4 # written byte and the last byte in COUNT + andnot $4, $3, $4 + zap $1, $4, $1 + + stq_u $1, 0($16) + ret + + .align 4 +$multiword: + subq $24, 1, $2 # clear the final bits in the prev word + or $2, $24, $2 + zapnot $1, $2, $1 + subq $18, 1, $18 + + stq_u $1, 0($16) + addq $16, 8, $16 + unop + beq $18, 1f -0: ret - nop nop + unop nop + blbc $18, 0f + + stq_u $31, 0($16) # zero one word + subq $18, 1, $18 + addq $16, 8, $16 + beq $18, 1f + +0: stq_u $31, 0($16) # zero two words + subq $18, 2, $18 + stq_u $31, 8($16) + addq $16, 16, $16 + bne $18, 0b + +1: ldq_u $1, 0($16) # clear the leading bits in the final word + subq $27, 1, $2 + or $2, $27, $2 + + zap $1, $2, $1 + stq_u $1, 0($16) +$zerolen: + ret - .end strncpy + .end strncpy diff -Nru a/arch/alpha/mm/init.c b/arch/alpha/mm/init.c --- a/arch/alpha/mm/init.c Sun Jul 27 10:13:51 2003 +++ b/arch/alpha/mm/init.c Sun Jul 27 10:13:51 2003 @@ -20,9 +20,6 @@ #include #include /* max_low_pfn */ #include -#ifdef CONFIG_BLK_DEV_INITRD -#include -#endif #include #include diff -Nru a/arch/arm/mach-clps711x/autcpu12.c b/arch/arm/mach-clps711x/autcpu12.c --- a/arch/arm/mach-clps711x/autcpu12.c Sun Jul 27 10:13:43 2003 +++ b/arch/arm/mach-clps711x/autcpu12.c Sun Jul 27 10:13:43 2003 @@ -21,7 +21,6 @@ #include #include #include -#include #include #include diff -Nru a/arch/arm26/kernel/setup.c b/arch/arm26/kernel/setup.c --- a/arch/arm26/kernel/setup.c Sun Jul 27 10:13:42 2003 +++ b/arch/arm26/kernel/setup.c Sun Jul 27 10:13:42 2003 @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include diff -Nru a/arch/arm26/mm/init.c b/arch/arm26/mm/init.c --- a/arch/arm26/mm/init.c Sun Jul 27 10:13:51 2003 +++ b/arch/arm26/mm/init.c Sun Jul 27 10:13:51 2003 @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include diff -Nru a/arch/h8300/Makefile b/arch/h8300/Makefile --- a/arch/h8300/Makefile Sun Jul 27 10:13:41 2003 +++ b/arch/h8300/Makefile Sun Jul 27 10:13:41 2003 @@ -34,7 +34,6 @@ CFLAGS += -DUTS_SYSNAME=\"uClinux\" -DTARGET=$(BOARD) AFLAGS += -DPLATFORM=$(PLATFORM) -DTARGET=$(BOARD) -DMODEL=$(MODEL) $(cflags-y) LDFLAGS += $(ldflags-y) -LDFLAGS_BLOB := --format binary --oformat elf32-h8300 CROSS_COMPILE = h8300-elf- #HEAD := arch/$(ARCH)/platform/$(platform-y)/$(board-y)/crt0_$(model-y).o diff -Nru a/arch/h8300/kernel/setup.c b/arch/h8300/kernel/setup.c --- a/arch/h8300/kernel/setup.c Sun Jul 27 10:13:41 2003 +++ b/arch/h8300/kernel/setup.c Sun Jul 27 10:13:41 2003 @@ -35,7 +35,6 @@ #include #ifdef CONFIG_BLK_DEV_INITRD -#include #include #endif diff -Nru a/arch/h8300/mm/init.c b/arch/h8300/mm/init.c --- a/arch/h8300/mm/init.c Sun Jul 27 10:13:46 2003 +++ b/arch/h8300/mm/init.c Sun Jul 27 10:13:46 2003 @@ -23,9 +23,6 @@ #include #include #include -#ifdef CONFIG_BLK_DEV_RAM -#include -#endif #include #include #include diff -Nru a/arch/i386/Makefile b/arch/i386/Makefile --- a/arch/i386/Makefile Sun Jul 27 10:13:43 2003 +++ b/arch/i386/Makefile Sun Jul 27 10:13:43 2003 @@ -18,7 +18,6 @@ LDFLAGS := -m elf_i386 OBJCOPYFLAGS := -O binary -R .note -R .comment -S LDFLAGS_vmlinux := -LDFLAGS_BLOB := --format binary --oformat elf32-i386 CFLAGS += -pipe diff -Nru a/arch/i386/kernel/cpu/mtrr/cyrix.c b/arch/i386/kernel/cpu/mtrr/cyrix.c --- a/arch/i386/kernel/cpu/mtrr/cyrix.c Sun Jul 27 10:13:46 2003 +++ b/arch/i386/kernel/cpu/mtrr/cyrix.c Sun Jul 27 10:13:46 2003 @@ -330,16 +330,16 @@ set_mtrr_done(&ctxt); /* flush cache and disable MAPEN */ if (ccrc[5]) - printk("mtrr: ARR usage was not enabled, enabled manually\n"); + printk(KERN_INFO "mtrr: ARR usage was not enabled, enabled manually\n"); if (ccrc[3]) - printk("mtrr: ARR3 cannot be changed\n"); + printk(KERN_INFO "mtrr: ARR3 cannot be changed\n"); /* if ( ccrc[1] & 0x80) printk ("mtrr: SMM memory access through ARR3 disabled\n"); if ( ccrc[1] & 0x04) printk ("mtrr: SMM memory access disabled\n"); if ( ccrc[1] & 0x02) printk ("mtrr: SMM mode disabled\n"); */ if (ccrc[6]) - printk("mtrr: ARR3 was write protected, unprotected\n"); + printk(KERN_INFO "mtrr: ARR3 was write protected, unprotected\n"); } static struct mtrr_ops cyrix_mtrr_ops = { diff -Nru a/arch/i386/kernel/cpu/mtrr/main.c b/arch/i386/kernel/cpu/mtrr/main.c --- a/arch/i386/kernel/cpu/mtrr/main.c Sun Jul 27 10:13:40 2003 +++ b/arch/i386/kernel/cpu/mtrr/main.c Sun Jul 27 10:13:40 2003 @@ -64,7 +64,7 @@ static void set_mtrr(unsigned int reg, unsigned long base, unsigned long size, mtrr_type type); -static unsigned int arr3_protected; +extern int arr3_protected; void set_mtrr_ops(struct mtrr_ops * ops) { @@ -75,23 +75,25 @@ /* Returns non-zero if we have the write-combining memory type */ static int have_wrcomb(void) { - struct pci_dev *dev = NULL; - - /* WTF is this? - * Someone, please shoot me. - */ - - /* ServerWorks LE chipsets have problems with write-combining - Don't allow it and leave room for other chipsets to be tagged */ - + struct pci_dev *dev; + if ((dev = pci_find_class(PCI_CLASS_BRIDGE_HOST << 8, NULL)) != NULL) { - if ((dev->vendor == PCI_VENDOR_ID_SERVERWORKS) && - (dev->device == PCI_DEVICE_ID_SERVERWORKS_LE)) { - printk(KERN_INFO - "mtrr: Serverworks LE detected. Write-combining disabled.\n"); + /* ServerWorks LE chipsets have problems with write-combining + Don't allow it and leave room for other chipsets to be tagged */ + if (dev->vendor == PCI_VENDOR_ID_SERVERWORKS && + dev->device == PCI_DEVICE_ID_SERVERWORKS_LE) { + printk(KERN_INFO "mtrr: Serverworks LE detected. Write-combining disabled.\n"); return 0; } - } + /* Intel 450NX errata # 23. Non ascending cachline evictions to + write combining memory may resulting in data corruption */ + if (dev->vendor == PCI_VENDOR_ID_INTEL && + dev->device == PCI_DEVICE_ID_INTEL_82451NX) + { + printk(KERN_INFO "mtrr: Intel 450NX MMC detected. Write-combining disabled.\n"); + return 0; + } + } return (mtrr_if->have_wrcomb ? mtrr_if->have_wrcomb() : 0); } @@ -121,7 +123,7 @@ max = num_var_ranges; if ((usage_table = kmalloc(max * sizeof *usage_table, GFP_KERNEL)) == NULL) { - printk("mtrr: could not allocate\n"); + printk(KERN_ERR "mtrr: could not allocate\n"); return; } for (i = 0; i < max; i++) @@ -310,7 +312,7 @@ return error; if (type >= MTRR_NUM_TYPES) { - printk("mtrr: type: %u illegal\n", type); + printk(KERN_WARNING "mtrr: type: %u invalid\n", type); return -EINVAL; } @@ -322,7 +324,7 @@ } if (base & size_or_mask || size & size_or_mask) { - printk("mtrr: base or size exceeds the MTRR width\n"); + printk(KERN_WARNING "mtrr: base or size exceeds the MTRR width\n"); return -EINVAL; } @@ -348,7 +350,7 @@ if (ltype != type) { if (type == MTRR_TYPE_UNCACHABLE) continue; - printk ("mtrr: type mismatch for %lx000,%lx000 old: %s new: %s\n", + printk (KERN_WARNING "mtrr: type mismatch for %lx000,%lx000 old: %s new: %s\n", base, size, attrib_to_str(ltype), attrib_to_str(type)); goto out; @@ -364,7 +366,7 @@ set_mtrr(i, base, size, type); usage_table[i] = 1; } else - printk("mtrr: no more MTRRs available\n"); + printk(KERN_INFO "mtrr: no more MTRRs available\n"); error = i; out: up(&main_lock); @@ -412,8 +414,8 @@ char increment) { if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1))) { - printk("mtrr: size and base must be multiples of 4 kiB\n"); - printk("mtrr: size: 0x%lx base: 0x%lx\n", size, base); + printk(KERN_WARNING "mtrr: size and base must be multiples of 4 kiB\n"); + printk(KERN_DEBUG "mtrr: size: 0x%lx base: 0x%lx\n", size, base); return -EINVAL; } return mtrr_add_page(base >> PAGE_SHIFT, size >> PAGE_SHIFT, type, @@ -458,28 +460,28 @@ } } if (reg < 0) { - printk("mtrr: no MTRR for %lx000,%lx000 found\n", base, + printk(KERN_DEBUG "mtrr: no MTRR for %lx000,%lx000 found\n", base, size); goto out; } } if (reg >= max) { - printk("mtrr: register: %d too big\n", reg); + printk(KERN_WARNING "mtrr: register: %d too big\n", reg); goto out; } if (is_cpu(CYRIX) && !use_intel()) { if ((reg == 3) && arr3_protected) { - printk("mtrr: ARR3 cannot be changed\n"); + printk(KERN_WARNING "mtrr: ARR3 cannot be changed\n"); goto out; } } mtrr_if->get(reg, &lbase, &lsize, <ype); if (lsize < 1) { - printk("mtrr: MTRR %d not used\n", reg); + printk(KERN_WARNING "mtrr: MTRR %d not used\n", reg); goto out; } if (usage_table[reg] < 1) { - printk("mtrr: reg: %d has count=0\n", reg); + printk(KERN_WARNING "mtrr: reg: %d has count=0\n", reg); goto out; } if (--usage_table[reg] < 1) @@ -508,8 +510,8 @@ mtrr_del(int reg, unsigned long base, unsigned long size) { if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1))) { - printk("mtrr: size and base must be multiples of 4 kiB\n"); - printk("mtrr: size: 0x%lx base: 0x%lx\n", size, base); + printk(KERN_INFO "mtrr: size and base must be multiples of 4 kiB\n"); + printk(KERN_DEBUG "mtrr: size: 0x%lx base: 0x%lx\n", size, base); return -EINVAL; } return mtrr_del_page(reg, base >> PAGE_SHIFT, size >> PAGE_SHIFT); @@ -677,7 +679,7 @@ break; } } - printk("mtrr: v%s\n",MTRR_VERSION); + printk(KERN_INFO "mtrr: v%s\n",MTRR_VERSION); if (mtrr_if) { set_num_var_ranges(); diff -Nru a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c --- a/arch/i386/kernel/io_apic.c Sun Jul 27 10:13:43 2003 +++ b/arch/i386/kernel/io_apic.c Sun Jul 27 10:13:43 2003 @@ -682,6 +682,21 @@ #else /* !SMP */ static inline void move_irq(int irq) { } + +void send_IPI_self(int vector) +{ + unsigned int cfg; + + /* + * Wait for idle. + */ + apic_wait_icr_idle(); + cfg = APIC_DM_FIXED | APIC_DEST_SELF | vector | APIC_DEST_LOGICAL; + /* + * Send the IPI. The write to APIC_ICR fires this off. + */ + apic_write_around(APIC_ICR, cfg); +} #endif /* defined(CONFIG_SMP) */ diff -Nru a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c --- a/arch/i386/kernel/setup.c Sun Jul 27 10:13:45 2003 +++ b/arch/i386/kernel/setup.c Sun Jul 27 10:13:45 2003 @@ -42,6 +42,7 @@ #include #include #include +#include #include "setup_arch_pre.h" #include "mach_resources.h" @@ -100,7 +101,7 @@ extern void dmi_scan_machine(void); extern void generic_apic_probe(char *); extern int root_mountflags; -extern char _text, _etext, _edata, _end; +extern char _end[]; unsigned long saved_videomode; @@ -520,7 +521,7 @@ acpi_disabled = 1; /* "acpismp=force" turns on ACPI again */ - else if (!memcmp(from, "acpismp=force", 14)) + if (c == ' ' && !memcmp(from, "acpismp=force", 13)) acpi_disabled = 0; /* @@ -676,7 +677,7 @@ * partially used pages are not usable - thus * we are rounding upwards: */ - start_pfn = PFN_UP(__pa(&_end)); + start_pfn = PFN_UP(__pa(_end)); find_max_pfn(); @@ -947,15 +948,15 @@ if (!MOUNT_ROOT_RDONLY) root_mountflags &= ~MS_RDONLY; - init_mm.start_code = (unsigned long) &_text; - init_mm.end_code = (unsigned long) &_etext; - init_mm.end_data = (unsigned long) &_edata; - init_mm.brk = (unsigned long) &_end; - - code_resource.start = virt_to_phys(&_text); - code_resource.end = virt_to_phys(&_etext)-1; - data_resource.start = virt_to_phys(&_etext); - data_resource.end = virt_to_phys(&_edata)-1; + init_mm.start_code = (unsigned long) _text; + init_mm.end_code = (unsigned long) _etext; + init_mm.end_data = (unsigned long) _edata; + init_mm.brk = (unsigned long) _end; + + code_resource.start = virt_to_phys(_text); + code_resource.end = virt_to_phys(_etext)-1; + data_resource.start = virt_to_phys(_etext); + data_resource.end = virt_to_phys(_edata)-1; parse_cmdline_early(cmdline_p); @@ -977,7 +978,7 @@ generic_apic_probe(*cmdline_p); #endif -#ifdef CONFIG_ACPI_BOOT +#ifdef CONFIG_ACPI /* * Parse the ACPI tables for possible boot-time SMP configuration. */ diff -Nru a/arch/i386/mm/init.c b/arch/i386/mm/init.c --- a/arch/i386/mm/init.c Sun Jul 27 10:13:49 2003 +++ b/arch/i386/mm/init.c Sun Jul 27 10:13:49 2003 @@ -20,9 +20,6 @@ #include #include #include -#ifdef CONFIG_BLK_DEV_INITRD -#include -#endif #include #include #include @@ -565,7 +562,7 @@ free_page(addr); totalram_pages++; } - printk (KERN_INFO "Freeing unused kernel memory: %dk freed\n", (&__init_end - &__init_begin) >> 10); + printk (KERN_INFO "Freeing unused kernel memory: %dk freed\n", (__init_end - __init_begin) >> 10); } #ifdef CONFIG_BLK_DEV_INITRD diff -Nru a/arch/i386/pci/legacy.c b/arch/i386/pci/legacy.c --- a/arch/i386/pci/legacy.c Sun Jul 27 10:13:50 2003 +++ b/arch/i386/pci/legacy.c Sun Jul 27 10:13:50 2003 @@ -24,7 +24,7 @@ for (devfn = 0; devfn < 256; devfn += 8) { if (!raw_pci_ops->read(0, n, devfn, PCI_VENDOR_ID, 2, &l) && l != 0x0000 && l != 0xffff) { - DBG("Found device at %02x:%02x [%04x]\n", n, dev->devfn, l); + DBG("Found device at %02x:%02x [%04x]\n", n, devfn, l); printk(KERN_INFO "PCI: Discovered peer bus %02x\n", n); pci_scan_bus(n, &pci_root_ops, NULL); break; diff -Nru a/arch/i386/pci/visws.c b/arch/i386/pci/visws.c --- a/arch/i386/pci/visws.c Sun Jul 27 10:13:49 2003 +++ b/arch/i386/pci/visws.c Sun Jul 27 10:13:49 2003 @@ -17,7 +17,7 @@ int broken_hp_bios_irq9; -extern struct pci_ops pci_direct_conf1; +extern struct pci_raw_ops pci_direct_conf1; static int pci_visws_enable_irq(struct pci_dev *dev) { return 0; } @@ -101,8 +101,9 @@ printk(KERN_INFO "PCI: Lithium bridge A bus: %u, " "bridge B (PIIX4) bus: %u\n", pci_bus1, pci_bus0); - pci_scan_bus(pci_bus0, &pci_direct_conf1, NULL); - pci_scan_bus(pci_bus1, &pci_direct_conf1, NULL); + raw_pci_ops = &pci_direct_conf1; + pci_scan_bus(pci_bus0, &pci_root_ops, NULL); + pci_scan_bus(pci_bus1, &pci_root_ops, NULL); pci_fixup_irqs(visws_swizzle, visws_map_irq); pcibios_resource_survey(); return 0; diff -Nru a/arch/ia64/Makefile b/arch/ia64/Makefile --- a/arch/ia64/Makefile Sun Jul 27 10:13:40 2003 +++ b/arch/ia64/Makefile Sun Jul 27 10:13:40 2003 @@ -66,8 +66,7 @@ drivers-$(CONFIG_PCI) += arch/ia64/pci/ drivers-$(CONFIG_IA64_HP_SIM) += arch/ia64/hp/sim/ drivers-$(CONFIG_IA64_HP_ZX1) += arch/ia64/hp/common/ arch/ia64/hp/zx1/ -drivers-$(CONFIG_IA64_GENERIC) += arch/ia64/hp/common/ arch/ia64/hp/zx1/ arch/ia64/hp/sim/ \ - arch/ia64/sn/ +drivers-$(CONFIG_IA64_GENERIC) += arch/ia64/hp/common/ arch/ia64/hp/zx1/ arch/ia64/hp/sim/ boot := arch/ia64/boot diff -Nru a/arch/ia64/hp/common/sba_iommu.c b/arch/ia64/hp/common/sba_iommu.c --- a/arch/ia64/hp/common/sba_iommu.c Sun Jul 27 10:13:41 2003 +++ b/arch/ia64/hp/common/sba_iommu.c Sun Jul 27 10:13:41 2003 @@ -48,9 +48,11 @@ ** This option allows cards capable of 64bit DMA to bypass the IOMMU. If ** not defined, all DMA will be 32bit and go through the TLB. ** There's potentially a conflict in the bio merge code with us -** advertising an iommu, but then bypassing it. Disabled for now. +** advertising an iommu, but then bypassing it. Since I/O MMU bypassing +** appears to give more performance than bio-level virtual merging, we'll +** do the former for now. */ -#undef ALLOW_IOV_BYPASS +#define ALLOW_IOV_BYPASS /* ** If a device prefetches beyond the end of a valid pdir entry, it will cause diff -Nru a/arch/ia64/hp/sim/simeth.c b/arch/ia64/hp/sim/simeth.c --- a/arch/ia64/hp/sim/simeth.c Sun Jul 27 10:13:47 2003 +++ b/arch/ia64/hp/sim/simeth.c Sun Jul 27 10:13:47 2003 @@ -223,7 +223,7 @@ dev->set_multicast_list = set_multicast_list; /* no yet used */ err = register_netdev(dev); - if (dev) { + if (err) { kfree(dev); return err; } diff -Nru a/arch/ia64/hp/sim/simscsi.c b/arch/ia64/hp/sim/simscsi.c --- a/arch/ia64/hp/sim/simscsi.c Sun Jul 27 10:13:44 2003 +++ b/arch/ia64/hp/sim/simscsi.c Sun Jul 27 10:13:44 2003 @@ -9,7 +9,7 @@ * 99/12/18 David Mosberger Added support for READ10/WRITE10 needed by linux v2.3.33 */ #include -#include +#include #include #include #include diff -Nru a/arch/ia64/ia32/ia32_ioctl.c b/arch/ia64/ia32/ia32_ioctl.c --- a/arch/ia64/ia32/ia32_ioctl.c Sun Jul 27 10:13:49 2003 +++ b/arch/ia64/ia32/ia32_ioctl.c Sun Jul 27 10:13:49 2003 @@ -52,7 +52,7 @@ #include #include #include -#include +#include #include #include #include diff -Nru a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c --- a/arch/ia64/kernel/acpi.c Sun Jul 27 10:13:45 2003 +++ b/arch/ia64/kernel/acpi.c Sun Jul 27 10:13:45 2003 @@ -720,7 +720,7 @@ { int vector = 0; - if (acpi_madt->flags.pcat_compat && (gsi < 16)) + if (has_8259 && (gsi < 16)) return isa_irq_to_vector(gsi); if (!iosapic_register_intr) diff -Nru a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S --- a/arch/ia64/kernel/entry.S Sun Jul 27 10:13:43 2003 +++ b/arch/ia64/kernel/entry.S Sun Jul 27 10:13:43 2003 @@ -61,7 +61,17 @@ mov out2=in2 // envp add out3=16,sp // regs br.call.sptk.many rp=sys_execve -.ret0: cmp4.ge p6,p7=r8,r0 +.ret0: +#ifdef CONFIG_IA32_SUPPORT + /* + * Check if we're returning to ia32 mode. If so, we need to restore ia32 registers + * from pt_regs. + */ + adds r16=PT(CR_IPSR)+16,sp + ;; + ld8 r16=[r16] +#endif + cmp4.ge p6,p7=r8,r0 mov ar.pfs=loc1 // restore ar.pfs sxt4 r8=r8 // return 64-bit result ;; @@ -89,6 +99,12 @@ ldf.fill f23=[sp]; ldf.fill f24=[sp]; mov f25=f0 ldf.fill f26=[sp]; ldf.fill f27=[sp]; mov f28=f0 ldf.fill f29=[sp]; ldf.fill f30=[sp]; mov f31=f0 +#ifdef CONFIG_IA32_SUPPORT + tbit.nz p6,p0=r16, IA64_PSR_IS_BIT + movl loc0=ia64_ret_from_ia32_execve + ;; +(p6) mov rp=loc0 +#endif br.ret.sptk.many rp END(ia64_execve) @@ -688,7 +704,7 @@ mov b7=r0 // clear b7 ;; (pUStk) st1 [r14]=r3 - movl r17=THIS_CPU(ia64_phys_stacked_size_p8) + addl r17=THIS_CPU(ia64_phys_stacked_size_p8),r0 ;; mov r16=ar.bsp // get existing backing store pointer srlz.i // ensure interruption collection is off @@ -701,6 +717,19 @@ br.cond.sptk.many rbs_switch END(ia64_leave_syscall) +#ifdef CONFIG_IA32_SUPPORT +GLOBAL_ENTRY(ia64_ret_from_ia32_execve) + PT_REGS_UNWIND_INFO(0) + adds r2=PT(R8)+16,sp // r2 = &pt_regs.r8 + adds r3=PT(R10)+16,sp // r3 = &pt_regs.r10 + ;; + .mem.offset 0,0 + st8.spill [r2]=r8 // store return value in slot for r8 and set unat bit + .mem.offset 8,0 + st8.spill [r3]=r0 // clear error indication in slot for r10 and set unat bit +END(ia64_ret_from_ia32_execve_syscall) + // fall through +#endif /* CONFIG_IA32_SUPPORT */ GLOBAL_ENTRY(ia64_leave_kernel) PT_REGS_UNWIND_INFO(0) /* @@ -841,7 +870,7 @@ shr.u r18=r19,16 // get byte size of existing "dirty" partition ;; mov r16=ar.bsp // get existing backing store pointer - movl r17=THIS_CPU(ia64_phys_stacked_size_p8) + addl r17=THIS_CPU(ia64_phys_stacked_size_p8),r0 ;; ld4 r17=[r17] // r17 = cpu_data->phys_stacked_size_p8 (pKStk) br.cond.dpnt skip_rbs_switch diff -Nru a/arch/ia64/kernel/fsys.S b/arch/ia64/kernel/fsys.S --- a/arch/ia64/kernel/fsys.S Sun Jul 27 10:13:39 2003 +++ b/arch/ia64/kernel/fsys.S Sun Jul 27 10:13:39 2003 @@ -165,7 +165,7 @@ .altrp b6 .body add r9=TI_FLAGS+IA64_TASK_SIZE,r16 - movl r3=THIS_CPU(cpu_info) + addl r3=THIS_CPU(cpu_info),r0 mov.m r31=ar.itc // put time stamp into r31 (ITC) == now (35 cyc) #ifdef CONFIG_SMP @@ -177,7 +177,7 @@ movl r19=xtime // xtime is a timespec struct ld8 r10=[r10] // r10 <- __per_cpu_offset[0] - movl r21=THIS_CPU(cpu_info) + addl r21=THIS_CPU(cpu_info),r0 ;; add r10=r21, r10 // r10 <- &cpu_data(time_keeper_id) tbit.nz p8,p0 = r2, IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT_BIT diff -Nru a/arch/ia64/kernel/head.S b/arch/ia64/kernel/head.S --- a/arch/ia64/kernel/head.S Sun Jul 27 10:13:48 2003 +++ b/arch/ia64/kernel/head.S Sun Jul 27 10:13:48 2003 @@ -863,7 +863,7 @@ .wait: // exponential backoff, kdb, lockmeter etc. go in here hint @pause - ld4.bias r30=[r31] + ld4 r30=[r31] // don't use ld4.bias; if it's contended, we won't write the word nop 0 ;; cmp4.eq p14,p0=r30,r0 @@ -880,7 +880,7 @@ .wait: // exponential backoff, kdb, lockmeter etc. go in here hint @pause - ld4.bias r30=[r31] + ld4 r30=[r31] // don't use ld4.bias; if it's contended, we won't write the word ;; cmp4.ne p14,p0=r30,r0 mov r30 = 1 diff -Nru a/arch/ia64/kernel/ia64_ksyms.c b/arch/ia64/kernel/ia64_ksyms.c --- a/arch/ia64/kernel/ia64_ksyms.c Sun Jul 27 10:13:45 2003 +++ b/arch/ia64/kernel/ia64_ksyms.c Sun Jul 27 10:13:45 2003 @@ -64,9 +64,10 @@ #endif #include -EXPORT_SYMBOL(cpu_info__per_cpu); +EXPORT_SYMBOL(per_cpu__cpu_info); #ifdef CONFIG_SMP EXPORT_SYMBOL(__per_cpu_offset); +EXPORT_SYMBOL(per_cpu__local_per_cpu_offset); #endif EXPORT_SYMBOL(kernel_thread); diff -Nru a/arch/ia64/kernel/init_task.c b/arch/ia64/kernel/init_task.c --- a/arch/ia64/kernel/init_task.c Sun Jul 27 10:13:52 2003 +++ b/arch/ia64/kernel/init_task.c Sun Jul 27 10:13:52 2003 @@ -2,7 +2,7 @@ * This is where we statically allocate and initialize the initial * task. * - * Copyright (C) 1999, 2002 Hewlett-Packard Co + * Copyright (C) 1999, 2002-2003 Hewlett-Packard Co * David Mosberger-Tang */ @@ -34,7 +34,7 @@ struct thread_info thread_info; } s; unsigned long stack[KERNEL_STACK_SIZE/sizeof (unsigned long)]; -} init_task_mem __attribute__((section(".data.init_task"))) = {{ +} init_task_mem asm ("init_task_mem") __attribute__((section(".data.init_task"))) = {{ .task = INIT_TASK(init_task_mem.s.task), .thread_info = INIT_THREAD_INFO(init_task_mem.s.task) }}; diff -Nru a/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c --- a/arch/ia64/kernel/iosapic.c Sun Jul 27 10:13:45 2003 +++ b/arch/ia64/kernel/iosapic.c Sun Jul 27 10:13:45 2003 @@ -717,6 +717,7 @@ register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY, IOSAPIC_POL_LOW, IOSAPIC_LEVEL); } + entry->irq = vector; snprintf(pci_id, sizeof(pci_id), "%02x:%02x:%02x[%c]", entry->id.segment, entry->id.bus, entry->id.device, 'A' + entry->pin); diff -Nru a/arch/ia64/kernel/module.c b/arch/ia64/kernel/module.c --- a/arch/ia64/kernel/module.c Sun Jul 27 10:13:44 2003 +++ b/arch/ia64/kernel/module.c Sun Jul 27 10:13:44 2003 @@ -164,7 +164,7 @@ apply_imm64 (struct module *mod, struct insn *insn, uint64_t val) { if (slot(insn) != 2) { - printk(KERN_ERR "%s: illegal slot number %d for IMM64\n", + printk(KERN_ERR "%s: invalid slot number %d for IMM64\n", mod->name, slot(insn)); return 0; } @@ -176,7 +176,7 @@ apply_imm60 (struct module *mod, struct insn *insn, uint64_t val) { if (slot(insn) != 2) { - printk(KERN_ERR "%s: illegal slot number %d for IMM60\n", + printk(KERN_ERR "%s: invalid slot number %d for IMM60\n", mod->name, slot(insn)); return 0; } diff -Nru a/arch/ia64/kernel/patch.c b/arch/ia64/kernel/patch.c --- a/arch/ia64/kernel/patch.c Sun Jul 27 10:13:48 2003 +++ b/arch/ia64/kernel/patch.c Sun Jul 27 10:13:48 2003 @@ -9,6 +9,7 @@ #include #include +#include #include #include @@ -176,16 +177,8 @@ void ia64_patch_gate (void) { - extern char __start_gate_mckinley_e9_patchlist; - extern char __end_gate_mckinley_e9_patchlist; - extern char __start_gate_vtop_patchlist; - extern char __end_gate_vtop_patchlist; - extern char __start_gate_fsyscall_patchlist; - extern char __end_gate_fsyscall_patchlist; - extern char __start_gate_brl_fsys_bubble_down_patchlist; - extern char __end_gate_brl_fsys_bubble_down_patchlist; -# define START(name) ((unsigned long) &__start_gate_##name##_patchlist) -# define END(name) ((unsigned long)&__end_gate_##name##_patchlist) +# define START(name) ((unsigned long) __start_gate_##name##_patchlist) +# define END(name) ((unsigned long)__end_gate_##name##_patchlist) patch_fsyscall_table(START(fsyscall), END(fsyscall)); patch_brl_fsys_bubble_down(START(brl_fsys_bubble_down), END(brl_fsys_bubble_down)); diff -Nru a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c --- a/arch/ia64/kernel/perfmon.c Sun Jul 27 10:13:51 2003 +++ b/arch/ia64/kernel/perfmon.c Sun Jul 27 10:13:51 2003 @@ -566,7 +566,7 @@ #define pfm_wait_task_inactive(t) wait_task_inactive(t) -#define pfm_get_cpu_var(v) __get_cpu_var(v) +#define pfm_get_cpu_var(v) __ia64_per_cpu_var(v) #define pfm_get_cpu_data(a,b) per_cpu(a, b) typedef irqreturn_t pfm_irq_handler_t; #define PFM_IRQ_HANDLER_RET(v) do { \ diff -Nru a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c --- a/arch/ia64/kernel/ptrace.c Sun Jul 27 10:13:52 2003 +++ b/arch/ia64/kernel/ptrace.c Sun Jul 27 10:13:52 2003 @@ -42,7 +42,7 @@ (IA64_PSR_UM | IA64_PSR_DB | IA64_PSR_IS | IA64_PSR_ID | IA64_PSR_DD | IA64_PSR_RI) #define IPSR_READ_MASK IPSR_WRITE_MASK -#define PTRACE_DEBUG 1 +#define PTRACE_DEBUG 0 #if PTRACE_DEBUG # define dprintk(format...) printk(format) diff -Nru a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c --- a/arch/ia64/kernel/setup.c Sun Jul 27 10:13:41 2003 +++ b/arch/ia64/kernel/setup.c Sun Jul 27 10:13:41 2003 @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -49,13 +50,12 @@ # error "struct cpuinfo_ia64 too big!" #endif -extern char _end; - #ifdef CONFIG_SMP unsigned long __per_cpu_offset[NR_CPUS]; #endif DEFINE_PER_CPU(struct cpuinfo_ia64, cpu_info); +DEFINE_PER_CPU(unsigned long, local_per_cpu_offset); DEFINE_PER_CPU(unsigned long, ia64_phys_stacked_size_p8); unsigned long ia64_cycles_per_usec; struct ia64_boot_param *ia64_boot_param; @@ -278,7 +278,6 @@ static void find_memory (void) { -# define KERNEL_END (&_end) unsigned long bootmap_size; int n = 0; @@ -299,7 +298,7 @@ n++; rsvd_region[n].start = (unsigned long) ia64_imva((void *)KERNEL_START); - rsvd_region[n].end = (unsigned long) ia64_imva(KERNEL_END); + rsvd_region[n].end = (unsigned long) ia64_imva(_end); n++; #ifdef CONFIG_BLK_DEV_INITRD @@ -362,13 +361,12 @@ void __init setup_arch (char **cmdline_p) { - extern unsigned long *__start___vtop_patchlist[], *__end____vtop_patchlist[]; extern unsigned long ia64_iobase; unsigned long phys_iobase; unw_init(); - ia64_patch_vtop((u64) __start___vtop_patchlist, (u64) __end____vtop_patchlist); + ia64_patch_vtop((u64) __start___vtop_patchlist, (u64) __end___vtop_patchlist); *cmdline_p = __va(ia64_boot_param->command_line); strlcpy(saved_command_line, *cmdline_p, sizeof(saved_command_line)); @@ -389,19 +387,6 @@ find_memory(); -#if 0 - /* XXX fix me */ - init_mm.start_code = (unsigned long) &_stext; - init_mm.end_code = (unsigned long) &_etext; - init_mm.end_data = (unsigned long) &_edata; - init_mm.brk = (unsigned long) &_end; - - code_resource.start = virt_to_bus(&_text); - code_resource.end = virt_to_bus(&_etext) - 1; - data_resource.start = virt_to_bus(&_etext); - data_resource.end = virt_to_bus(&_edata) - 1; -#endif - /* process SAL system table: */ ia64_sal_init(efi.sal_systab); @@ -686,7 +671,6 @@ void cpu_init (void) { - extern char __per_cpu_start[], __phys_per_cpu_start[]; extern void __init ia64_mmu_init (void *); unsigned long num_phys_stacked; pal_vm_info_2_u_t vmi; @@ -695,7 +679,6 @@ void *cpu_data; #ifdef CONFIG_SMP - extern char __per_cpu_end[]; int cpu; /* @@ -709,6 +692,8 @@ memcpy(cpu_data, __phys_per_cpu_start, __per_cpu_end - __per_cpu_start); __per_cpu_offset[cpu] = (char *) cpu_data - __per_cpu_start; cpu_data += PERCPU_PAGE_SIZE; + + per_cpu(local_per_cpu_offset, cpu) = __per_cpu_offset[cpu]; } } cpu_data = __per_cpu_start + __per_cpu_offset[smp_processor_id()]; @@ -716,19 +701,18 @@ cpu_data = __phys_per_cpu_start; #endif /* !CONFIG_SMP */ - cpu_info = cpu_data + ((char *) &__get_cpu_var(cpu_info) - __per_cpu_start); -#ifdef CONFIG_NUMA - cpu_info->node_data = get_node_data_ptr(); -#endif - get_max_cacheline_size(); /* * We can't pass "local_cpu_data" to identify_cpu() because we haven't called * ia64_mmu_init() yet. And we can't call ia64_mmu_init() first because it * depends on the data returned by identify_cpu(). We break the dependency by - * accessing cpu_data() the old way, through identity mapped space. + * accessing cpu_data() through the canonical per-CPU address. */ + cpu_info = cpu_data + ((char *) &__ia64_per_cpu_var(cpu_info) - __per_cpu_start); +#ifdef CONFIG_NUMA + cpu_info->node_data = get_node_data_ptr(); +#endif identify_cpu(cpu_info); #ifdef CONFIG_MCKINLEY @@ -810,9 +794,6 @@ void check_bugs (void) { - extern char __start___mckinley_e9_bundles[]; - extern char __end___mckinley_e9_bundles[]; - ia64_patch_mckinley_e9((unsigned long) __start___mckinley_e9_bundles, (unsigned long) __end___mckinley_e9_bundles); } diff -Nru a/arch/ia64/kernel/smp.c b/arch/ia64/kernel/smp.c --- a/arch/ia64/kernel/smp.c Sun Jul 27 10:13:52 2003 +++ b/arch/ia64/kernel/smp.c Sun Jul 27 10:13:52 2003 @@ -72,7 +72,7 @@ #define IPI_CPU_STOP 1 /* This needs to be cacheline aligned because it is written to by *other* CPUs. */ -static DEFINE_PER_CPU(__u64, ipi_operation) ____cacheline_aligned; +static DEFINE_PER_CPU(u64, ipi_operation) ____cacheline_aligned; static void stop_this_cpu (void) @@ -91,7 +91,7 @@ handle_IPI (int irq, void *dev_id, struct pt_regs *regs) { int this_cpu = get_cpu(); - unsigned long *pending_ipis = &__get_cpu_var(ipi_operation); + unsigned long *pending_ipis = &__ia64_per_cpu_var(ipi_operation); unsigned long ops; /* Count this now; we may make a call that never returns. */ diff -Nru a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c --- a/arch/ia64/kernel/time.c Sun Jul 27 10:13:42 2003 +++ b/arch/ia64/kernel/time.c Sun Jul 27 10:13:42 2003 @@ -23,6 +23,7 @@ #include #include #include +#include #include extern unsigned long wall_jiffies; @@ -41,7 +42,6 @@ do_profile (unsigned long ip) { extern unsigned long prof_cpu_mask; - extern char _stext; if (!prof_buffer) return; @@ -49,7 +49,7 @@ if (!((1UL << smp_processor_id()) & prof_cpu_mask)) return; - ip -= (unsigned long) &_stext; + ip -= (unsigned long) _stext; ip >>= prof_shift; /* * Don't ignore out-of-bounds IP values silently, put them into the last @@ -83,12 +83,11 @@ itc_get_offset (void) { unsigned long elapsed_cycles, lost = jiffies - wall_jiffies; - unsigned long now, last_tick; + unsigned long now = ia64_get_itc(), last_tick; last_tick = (cpu_data(TIME_KEEPER_ID)->itm_next - (lost + 1)*cpu_data(TIME_KEEPER_ID)->itm_delta); - now = ia64_get_itc(); if (unlikely((long) (now - last_tick) < 0)) { printk(KERN_ERR "CPU %d: now < last_tick (now=0x%lx,last_tick=0x%lx)!\n", smp_processor_id(), now, last_tick); diff -Nru a/arch/ia64/kernel/unwind.c b/arch/ia64/kernel/unwind.c --- a/arch/ia64/kernel/unwind.c Sun Jul 27 10:13:52 2003 +++ b/arch/ia64/kernel/unwind.c Sun Jul 27 10:13:52 2003 @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -2178,7 +2179,7 @@ void __init unw_init (void) { - extern int ia64_unw_start, ia64_unw_end, __gp; + extern char __gp[]; extern void unw_hash_index_t_is_too_narrow (void); long i, off; @@ -2211,8 +2212,8 @@ unw.lru_head = UNW_CACHE_SIZE - 1; unw.lru_tail = 0; - init_unwind_table(&unw.kernel_table, "kernel", KERNEL_START, (unsigned long) &__gp, - &ia64_unw_start, &ia64_unw_end); + init_unwind_table(&unw.kernel_table, "kernel", KERNEL_START, (unsigned long) __gp, + __start_unwind, __end_unwind); } /* diff -Nru a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c --- a/arch/ia64/mm/init.c Sun Jul 27 10:13:44 2003 +++ b/arch/ia64/mm/init.c Sun Jul 27 10:13:44 2003 @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -34,9 +35,6 @@ DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); -/* References to section boundaries: */ -extern char _stext, _etext, _edata, __init_begin, __init_end, _end; - extern void ia64_tlb_init (void); unsigned long MAX_DMA_ADDRESS = PAGE_OFFSET + 0x100000000UL; @@ -151,8 +149,8 @@ { unsigned long addr, eaddr; - addr = (unsigned long) ia64_imva(&__init_begin); - eaddr = (unsigned long) ia64_imva(&__init_end); + addr = (unsigned long) ia64_imva(__init_begin); + eaddr = (unsigned long) ia64_imva(__init_end); while (addr < eaddr) { ClearPageReserved(virt_to_page(addr)); set_page_count(virt_to_page(addr), 1); @@ -161,7 +159,7 @@ addr += PAGE_SIZE; } printk(KERN_INFO "Freeing unused kernel memory: %ldkB freed\n", - (&__init_end - &__init_begin) >> 10); + (__init_end - __init_begin) >> 10); } void @@ -308,7 +306,6 @@ setup_gate (void) { struct page *page; - extern char __start_gate_section[]; /* * Map the gate page twice: once read-only to export the ELF headers etc. and once @@ -671,7 +668,7 @@ kclist_add(&kcore_mem, __va(0), max_low_pfn * PAGE_SIZE); kclist_add(&kcore_vmem, (void *)VMALLOC_START, VMALLOC_END-VMALLOC_START); - kclist_add(&kcore_kernel, &_stext, &_end - &_stext); + kclist_add(&kcore_kernel, _stext, _end - _stext); for_each_pgdat(pgdat) totalram_pages += free_all_bootmem_node(pgdat); @@ -679,9 +676,9 @@ reserved_pages = 0; efi_memmap_walk(count_reserved_pages, &reserved_pages); - codesize = (unsigned long) &_etext - (unsigned long) &_stext; - datasize = (unsigned long) &_edata - (unsigned long) &_etext; - initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin; + codesize = (unsigned long) _etext - (unsigned long) _stext; + datasize = (unsigned long) _edata - (unsigned long) _etext; + initsize = (unsigned long) __init_end - (unsigned long) __init_begin; printk(KERN_INFO "Memory: %luk/%luk available (%luk code, %luk reserved, " "%luk data, %luk init)\n", (unsigned long) nr_free_pages() << (PAGE_SHIFT - 10), diff -Nru a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c --- a/arch/ia64/pci/pci.c Sun Jul 27 10:13:44 2003 +++ b/arch/ia64/pci/pci.c Sun Jul 27 10:13:44 2003 @@ -124,7 +124,7 @@ /* Called by ACPI when it finds a new root bus. */ -static struct pci_controller * +static struct pci_controller * __devinit alloc_pci_controller (int seg) { struct pci_controller *controller; @@ -138,7 +138,7 @@ return controller; } -static int +static int __devinit alloc_resource (char *name, struct resource *root, unsigned long start, unsigned long end, unsigned long flags) { struct resource *res; @@ -159,7 +159,7 @@ return 0; } -static u64 +static u64 __devinit add_io_space (struct acpi_resource_address64 *addr) { u64 offset; @@ -190,7 +190,7 @@ return IO_SPACE_BASE(i); } -static acpi_status +static acpi_status __devinit count_window (struct acpi_resource *resource, void *data) { unsigned int *windows = (unsigned int *) data; @@ -211,7 +211,7 @@ char *name; }; -static acpi_status +static acpi_status __devinit add_window (struct acpi_resource *res, void *data) { struct pci_root_info *info = (struct pci_root_info *) data; @@ -252,7 +252,7 @@ return AE_OK; } -struct pci_bus * +struct pci_bus * __devinit pci_acpi_scan_root (struct acpi_device *device, int domain, int bus) { struct pci_root_info info; diff -Nru a/arch/ia64/scripts/check-model.c b/arch/ia64/scripts/check-model.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ia64/scripts/check-model.c Sun Jul 27 10:13:53 2003 @@ -0,0 +1 @@ +int __attribute__ ((__model__ (__small__))) x; diff -Nru a/arch/ia64/scripts/toolchain-flags b/arch/ia64/scripts/toolchain-flags --- a/arch/ia64/scripts/toolchain-flags Sun Jul 27 10:13:52 2003 +++ b/arch/ia64/scripts/toolchain-flags Sun Jul 27 10:13:52 2003 @@ -2,6 +2,7 @@ # # Check whether linker can handle cross-segment @segrel(): # +CPPFLAGS="" CC=$1 OBJDUMP=$2 dir=$(dirname $0) @@ -11,10 +12,17 @@ res=$($OBJDUMP --full --section .rodata $out | fgrep 000 | cut -f3 -d' ') rm -f $out if [ $res != 00000a00 ]; then - echo " -DHAVE_BUGGY_SEGREL" + CPPFLAGS="$CPPFLAGS -DHAVE_BUGGY_SEGREL" cat >&2 <&1 | grep -q 'attribute directive ignored' +then + CPPFLAGS="$CPPFLAGS -DHAVE_MODEL_SMALL_ATTRIBUTE" +fi +rm -f $out +echo $CPPFLAGS diff -Nru a/arch/ia64/vmlinux.lds.S b/arch/ia64/vmlinux.lds.S --- a/arch/ia64/vmlinux.lds.S Sun Jul 27 10:13:50 2003 +++ b/arch/ia64/vmlinux.lds.S Sun Jul 27 10:13:50 2003 @@ -59,7 +59,7 @@ { __start___vtop_patchlist = .; *(.data.patch.vtop) - __end____vtop_patchlist = .; + __end___vtop_patchlist = .; } .data.patch.mckinley_e9 : AT(ADDR(.data.patch.mckinley_e9) - LOAD_OFFSET) @@ -89,9 +89,9 @@ { *(.IA_64.unwind_info*) } .IA_64.unwind : AT(ADDR(.IA_64.unwind) - LOAD_OFFSET) { - ia64_unw_start = .; + __start_unwind = .; *(.IA_64.unwind*) - ia64_unw_end = .; + __end_unwind = .; } RODATA diff -Nru a/arch/m68k/Kconfig b/arch/m68k/Kconfig --- a/arch/m68k/Kconfig Sun Jul 27 10:13:47 2003 +++ b/arch/m68k/Kconfig Sun Jul 27 10:13:47 2003 @@ -1126,37 +1126,8 @@ . The module will be called softdog. -config RTC - bool "Enhanced Real Time Clock Support" - depends on ATARI - ---help--- - If you say Y here and create a character special file /dev/rtc with - major number 10 and minor number 135 using mknod ("man mknod"), you - will get access to the real time clock (or hardware clock) built - into your computer. - - Every PC has such a clock built in. It can be used to generate - signals from as low as 1Hz up to 8192Hz, and can also be used - as a 24 hour alarm. It reports status information via the file - /proc/driver/rtc and its behaviour is set by various ioctls on - /dev/rtc. - - If you run Linux on a multiprocessor machine and said Y to - "Symmetric Multi Processing" above, you should say Y here to read - and set the RTC in an SMP compatible fashion. - - If you think you have a use for such a device (such as periodic data - sampling), then say Y here, and read - for details. - - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module is called rtc. If you want to compile it as a module, - say M here and read . - config GEN_RTC tristate "Generic /dev/rtc emulation" if !SUN3 - depends on !ATARI default y if SUN3 ---help--- If you say Y here and create a character special file /dev/rtc with diff -Nru a/arch/m68k/Makefile b/arch/m68k/Makefile --- a/arch/m68k/Makefile Sun Jul 27 10:13:51 2003 +++ b/arch/m68k/Makefile Sun Jul 27 10:13:51 2003 @@ -19,7 +19,6 @@ # override top level makefile AS += -m68020 LDFLAGS := -m m68kelf -LDFLAGS_BLOB := --format binary --oformat elf32-m68k ifneq ($(COMPILE_ARCH),$(ARCH)) # prefix for cross-compiling binaries CROSS_COMPILE = m68k-linux- diff -Nru a/arch/m68k/apollo/config.c b/arch/m68k/apollo/config.c --- a/arch/m68k/apollo/config.c Sun Jul 27 10:13:51 2003 +++ b/arch/m68k/apollo/config.c Sun Jul 27 10:13:51 2003 @@ -174,10 +174,6 @@ mach_hwclk = dn_dummy_hwclk; /* */ mach_set_clock_mmss = dn_dummy_set_clock_mmss; /* */ mach_process_int = dn_process_int; -#ifdef CONFIG_BLK_DEV_FD - mach_floppy_init = dn_dummy_floppy_init; - mach_floppy_setup = dn_dummy_floppy_setup; -#endif mach_reset = dn_dummy_reset; /* */ #ifdef CONFIG_DUMMY_CONSOLE conswitchp = &dummy_con; diff -Nru a/arch/m68k/apollo/dn_ints.c b/arch/m68k/apollo/dn_ints.c --- a/arch/m68k/apollo/dn_ints.c Sun Jul 27 10:13:48 2003 +++ b/arch/m68k/apollo/dn_ints.c Sun Jul 27 10:13:48 2003 @@ -46,7 +46,7 @@ int dn_request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id) { if((irq<0) || (irq>15)) { - printk("Trying to request illegal IRQ\n"); + printk("Trying to request invalid IRQ\n"); return -ENXIO; } @@ -72,7 +72,7 @@ void dn_free_irq(unsigned int irq, void *dev_id) { if((irq<0) || (irq>15)) { - printk("Trying to free illegal IRQ\n"); + printk("Trying to free invalid IRQ\n"); return ; } diff -Nru a/arch/m68k/atari/atari_ksyms.c b/arch/m68k/atari/atari_ksyms.c --- a/arch/m68k/atari/atari_ksyms.c Sun Jul 27 10:13:45 2003 +++ b/arch/m68k/atari/atari_ksyms.c Sun Jul 27 10:13:45 2003 @@ -28,16 +28,8 @@ EXPORT_SYMBOL(atari_stram_alloc); EXPORT_SYMBOL(atari_stram_free); -EXPORT_SYMBOL(atari_mouse_buttons); -EXPORT_SYMBOL(atari_mouse_interrupt_hook); -EXPORT_SYMBOL(atari_MIDI_interrupt_hook); EXPORT_SYMBOL(atari_MFP_init_done); EXPORT_SYMBOL(atari_SCC_init_done); EXPORT_SYMBOL(atari_SCC_reset_done); -EXPORT_SYMBOL(ikbd_write); -EXPORT_SYMBOL(ikbd_mouse_y0_top); -EXPORT_SYMBOL(ikbd_mouse_thresh); -EXPORT_SYMBOL(ikbd_mouse_rel_pos); -EXPORT_SYMBOL(ikbd_mouse_disable); EXPORT_SYMBOL(atari_microwire_cmd); diff -Nru a/arch/m68k/atari/stram.c b/arch/m68k/atari/stram.c --- a/arch/m68k/atari/stram.c Sun Jul 27 10:13:49 2003 +++ b/arch/m68k/atari/stram.c Sun Jul 27 10:13:49 2003 @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -37,7 +38,6 @@ #define MAJOR_NR Z2RAM_MAJOR #define do_z2_request do_stram_request #define DEVICE_NR(device) (minor(device)) -#include #endif #undef DEBUG diff -Nru a/arch/m68k/atari/time.c b/arch/m68k/atari/time.c --- a/arch/m68k/atari/time.c Sun Jul 27 10:13:50 2003 +++ b/arch/m68k/atari/time.c Sun Jul 27 10:13:50 2003 @@ -17,7 +17,7 @@ #include #include -#include +#include void __init atari_sched_init(irqreturn_t (*timer_routine)(int, void *, struct pt_regs *)) diff -Nru a/arch/m68k/defconfig b/arch/m68k/defconfig --- a/arch/m68k/defconfig Sun Jul 27 10:13:40 2003 +++ b/arch/m68k/defconfig Sun Jul 27 10:13:40 2003 @@ -177,7 +177,7 @@ # CONFIG_PPP is not set # CONFIG_EQUALIZER is not set # CONFIG_ARIADNE is not set -# CONFIG_ARIADNE2 is not set +# CONFIG_ZORRO8390 is not set # CONFIG_A2065 is not set # CONFIG_HYDRA is not set diff -Nru a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S --- a/arch/m68k/kernel/entry.S Sun Jul 27 10:13:40 2003 +++ b/arch/m68k/kernel/entry.S Sun Jul 27 10:13:40 2003 @@ -68,11 +68,13 @@ addql #4,%sp jra ret_from_exception - | schedule_tail is only used with CONFIG_SMP + | After a fork we jump here directly from resume, + | so that %d1 contains the previous task + | schedule_tail now used regardless of CONFIG_SMP ENTRY(ret_from_fork) -#ifdef CONFIG_SMP + movel %d1,%sp@- jsr schedule_tail -#endif + addql #4,%sp jra ret_from_exception badsys: diff -Nru a/arch/m68k/kernel/m68k_defs.c b/arch/m68k/kernel/m68k_defs.c --- a/arch/m68k/kernel/m68k_defs.c Sun Jul 27 10:13:40 2003 +++ b/arch/m68k/kernel/m68k_defs.c Sun Jul 27 10:13:40 2003 @@ -71,7 +71,6 @@ /* offsets into the irq_cpustat_t struct */ DEFINE(CPUSTAT_SOFTIRQ_PENDING, offsetof(irq_cpustat_t, __softirq_pending)); - DEFINE(CPUSTAT_SYSCALL_COUNT, offsetof(irq_cpustat_t, __syscall_count)); /* offsets into the bi_record struct */ DEFINE(BIR_TAG, offsetof(struct bi_record, tag)); diff -Nru a/arch/m68k/kernel/module.c b/arch/m68k/kernel/module.c --- a/arch/m68k/kernel/module.c Sun Jul 27 10:13:45 2003 +++ b/arch/m68k/kernel/module.c Sun Jul 27 10:13:45 2003 @@ -93,3 +93,7 @@ { return 0; } + +void module_arch_cleanup(struct module *mod) +{ +} diff -Nru a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c --- a/arch/m68k/kernel/process.c Sun Jul 27 10:13:52 2003 +++ b/arch/m68k/kernel/process.c Sun Jul 27 10:13:52 2003 @@ -202,24 +202,19 @@ asmlinkage int m68k_fork(struct pt_regs *regs) { - struct task_struct *p; - p = do_fork(SIGCHLD, rdusp(), regs, 0, NULL, NULL); - return IS_ERR(p) ? PTR_ERR(p) : p->pid; + return do_fork(SIGCHLD, rdusp(), regs, 0, NULL, NULL); } asmlinkage int m68k_vfork(struct pt_regs *regs) { - struct task_struct *p; - p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0, NULL, - NULL); - return IS_ERR(p) ? PTR_ERR(p) : p->pid; + return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0, + NULL, NULL); } asmlinkage int m68k_clone(struct pt_regs *regs) { unsigned long clone_flags; unsigned long newsp; - struct task_struct *p; int *parent_tidptr, *child_tidptr; /* syscall2 puts clone_flags in d1 and usp in d2 */ @@ -229,9 +224,8 @@ child_tidptr = (int *)regs->d4; if (!newsp) newsp = rdusp(); - p = do_fork(clone_flags & ~CLONE_IDLETASK, newsp, regs, 0, - parent_tidptr, child_tidptr); - return IS_ERR(p) ? PTR_ERR(p) : p->pid; + return do_fork(clone_flags & ~CLONE_IDLETASK, newsp, regs, 0, + parent_tidptr, child_tidptr); } int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, diff -Nru a/arch/m68k/kernel/traps.c b/arch/m68k/kernel/traps.c --- a/arch/m68k/kernel/traps.c Sun Jul 27 10:13:52 2003 +++ b/arch/m68k/kernel/traps.c Sun Jul 27 10:13:52 2003 @@ -852,11 +852,6 @@ printk("\n"); } -void show_trace_task(struct task_struct *tsk) -{ - show_trace((unsigned long *)tsk->thread.esp0); -} - void show_registers(struct pt_regs *regs) { struct frame *fp = (struct frame *)regs; @@ -915,7 +910,7 @@ default: printk("\n"); } - show_stack((unsigned long *)addr); + show_stack(NULL, (unsigned long *)addr); printk("Code: "); for (i = 0; i < 10; i++) @@ -923,13 +918,17 @@ printk ("\n"); } -extern void show_stack(unsigned long *stack) +extern void show_stack(struct task_struct *task, unsigned long *stack) { unsigned long *endstack; int i; - if (!stack) - stack = (unsigned long *)&stack; + if (!stack) { + if (task) + stack = (unsigned long *)task->thread.esp0; + else + stack = (unsigned long *)&stack; + } endstack = (unsigned long *)(((unsigned long)stack + THREAD_SIZE - 1) & -THREAD_SIZE); printk("Stack from %08lx:", (unsigned long)stack); @@ -1124,7 +1123,7 @@ printk("Process %s (pid: %d, stackpage=%08lx)\n", current->comm, current->pid, PAGE_SIZE+(unsigned long)current); - show_stack((unsigned long *)fp); + show_stack(NULL, (unsigned long *)fp); do_exit(SIGSEGV); } diff -Nru a/arch/m68k/math-emu/fp_emu.h b/arch/m68k/math-emu/fp_emu.h --- a/arch/m68k/math-emu/fp_emu.h Sun Jul 27 10:13:40 2003 +++ b/arch/m68k/math-emu/fp_emu.h Sun Jul 27 10:13:40 2003 @@ -115,6 +115,15 @@ __res; \ }) +#define fp_conv_long2ext(dest, src) ({ \ + register struct fp_ext *__dest asm ("a0") = dest; \ + register int __src asm ("d0") = src; \ + \ + asm volatile ("jsr fp_conv_ext2long" \ + : : "d" (__src), "a" (__dest) \ + : "a1", "d1", "d2", "memory"); \ +}) + #else /* __ASSEMBLY__ */ /* diff -Nru a/arch/m68k/math-emu/fp_log.c b/arch/m68k/math-emu/fp_log.c --- a/arch/m68k/math-emu/fp_log.c Sun Jul 27 10:13:39 2003 +++ b/arch/m68k/math-emu/fp_log.c Sun Jul 27 10:13:39 2003 @@ -17,10 +17,22 @@ #include "fp_emu.h" +static const struct fp_ext fp_one = +{ + 0, 0, 0x3fff, { 0 } +}; + +extern struct fp_ext *fp_fadd(struct fp_ext *dest, const struct fp_ext *src); +extern struct fp_ext *fp_fdiv(struct fp_ext *dest, const struct fp_ext *src); +extern struct fp_ext *fp_fmul(struct fp_ext *dest, const struct fp_ext *src); + struct fp_ext * fp_fsqrt(struct fp_ext *dest, struct fp_ext *src) { - uprint("fsqrt\n"); + struct fp_ext tmp, src2; + int i, exp; + + dprint(PINSTR, "fsqrt\n"); fp_monadic_check(dest, src); @@ -34,6 +46,56 @@ if (IS_INF(dest)) return dest; + /* + * sqrt(m) * 2^(p) , if e = 2*p + * sqrt(m*2^e) = + * sqrt(2*m) * 2^(p) , if e = 2*p + 1 + * + * So we use the last bit of the exponent to decide wether to + * use the m or 2*m. + * + * Since only the fractional part of the mantissa is stored and + * the integer part is assumed to be one, we place a 1 or 2 into + * the fixed point representation. + */ + exp = dest->exp; + dest->exp = 0x3FFF; + if (!(exp & 1)) /* lowest bit of exponent is set */ + dest->exp++; + fp_copy_ext(&src2, dest); + + /* + * The taylor row arround a for sqrt(x) is: + * sqrt(x) = sqrt(a) + 1/(2*sqrt(a))*(x-a) + R + * With a=1 this gives: + * sqrt(x) = 1 + 1/2*(x-1) + * = 1/2*(1+x) + */ + fp_fadd(dest, &fp_one); + dest->exp--; /* * 1/2 */ + + /* + * We now apply the newton rule to the function + * f(x) := x^2 - r + * which has a null point on x = sqrt(r). + * + * It gives: + * x' := x - f(x)/f'(x) + * = x - (x^2 -r)/(2*x) + * = x - (x - r/x)/2 + * = (2*x - x + r/x)/2 + * = (x + r/x)/2 + */ + for (i = 0; i < 9; i++) { + fp_copy_ext(&tmp, &src2); + + fp_fdiv(&tmp, dest); + fp_fadd(dest, &tmp); + dest->exp--; + } + + dest->exp += (exp - 0x3FFF) / 2; + return dest; } @@ -123,19 +185,38 @@ struct fp_ext * fp_fgetexp(struct fp_ext *dest, struct fp_ext *src) { - uprint("fgetexp\n"); + dprint(PINSTR, "fgetexp\n"); fp_monadic_check(dest, src); + if (IS_INF(dest)) { + fp_set_nan(dest); + return dest; + } + if (IS_ZERO(dest)) + return dest; + + fp_conv_long2ext(dest, (int)dest->exp - 0x3FFF); + + fp_normalize_ext(dest); + return dest; } struct fp_ext * fp_fgetman(struct fp_ext *dest, struct fp_ext *src) { - uprint("fgetman\n"); + dprint(PINSTR, "fgetman\n"); fp_monadic_check(dest, src); + + if (IS_ZERO(dest)) + return dest; + + if (IS_INF(dest)) + return dest; + + dest->exp = 0x3FFF; return dest; } diff -Nru a/arch/m68k/mm/init.c b/arch/m68k/mm/init.c --- a/arch/m68k/mm/init.c Sun Jul 27 10:13:50 2003 +++ b/arch/m68k/mm/init.c Sun Jul 27 10:13:50 2003 @@ -17,9 +17,6 @@ #include #include #include -#ifdef CONFIG_BLK_DEV_RAM -#include -#endif #include #include diff -Nru a/arch/m68k/mm/memory.c b/arch/m68k/mm/memory.c --- a/arch/m68k/mm/memory.c Sun Jul 27 10:13:48 2003 +++ b/arch/m68k/mm/memory.c Sun Jul 27 10:13:48 2003 @@ -19,11 +19,7 @@ #include #include #include -#include #include -#ifdef CONFIG_AMIGA -#include -#endif /* ++andreas: {get,free}_pointer_table rewritten to use unused fields from @@ -356,6 +352,109 @@ if(mach_l2_flush) mach_l2_flush(1); #endif +} + +static unsigned long virt_to_phys_slow(unsigned long vaddr) +{ + if (CPU_IS_060) { + mm_segment_t fs = get_fs(); + unsigned long paddr; + + set_fs(get_ds()); + + /* The PLPAR instruction causes an access error if the translation + * is not possible. To catch this we use the same exception mechanism + * as for user space accesses in . */ + asm volatile (".chip 68060\n" + "1: plpar (%0)\n" + ".chip 68k\n" + "2:\n" + ".section .fixup,\"ax\"\n" + " .even\n" + "3: sub.l %0,%0\n" + " jra 2b\n" + ".previous\n" + ".section __ex_table,\"a\"\n" + " .align 4\n" + " .long 1b,3b\n" + ".previous" + : "=a" (paddr) + : "0" (vaddr)); + set_fs(fs); + return paddr; + } else if (CPU_IS_040) { + mm_segment_t fs = get_fs(); + unsigned long mmusr; + + set_fs(get_ds()); + + asm volatile (".chip 68040\n\t" + "ptestr (%1)\n\t" + "movec %%mmusr, %0\n\t" + ".chip 68k" + : "=r" (mmusr) + : "a" (vaddr)); + set_fs(fs); + + if (mmusr & MMU_R_040) + return (mmusr & PAGE_MASK) | (vaddr & ~PAGE_MASK); + } else { + unsigned short mmusr; + unsigned long *descaddr; + + asm volatile ("ptestr #5,%2@,#7,%0\n\t" + "pmove %%psr,%1@" + : "=a&" (descaddr) + : "a" (&mmusr), "a" (vaddr)); + if (mmusr & (MMU_I|MMU_B|MMU_L)) + return 0; + descaddr = phys_to_virt((unsigned long)descaddr); + switch (mmusr & MMU_NUM) { + case 1: + return (*descaddr & 0xfe000000) | (vaddr & 0x01ffffff); + case 2: + return (*descaddr & 0xfffc0000) | (vaddr & 0x0003ffff); + case 3: + return (*descaddr & PAGE_MASK) | (vaddr & ~PAGE_MASK); + } + } + return 0; +} + +/* Push n pages at kernel virtual address and clear the icache */ +/* RZ: use cpush %bc instead of cpush %dc, cinv %ic */ +void flush_icache_range(unsigned long address, unsigned long endaddr) +{ + if (CPU_IS_040_OR_060) { + address &= PAGE_MASK; + + if (address >= PAGE_OFFSET && address < (unsigned long)high_memory) { + do { + asm volatile ("nop\n\t" + ".chip 68040\n\t" + "cpushp %%bc,(%0)\n\t" + ".chip 68k" + : : "a" (virt_to_phys((void *)address))); + address += PAGE_SIZE; + } while (address < endaddr); + } else { + do { + asm volatile ("nop\n\t" + ".chip 68040\n\t" + "cpushp %%bc,(%0)\n\t" + ".chip 68k" + : : "a" (virt_to_phys_slow(address))); + address += PAGE_SIZE; + } while (address < endaddr); + } + } else { + unsigned long tmp; + asm volatile ("movec %%cacr,%0\n\t" + "orw %1,%0\n\t" + "movec %0,%%cacr" + : "=&d" (tmp) + : "di" (FLUSH_I)); + } } diff -Nru a/arch/m68k/mm/motorola.c b/arch/m68k/mm/motorola.c --- a/arch/m68k/mm/motorola.c Sun Jul 27 10:13:47 2003 +++ b/arch/m68k/mm/motorola.c Sun Jul 27 10:13:47 2003 @@ -18,9 +18,6 @@ #include #include #include -#ifdef CONFIG_BLK_DEV_RAM -#include -#endif #include #include @@ -222,18 +219,6 @@ #endif for (i = 0; i < 16; i++) pgprot_val(protection_map[i]) |= _PAGE_CACHE040; - } - /* Fix the PAGE_NONE value. */ - if (CPU_IS_040_OR_060) { - /* On the 680[46]0 we can use the _PAGE_SUPER bit. */ - pgprot_val(protection_map[0]) |= _PAGE_SUPER; - pgprot_val(protection_map[VM_SHARED]) |= _PAGE_SUPER; - } else { - /* Otherwise we must fake it. */ - pgprot_val(protection_map[0]) &= ~_PAGE_PRESENT; - pgprot_val(protection_map[0]) |= _PAGE_FAKE_SUPER; - pgprot_val(protection_map[VM_SHARED]) &= ~_PAGE_PRESENT; - pgprot_val(protection_map[VM_SHARED]) |= _PAGE_FAKE_SUPER; } /* diff -Nru a/arch/m68k/mm/sun3mmu.c b/arch/m68k/mm/sun3mmu.c --- a/arch/m68k/mm/sun3mmu.c Sun Jul 27 10:13:43 2003 +++ b/arch/m68k/mm/sun3mmu.c Sun Jul 27 10:13:43 2003 @@ -16,9 +16,6 @@ #include #include #include -#ifdef CONFIG_BLK_DEV_RAM -#include -#endif #include #include diff -Nru a/arch/m68k/q40/q40ints.c b/arch/m68k/q40/q40ints.c --- a/arch/m68k/q40/q40ints.c Sun Jul 27 10:13:51 2003 +++ b/arch/m68k/q40/q40ints.c Sun Jul 27 10:13:51 2003 @@ -171,7 +171,7 @@ { case 1: case 2: case 8: case 9: case 12: case 13: - printk("%s: ISA IRQ %d from %x illegal\n", __FUNCTION__, irq, (unsigned)dev_id); + printk("%s: ISA IRQ %d from %x invalid\n", __FUNCTION__, irq, (unsigned)dev_id); return; case 11: irq=10; default: diff -Nru a/arch/m68knommu/Makefile b/arch/m68knommu/Makefile --- a/arch/m68knommu/Makefile Sun Jul 27 10:13:49 2003 +++ b/arch/m68knommu/Makefile Sun Jul 27 10:13:49 2003 @@ -85,8 +85,6 @@ CFLAGS += -D__linux__ CFLAGS += -DUTS_SYSNAME=\"uClinux\" -LDFLAGS_BLOB := --format binary --oformat elf32-m68k - head-y := arch/m68knommu/platform/$(platform-y)/$(board-y)/crt0_$(model-y).o CLEAN_FILES := include/asm-$(ARCH)/asm-offsets.h \ diff -Nru a/arch/m68knommu/kernel/setup.c b/arch/m68knommu/kernel/setup.c --- a/arch/m68knommu/kernel/setup.c Sun Jul 27 10:13:48 2003 +++ b/arch/m68knommu/kernel/setup.c Sun Jul 27 10:13:48 2003 @@ -37,7 +37,6 @@ #include #ifdef CONFIG_BLK_DEV_INITRD -#include #include #endif diff -Nru a/arch/m68knommu/mm/init.c b/arch/m68knommu/mm/init.c --- a/arch/m68knommu/mm/init.c Sun Jul 27 10:13:48 2003 +++ b/arch/m68knommu/mm/init.c Sun Jul 27 10:13:48 2003 @@ -27,9 +27,6 @@ #include #include #include -#ifdef CONFIG_BLK_DEV_RAM -#include -#endif #include #include #include diff -Nru a/arch/mips/Makefile b/arch/mips/Makefile --- a/arch/mips/Makefile Sun Jul 27 10:13:40 2003 +++ b/arch/mips/Makefile Sun Jul 27 10:13:40 2003 @@ -18,11 +18,9 @@ ifdef CONFIG_CPU_LITTLE_ENDIAN tool-prefix = mipsel-linux- JIFFIES32 = jiffies_64 -LDFLAGS_BLOB := --format binary --oformat elf32-tradlittlemips else tool-prefix = mips-linux- JIFFIES32 = jiffies_64 + 4 -LDFLAGS_BLOB := --format binary --oformat elf32-tradbigmips endif ifdef CONFIG_CROSSCOMPILE diff -Nru a/arch/mips/mm/fault.c b/arch/mips/mm/fault.c --- a/arch/mips/mm/fault.c Sun Jul 27 10:13:43 2003 +++ b/arch/mips/mm/fault.c Sun Jul 27 10:13:43 2003 @@ -162,7 +162,7 @@ tsk->thread.cp0_badvaddr = address; tsk->thread.error_code = write; #if 0 - printk("do_page_fault() #2: sending SIGSEGV to %s for illegal %s\n" + printk("do_page_fault() #2: sending SIGSEGV to %s for invalid %s\n" "%08lx (epc == %08lx, ra == %08lx)\n", tsk->comm, write ? "write access to" : "read access from", diff -Nru a/arch/mips/mm/init.c b/arch/mips/mm/init.c --- a/arch/mips/mm/init.c Sun Jul 27 10:13:50 2003 +++ b/arch/mips/mm/init.c Sun Jul 27 10:13:50 2003 @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include diff -Nru a/arch/mips/momentum/ocelot_c/setup.c b/arch/mips/momentum/ocelot_c/setup.c --- a/arch/mips/momentum/ocelot_c/setup.c Sun Jul 27 10:13:42 2003 +++ b/arch/mips/momentum/ocelot_c/setup.c Sun Jul 27 10:13:42 2003 @@ -63,7 +63,7 @@ #include #include #include -#include +#include #include #include "ocelot_c_fpga.h" diff -Nru a/arch/mips/momentum/ocelot_g/setup.c b/arch/mips/momentum/ocelot_g/setup.c --- a/arch/mips/momentum/ocelot_g/setup.c Sun Jul 27 10:13:43 2003 +++ b/arch/mips/momentum/ocelot_g/setup.c Sun Jul 27 10:13:43 2003 @@ -64,7 +64,7 @@ #include #include #include -#include +#include #include "gt64240.h" #include "ocelot_pld.h" diff -Nru a/arch/mips/ramdisk/Makefile b/arch/mips/ramdisk/Makefile --- a/arch/mips/ramdisk/Makefile Sun Jul 27 10:13:48 2003 +++ b/arch/mips/ramdisk/Makefile Sun Jul 27 10:13:48 2003 @@ -2,7 +2,7 @@ # Makefile for a ramdisk image # -O_FORMAT = $(shell $(OBJDUMP) -i | head -2 | grep elf32) +O_FORMAT = $(shell $(OBJDUMP) -i | head -n 2 | grep elf32) img = $(CONFIG_EMBEDDED_RAMDISK_IMAGE) ramdisk.o: $(subst ",,$(img)) ld.script echo "O_FORMAT: " $(O_FORMAT) diff -Nru a/arch/mips/sibyte/cfe/setup.c b/arch/mips/sibyte/cfe/setup.c --- a/arch/mips/sibyte/cfe/setup.c Sun Jul 27 10:13:42 2003 +++ b/arch/mips/sibyte/cfe/setup.c Sun Jul 27 10:13:42 2003 @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include diff -Nru a/arch/mips/sibyte/sb1250/prom.c b/arch/mips/sibyte/sb1250/prom.c --- a/arch/mips/sibyte/sb1250/prom.c Sun Jul 27 10:13:49 2003 +++ b/arch/mips/sibyte/sb1250/prom.c Sun Jul 27 10:13:49 2003 @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include diff -Nru a/arch/mips/sibyte/swarm/setup.c b/arch/mips/sibyte/swarm/setup.c --- a/arch/mips/sibyte/swarm/setup.c Sun Jul 27 10:13:45 2003 +++ b/arch/mips/sibyte/swarm/setup.c Sun Jul 27 10:13:45 2003 @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include #include diff -Nru a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c --- a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c Sun Jul 27 10:13:43 2003 +++ b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c Sun Jul 27 10:13:43 2003 @@ -134,7 +134,7 @@ #include #include #include -#include +#include #ifdef CONFIG_RTC_DS1742 #include #endif diff -Nru a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c --- a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c Sun Jul 27 10:13:47 2003 +++ b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c Sun Jul 27 10:13:47 2003 @@ -62,7 +62,7 @@ #include #include #include -#include +#include #include #ifdef CONFIG_RTC_DS1742 #include diff -Nru a/arch/mips/vr41xx/tanbac-tb0229/setup.c b/arch/mips/vr41xx/tanbac-tb0229/setup.c --- a/arch/mips/vr41xx/tanbac-tb0229/setup.c Sun Jul 27 10:13:46 2003 +++ b/arch/mips/vr41xx/tanbac-tb0229/setup.c Sun Jul 27 10:13:46 2003 @@ -18,7 +18,7 @@ * option) any later version. */ #include -#include +#include #include #include #include diff -Nru a/arch/mips64/kernel/setup.c b/arch/mips64/kernel/setup.c --- a/arch/mips64/kernel/setup.c Sun Jul 27 10:13:40 2003 +++ b/arch/mips64/kernel/setup.c Sun Jul 27 10:13:40 2003 @@ -28,9 +28,6 @@ #include #include #include -#ifdef CONFIG_BLK_DEV_RAM -#include -#endif #include #include #include diff -Nru a/arch/parisc/Makefile b/arch/parisc/Makefile --- a/arch/parisc/Makefile Sun Jul 27 10:13:51 2003 +++ b/arch/parisc/Makefile Sun Jul 27 10:13:51 2003 @@ -20,13 +20,11 @@ ifdef CONFIG_PARISC64 CROSS_COMPILE := hppa64-linux- UTS_MACHINE := parisc64 -LDFLAGS_BLOB := --format binary --oformat elf64-hppa-linux else MACHINE := $(subst 64,,$(shell uname -m)) ifneq ($(MACHINE),parisc) CROSS_COMPILE := hppa-linux- endif -LDFLAGS_BLOB := --format binary --oformat elf32-hppa-linux endif FINAL_LD=$(CROSS_COMPILE)ld --warn-common --warn-section-align diff -Nru a/arch/parisc/kernel/ioctl32.c b/arch/parisc/kernel/ioctl32.c --- a/arch/parisc/kernel/ioctl32.c Sun Jul 27 10:13:40 2003 +++ b/arch/parisc/kernel/ioctl32.c Sun Jul 27 10:13:40 2003 @@ -48,7 +48,6 @@ #include #include #include -#include #include #include #include diff -Nru a/arch/ppc/Makefile b/arch/ppc/Makefile --- a/arch/ppc/Makefile Sun Jul 27 10:13:40 2003 +++ b/arch/ppc/Makefile Sun Jul 27 10:13:40 2003 @@ -13,7 +13,6 @@ # This must match PAGE_OFFSET in include/asm-ppc/page.h. KERNELLOAD := $(CONFIG_KERNEL_START) -LDFLAGS_BLOB := --format binary --oformat elf32-powerpc LDFLAGS_vmlinux := -Ttext $(KERNELLOAD) -Bstatic CPPFLAGS += -Iarch/$(ARCH) AFLAGS += -Iarch/$(ARCH) diff -Nru a/arch/ppc/configs/apus_defconfig b/arch/ppc/configs/apus_defconfig --- a/arch/ppc/configs/apus_defconfig Sun Jul 27 10:13:50 2003 +++ b/arch/ppc/configs/apus_defconfig Sun Jul 27 10:13:50 2003 @@ -421,8 +421,7 @@ # CONFIG_MII is not set # CONFIG_OAKNET is not set CONFIG_ARIADNE=y -# CONFIG_ARIADNE2 is not set -CONFIG_NE2K_ZORRO=y +# CONFIG_ZORRO8390 is not set CONFIG_A2065=y CONFIG_HYDRA=y # CONFIG_HAPPYMEAL is not set diff -Nru a/arch/ppc/kernel/irq.c b/arch/ppc/kernel/irq.c --- a/arch/ppc/kernel/irq.c Sun Jul 27 10:13:50 2003 +++ b/arch/ppc/kernel/irq.c Sun Jul 27 10:13:50 2003 @@ -420,10 +420,9 @@ { int status; struct irqaction *action; - int cpu = smp_processor_id(); irq_desc_t *desc = irq_desc + irq; - kstat_cpu(cpu).irqs[irq]++; + kstat_this_cpu.irqs[irq]++; spin_lock(&desc->lock); ack_irq(irq); /* diff -Nru a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S --- a/arch/ppc/kernel/misc.S Sun Jul 27 10:13:51 2003 +++ b/arch/ppc/kernel/misc.S Sun Jul 27 10:13:51 2003 @@ -1375,3 +1375,8 @@ .long sys_clock_gettime .long sys_clock_getres .long sys_clock_nanosleep + .long sys_ni_syscall /* reserved for swapcontext */ + .long sys_tgkill /* 250 */ + .long sys_utimes + .long sys_statfs64 + .long sys_fstatfs64 diff -Nru a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c --- a/arch/ppc/kernel/setup.c Sun Jul 27 10:13:52 2003 +++ b/arch/ppc/kernel/setup.c Sun Jul 27 10:13:52 2003 @@ -268,7 +268,6 @@ unsigned long early_init(int r3, int r4, int r5) { - extern char __bss_start, _end; unsigned long phys; unsigned long offset = reloc_offset(); @@ -277,7 +276,7 @@ /* First zero the BSS -- use memset, some arches don't have * caches on yet */ - memset_io(PTRRELOC(&__bss_start), 0, &_end - &__bss_start); + memset_io(PTRRELOC(&__bss_start), 0, _end - __bss_start); /* * Identify the CPU type and fix up code sections @@ -466,7 +465,6 @@ struct bi_record *find_bootinfo(void) { struct bi_record *rec; - extern char __bss_start[]; rec = (struct bi_record *)_ALIGN((ulong)__bss_start+(1<<20)-1,(1<<20)); if ( rec->tag != BI_FIRST ) { @@ -591,7 +589,6 @@ void __init setup_arch(char **cmdline_p) { extern int panic_timeout; - extern char _etext[], _edata[]; extern char *klimit; extern void do_init_bootmem(void); diff -Nru a/arch/ppc/kernel/syscalls.c b/arch/ppc/kernel/syscalls.c --- a/arch/ppc/kernel/syscalls.c Sun Jul 27 10:13:52 2003 +++ b/arch/ppc/kernel/syscalls.c Sun Jul 27 10:13:52 2003 @@ -20,7 +20,6 @@ * */ -#include #include #include #include @@ -59,10 +58,15 @@ version = call >> 16; /* hack for backward compatibility */ call &= 0xffff; - ret = -EINVAL; + ret = -ENOSYS; switch (call) { case SEMOP: - ret = sys_semop (first, (struct sembuf __user *)ptr, second); + ret = sys_semtimedop (first, (struct sembuf __user *)ptr, + second, NULL); + break; + case SEMTIMEDOP: + ret = sys_semtimedop (first, (struct sembuf __user *)ptr, + second, (const struct timespec *) fifth); break; case SEMGET: ret = sys_semget (first, second, third); @@ -258,6 +262,4 @@ return error; } -cond_syscall(sys_pciconfig_read); -cond_syscall(sys_pciconfig_write); cond_syscall(sys_pciconfig_iobase); diff -Nru a/arch/ppc/kernel/time.c b/arch/ppc/kernel/time.c --- a/arch/ppc/kernel/time.c Sun Jul 27 10:13:49 2003 +++ b/arch/ppc/kernel/time.c Sun Jul 27 10:13:49 2003 @@ -244,7 +244,7 @@ time_t wtm_sec, new_sec = tv->tv_sec; long wtm_nsec, new_nsec = tv->tv_nsec; unsigned long flags; - int tb_delta, new_nsec, new_sec; + int tb_delta; if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) return -EINVAL; diff -Nru a/arch/ppc/mm/mem_pieces.c b/arch/ppc/mm/mem_pieces.c --- a/arch/ppc/mm/mem_pieces.c Sun Jul 27 10:13:40 2003 +++ b/arch/ppc/mm/mem_pieces.c Sun Jul 27 10:13:40 2003 @@ -17,8 +17,8 @@ #include #include #include -#include #include +#include #include "mem_pieces.h" diff -Nru a/arch/ppc/platforms/4xx/beech.c b/arch/ppc/platforms/4xx/beech.c --- a/arch/ppc/platforms/4xx/beech.c Sun Jul 27 10:13:46 2003 +++ b/arch/ppc/platforms/4xx/beech.c Sun Jul 27 10:13:46 2003 @@ -25,7 +25,6 @@ * */ -#include #include #include #include diff -Nru a/arch/ppc/platforms/4xx/sycamore.c b/arch/ppc/platforms/4xx/sycamore.c --- a/arch/ppc/platforms/4xx/sycamore.c Sun Jul 27 10:13:48 2003 +++ b/arch/ppc/platforms/4xx/sycamore.c Sun Jul 27 10:13:48 2003 @@ -17,7 +17,6 @@ #include #include #include -#include #include #include diff -Nru a/arch/ppc/platforms/4xx/walnut.c b/arch/ppc/platforms/4xx/walnut.c --- a/arch/ppc/platforms/4xx/walnut.c Sun Jul 27 10:13:47 2003 +++ b/arch/ppc/platforms/4xx/walnut.c Sun Jul 27 10:13:47 2003 @@ -19,7 +19,6 @@ #include #include #include -#include #include #include diff -Nru a/arch/ppc/platforms/pmac_cpufreq.c b/arch/ppc/platforms/pmac_cpufreq.c --- a/arch/ppc/platforms/pmac_cpufreq.c Sun Jul 27 10:13:47 2003 +++ b/arch/ppc/platforms/pmac_cpufreq.c Sun Jul 27 10:13:47 2003 @@ -176,7 +176,7 @@ freqs.old = cur_freq; freqs.new = (speed_mode == PMAC_CPU_HIGH_SPEED) ? hi_freq : low_freq; - freqs.cpu = CPUFREQ_ALL_CPUS; + freqs.cpu = smp_processor_id(); cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); if (cpufreq_uses_pmu) diff -Nru a/arch/ppc/platforms/residual.c b/arch/ppc/platforms/residual.c --- a/arch/ppc/platforms/residual.c Sun Jul 27 10:13:42 2003 +++ b/arch/ppc/platforms/residual.c Sun Jul 27 10:13:42 2003 @@ -36,7 +36,6 @@ #include #include #include -#include #include #include #include diff -Nru a/arch/ppc/syslib/prom_init.c b/arch/ppc/syslib/prom_init.c --- a/arch/ppc/syslib/prom_init.c Sun Jul 27 10:13:52 2003 +++ b/arch/ppc/syslib/prom_init.c Sun Jul 27 10:13:52 2003 @@ -133,7 +133,6 @@ struct device_node *allnodes; extern char *klimit; -extern char _stext; static void __init prom_exit(void) @@ -601,7 +600,7 @@ /* copy the holding pattern code to someplace safe (0) */ /* the holding pattern is now within the first 0x100 bytes of the kernel image -- paulus */ - memcpy((void *)0, &_stext, 0x100); + memcpy((void *)0, _stext, 0x100); flush_icache_range(0, 0x100); /* look for cpus */ @@ -631,7 +630,7 @@ prom_print(path); *(ulong *)(0x4) = 0; call_prom("start-cpu", 3, 0, node, - (char *)__secondary_hold - &_stext, cpu); + (char *)__secondary_hold - _stext, cpu); prom_print("..."); for ( i = 0 ; (i < 10000) && (*(ulong *)(0x4) == 0); i++ ) ; diff -Nru a/arch/ppc64/Makefile b/arch/ppc64/Makefile --- a/arch/ppc64/Makefile Sun Jul 27 10:13:41 2003 +++ b/arch/ppc64/Makefile Sun Jul 27 10:13:41 2003 @@ -17,7 +17,6 @@ LDFLAGS := -m elf64ppc LDFLAGS_vmlinux := -Bstatic -e $(KERNELLOAD) -Ttext $(KERNELLOAD) -LDFLAGS_BLOB := --format binary --oformat elf64-powerpc CFLAGS += -msoft-float -pipe -Wno-uninitialized -mminimal-toc \ -mtraceback=full -mcpu=power4 diff -Nru a/arch/ppc64/boot/Makefile b/arch/ppc64/boot/Makefile --- a/arch/ppc64/boot/Makefile Sun Jul 27 10:13:50 2003 +++ b/arch/ppc64/boot/Makefile Sun Jul 27 10:13:50 2003 @@ -118,7 +118,7 @@ ls -l vmlinux | \ awk '{printf "/* generated -- do not edit! */\n" \ "unsigned long vmlinux_filesize = %d;\n", $$5}' > $(obj)/imagesize.c - $(CROSS_COMPILE)nm -n vmlinux | tail -1 | \ + $(CROSS_COMPILE)nm -n vmlinux | tail -n 1 | \ awk '{printf "unsigned long vmlinux_memsize = 0x%s;\n", substr($$1,8)}' \ >> $(obj)/imagesize.c diff -Nru a/arch/ppc64/kernel/XmPciLpEvent.c b/arch/ppc64/kernel/XmPciLpEvent.c --- a/arch/ppc64/kernel/XmPciLpEvent.c Sun Jul 27 10:13:45 2003 +++ b/arch/ppc64/kernel/XmPciLpEvent.c Sun Jul 27 10:13:45 2003 @@ -12,7 +12,6 @@ #include #include #include -#include #include #include diff -Nru a/arch/ppc64/kernel/iSeries_irq.c b/arch/ppc64/kernel/iSeries_irq.c --- a/arch/ppc64/kernel/iSeries_irq.c Sun Jul 27 10:13:49 2003 +++ b/arch/ppc64/kernel/iSeries_irq.c Sun Jul 27 10:13:49 2003 @@ -29,7 +29,6 @@ #include #include #include -#include #include #include diff -Nru a/arch/ppc64/kernel/prom.c b/arch/ppc64/kernel/prom.c --- a/arch/ppc64/kernel/prom.c Sun Jul 27 10:13:49 2003 +++ b/arch/ppc64/kernel/prom.c Sun Jul 27 10:13:49 2003 @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include diff -Nru a/arch/ppc64/mm/init.c b/arch/ppc64/mm/init.c --- a/arch/ppc64/mm/init.c Sun Jul 27 10:13:47 2003 +++ b/arch/ppc64/mm/init.c Sun Jul 27 10:13:47 2003 @@ -37,9 +37,6 @@ #include #include #include -#ifdef CONFIG_BLK_DEV_INITRD -#include /* for initrd_* */ -#endif #include #include diff -Nru a/arch/s390/Makefile b/arch/s390/Makefile --- a/arch/s390/Makefile Sun Jul 27 10:13:42 2003 +++ b/arch/s390/Makefile Sun Jul 27 10:13:42 2003 @@ -17,7 +17,6 @@ ifdef CONFIG_ARCH_S390_31 LDFLAGS := -m elf_s390 -LDFLAGS_BLOB := --format binary --oformat elf32-s390 CFLAGS += -m31 AFLAGS += -m31 UTS_MACHINE := s390 @@ -26,7 +25,6 @@ ifdef CONFIG_ARCH_S390X LDFLAGS := -m elf64_s390 MODFLAGS += -fpic -D__PIC__ -LDFLAGS_BLOB := --format binary --oformat elf64-s390 CFLAGS += -m64 AFLAGS += -m64 UTS_MACHINE := s390x diff -Nru a/arch/s390/defconfig b/arch/s390/defconfig --- a/arch/s390/defconfig Sun Jul 27 10:13:50 2003 +++ b/arch/s390/defconfig Sun Jul 27 10:13:50 2003 @@ -20,6 +20,7 @@ CONFIG_SYSCTL=y CONFIG_LOG_BUF_SHIFT=17 # CONFIG_EMBEDDED is not set +# CONFIG_KALLSYMS is not set CONFIG_FUTEX=y CONFIG_EPOLL=y @@ -169,7 +170,7 @@ # CONFIG_INET_AH is not set # CONFIG_INET_ESP is not set # CONFIG_INET_IPCOMP is not set -CONFIG_IPV6=m +CONFIG_IPV6=y # CONFIG_IPV6_PRIVACY is not set # CONFIG_INET6_AH is not set # CONFIG_INET6_ESP is not set @@ -180,7 +181,7 @@ # # SCTP Configuration (EXPERIMENTAL) # -CONFIG_IPV6_SCTP__=m +CONFIG_IPV6_SCTP__=y # CONFIG_IP_SCTP is not set # CONFIG_ATM is not set # CONFIG_VLAN_8021Q is not set @@ -383,7 +384,6 @@ CONFIG_DEBUG_KERNEL=y CONFIG_MAGIC_SYSRQ=y # CONFIG_DEBUG_SLAB is not set -# CONFIG_KALLSYMS is not set # CONFIG_DEBUG_SPINLOCK_SLEEP is not set # diff -Nru a/arch/s390/kernel/compat_ioctl.c b/arch/s390/kernel/compat_ioctl.c --- a/arch/s390/kernel/compat_ioctl.c Sun Jul 27 10:13:48 2003 +++ b/arch/s390/kernel/compat_ioctl.c Sun Jul 27 10:13:48 2003 @@ -23,7 +23,6 @@ #include #include -#include #include #include #include diff -Nru a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c --- a/arch/s390/kernel/compat_linux.c Sun Jul 27 10:13:50 2003 +++ b/arch/s390/kernel/compat_linux.c Sun Jul 27 10:13:50 2003 @@ -250,14 +250,14 @@ static inline long get_tv32(struct timeval *o, struct compat_timeval *i) { return (!access_ok(VERIFY_READ, tv32, sizeof(*tv32)) || - (__get_user(o->tv_sec, &i->tv_sec) | + (__get_user(o->tv_sec, &i->tv_sec) || __get_user(o->tv_usec, &i->tv_usec))); } static inline long put_tv32(struct compat_timeval *o, struct timeval *i) { return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) || - (__put_user(i->tv_sec, &o->tv_sec) | + (__put_user(i->tv_sec, &o->tv_sec) || __put_user(i->tv_usec, &o->tv_usec))); } diff -Nru a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S --- a/arch/s390/kernel/entry.S Sun Jul 27 10:13:42 2003 +++ b/arch/s390/kernel/entry.S Sun Jul 27 10:13:42 2003 @@ -606,6 +606,8 @@ SAVE_ALL_BASE SAVE_ALL __LC_EXT_OLD_PSW,0 GET_THREAD_INFO # load pointer to task_struct to R9 + l %r1,BASED(.Ldo_extint) + basr %r14,%r1 lh %r6,__LC_EXT_INT_CODE # get interruption code lr %r1,%r6 # calculate index = code & 0xff n %r1,BASED(.Lc0xff) @@ -694,6 +696,7 @@ */ .Ls390_mcck: .long s390_do_machine_check .Ldo_IRQ: .long do_IRQ +.Ldo_extint: .long do_extint .Ldo_signal: .long do_signal .Ldo_softirq: .long do_softirq .Lentry_base: .long entry_base diff -Nru a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S --- a/arch/s390/kernel/entry64.S Sun Jul 27 10:13:42 2003 +++ b/arch/s390/kernel/entry64.S Sun Jul 27 10:13:42 2003 @@ -637,6 +637,7 @@ ext_int_handler: SAVE_ALL __LC_EXT_OLD_PSW,0 GET_THREAD_INFO # load pointer to task_struct to R9 + brasl %r14,do_extint llgh %r6,__LC_EXT_INT_CODE # get interruption code lgr %r1,%r6 # calculate index = code & 0xff nill %r1,0xff diff -Nru a/arch/s390/kernel/s390_ext.c b/arch/s390/kernel/s390_ext.c --- a/arch/s390/kernel/s390_ext.c Sun Jul 27 10:13:45 2003 +++ b/arch/s390/kernel/s390_ext.c Sun Jul 27 10:13:45 2003 @@ -11,8 +11,11 @@ #include #include #include +#include + #include #include +#include /* * Simple hash strategy: index = code & 0xff; @@ -96,6 +99,11 @@ } else ext_int_hash[index] = p->next; return 0; +} + +void do_extint(void) +{ + kstat_cpu(smp_processor_id()).irqs[EXTERNAL_INTERRUPT]++; } EXPORT_SYMBOL(register_external_interrupt); diff -Nru a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c --- a/arch/s390/kernel/setup.c Sun Jul 27 10:13:41 2003 +++ b/arch/s390/kernel/setup.c Sun Jul 27 10:13:41 2003 @@ -34,12 +34,15 @@ #include #include #include +#include + #include #include #include #include #include #include +#include /* * Machine setup.. @@ -600,3 +603,40 @@ .stop = c_stop, .show = show_cpuinfo, }; + +/* + * show_interrupts is needed by /proc/interrupts. + */ + +static const char *intrclass_names[] = { + "EXT", + "I/O", +}; + +int show_interrupts(struct seq_file *p, void *v) +{ + int i, j; + + seq_puts(p, " "); + + for (j=0; j #include #include -#ifdef CONFIG_BLK_DEV_INITRD -#include -#endif #include #include diff -Nru a/arch/sh/Makefile b/arch/sh/Makefile --- a/arch/sh/Makefile Sun Jul 27 10:13:48 2003 +++ b/arch/sh/Makefile Sun Jul 27 10:13:48 2003 @@ -50,10 +50,8 @@ ifdef CONFIG_CPU_LITTLE_ENDIAN LDFLAGS_vmlinux += --defsym 'jiffies=jiffies_64' -EL -LDFLAGS_BLOB :=--format binary --oformat elf32-sh-linux else LDFLAGS_vmlinux += --defsym 'jiffies=jiffies_64+4' -EB -LDFLAGS_BLOB :=--format binary --oformat elf32-shbig-linux endif CFLAGS += -pipe $(cpu-y) diff -Nru a/arch/sh/mm/init.c b/arch/sh/mm/init.c --- a/arch/sh/mm/init.c Sun Jul 27 10:13:50 2003 +++ b/arch/sh/mm/init.c Sun Jul 27 10:13:50 2003 @@ -22,9 +22,6 @@ #include #include #include -#ifdef CONFIG_BLK_DEV_INITRD -#include -#endif #include #include diff -Nru a/arch/sparc/Makefile b/arch/sparc/Makefile --- a/arch/sparc/Makefile Sun Jul 27 10:13:41 2003 +++ b/arch/sparc/Makefile Sun Jul 27 10:13:41 2003 @@ -23,8 +23,6 @@ LDFLAGS := -m elf32_sparc endif -LDFLAGS_BLOB := --format binary --oformat elf32-sparc - #CFLAGS := $(CFLAGS) -g -pipe -fcall-used-g5 -fcall-used-g7 ifneq ($(IS_EGCS),y) CFLAGS := $(CFLAGS) -pipe -mno-fpu -fcall-used-g5 -fcall-used-g7 diff -Nru a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c --- a/arch/sparc/kernel/process.c Sun Jul 27 10:13:41 2003 +++ b/arch/sparc/kernel/process.c Sun Jul 27 10:13:41 2003 @@ -590,16 +590,20 @@ put_psr(get_psr() | PSR_EF); fpsave(¤t->thread.float_regs[0], ¤t->thread.fsr, ¤t->thread.fpqueue[0], ¤t->thread.fpqdepth); - regs->psr &= ~(PSR_EF); - current->flags &= ~(PF_USEDFPU); + if (regs != NULL) { + regs->psr &= ~(PSR_EF); + current->flags &= ~(PF_USEDFPU); + } } #else if (current == last_task_used_math) { put_psr(get_psr() | PSR_EF); fpsave(¤t->thread.float_regs[0], ¤t->thread.fsr, ¤t->thread.fpqueue[0], ¤t->thread.fpqdepth); - last_task_used_math = 0; - regs->psr &= ~(PSR_EF); + if (regs != NULL) { + regs->psr &= ~(PSR_EF); + last_task_used_math = 0; + } } #endif memcpy(&fpregs->pr_fr.pr_regs[0], diff -Nru a/arch/sparc/kernel/setup.c b/arch/sparc/kernel/setup.c --- a/arch/sparc/kernel/setup.c Sun Jul 27 10:13:40 2003 +++ b/arch/sparc/kernel/setup.c Sun Jul 27 10:13:40 2003 @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include diff -Nru a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c --- a/arch/sparc/mm/srmmu.c Sun Jul 27 10:13:47 2003 +++ b/arch/sparc/mm/srmmu.c Sun Jul 27 10:13:47 2003 @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff -Nru a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig --- a/arch/sparc64/Kconfig Sun Jul 27 10:13:51 2003 +++ b/arch/sparc64/Kconfig Sun Jul 27 10:13:51 2003 @@ -16,6 +16,7 @@ config BBC_I2C tristate "UltraSPARC-III bootbus i2c controller driver" + depends on PCI help The BBC devices on the UltraSPARC III have two I2C controllers. The first I2C controller connects mainly to configuration PROMs (NVRAM, @@ -208,10 +209,6 @@ to use devices as you hotplug them. # Global things across all Sun machines. -config HAVE_DEC_LOCK - bool - default y - config RWSEM_GENERIC_SPINLOCK bool @@ -923,6 +920,14 @@ and certain other kinds of spinlock errors commonly made. This is best used in conjunction with the NMI watchdog so that spinlock deadlocks are also debuggable. + +# We have a custom atomic_dec_and_lock() implementation but it's not +# compatible with spinlock debugging so we need to fall back on +# the generic version in that case. +config HAVE_DEC_LOCK + bool + depends on !DEBUG_SPINLOCK + default y config DEBUG_SPINLOCK_SLEEP bool "Sleep-inside-spinlock checking" diff -Nru a/arch/sparc64/Makefile b/arch/sparc64/Makefile --- a/arch/sparc64/Makefile Sun Jul 27 10:13:52 2003 +++ b/arch/sparc64/Makefile Sun Jul 27 10:13:52 2003 @@ -32,7 +32,6 @@ else AS := $(AS) -64 LDFLAGS := -m elf64_sparc -LDFLAGS_BLOB := --format binary --oformat elf64-sparc endif ifneq ($(UNDECLARED_REGS),y) diff -Nru a/arch/sparc64/defconfig b/arch/sparc64/defconfig --- a/arch/sparc64/defconfig Sun Jul 27 10:13:43 2003 +++ b/arch/sparc64/defconfig Sun Jul 27 10:13:43 2003 @@ -17,6 +17,7 @@ CONFIG_SYSCTL=y CONFIG_LOG_BUF_SHIFT=15 # CONFIG_EMBEDDED is not set +CONFIG_KALLSYMS=y CONFIG_FUTEX=y CONFIG_EPOLL=y @@ -202,6 +203,7 @@ CONFIG_MD_RAID5=m CONFIG_MD_MULTIPATH=m CONFIG_BLK_DEV_DM=m +# CONFIG_DM_IOCTL_V4 is not set # CONFIG_BLK_DEV_RAM is not set # @@ -269,7 +271,7 @@ CONFIG_BLK_DEV_IDE_MODES=y # -# SCSI support +# SCSI device support # CONFIG_SCSI=y @@ -479,8 +481,43 @@ CONFIG_IP_NF_TARGET_TCPMSS=m CONFIG_IP_NF_ARPTABLES=m CONFIG_IP_NF_ARPFILTER=m +CONFIG_IP_NF_ARP_MANGLE=m CONFIG_IP_NF_COMPAT_IPCHAINS=m CONFIG_IP_NF_COMPAT_IPFWADM=m + +# +# IP: Virtual Server Configuration +# +CONFIG_IP_VS=m +# CONFIG_IP_VS_DEBUG is not set +CONFIG_IP_VS_TAB_BITS=12 + +# +# IPVS transport protocol load balancing support +# +CONFIG_IP_VS_PROTO_TCP=y +CONFIG_IP_VS_PROTO_UDP=y +CONFIG_IP_VS_PROTO_ESP=y +CONFIG_IP_VS_PROTO_AH=y + +# +# IPVS scheduler +# +CONFIG_IP_VS_RR=m +CONFIG_IP_VS_WRR=m +CONFIG_IP_VS_LC=m +CONFIG_IP_VS_WLC=m +CONFIG_IP_VS_LBLC=m +CONFIG_IP_VS_LBLCR=m +CONFIG_IP_VS_DH=m +CONFIG_IP_VS_SH=m +CONFIG_IP_VS_SED=m +CONFIG_IP_VS_NQ=m + +# +# IPVS application helper +# +CONFIG_IP_VS_FTP=m CONFIG_IPV6=m CONFIG_IPV6_PRIVACY=y CONFIG_INET6_AH=m @@ -821,7 +858,6 @@ # # Dongle support # -# CONFIG_DONGLE is not set # # Old SIR device drivers @@ -832,19 +868,13 @@ # # Old Serial dongle support # -# CONFIG_DONGLE_OLD is not set # # FIR device drivers # # CONFIG_USB_IRDA is not set -# CONFIG_NSC_FIR is not set -# CONFIG_WINBOND_FIR is not set # CONFIG_TOSHIBA_OLD is not set # CONFIG_TOSHIBA_FIR is not set -# CONFIG_SMC_IRCC_OLD is not set -# CONFIG_SMC_IRCC_FIR is not set -# CONFIG_ALI_FIR is not set # CONFIG_VLSI_FIR is not set # @@ -886,7 +916,6 @@ # CONFIG_PHONE=m CONFIG_PHONE_IXJ=m -# CONFIG_PHONE_IXJ_PCMCIA is not set # # Unix 98 PTY support diff -Nru a/arch/sparc64/kernel/cpu.c b/arch/sparc64/kernel/cpu.c --- a/arch/sparc64/kernel/cpu.c Sun Jul 27 10:13:50 2003 +++ b/arch/sparc64/kernel/cpu.c Sun Jul 27 10:13:50 2003 @@ -34,6 +34,7 @@ { 0x17, 0x13, 0, "UltraSparc IIe integrated FPU"}, { 0x3e, 0x14, 0, "UltraSparc III integrated FPU"}, { 0x3e, 0x15, 0, "UltraSparc III+ integrated FPU"}, + { 0x3e, 0x16, 0, "UltraSparc IIIi integrated FPU"}, }; #define NSPARCFPU (sizeof(linux_sparc_fpu)/sizeof(struct cpu_fp_info)) @@ -42,10 +43,11 @@ { 0x17, 0x10, "TI UltraSparc I (SpitFire)"}, { 0x22, 0x10, "TI UltraSparc I (SpitFire)"}, { 0x17, 0x11, "TI UltraSparc II (BlackBird)"}, - { 0x17, 0x12, "TI UltraSparc IIi"}, - { 0x17, 0x13, "TI UltraSparc IIe"}, + { 0x17, 0x12, "TI UltraSparc IIi (Sabre)"}, + { 0x17, 0x13, "TI UltraSparc IIe (Hummingbird)"}, { 0x3e, 0x14, "TI UltraSparc III (Cheetah)"}, { 0x3e, 0x15, "TI UltraSparc III+ (Cheetah+)"}, + { 0x3e, 0x16, "TI UltraSparc IIIi (Jalapeno)"}, }; #define NSPARCCHIPS (sizeof(linux_sparc_chips)/sizeof(struct cpu_iu_info)) diff -Nru a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S --- a/arch/sparc64/kernel/entry.S Sun Jul 27 10:13:39 2003 +++ b/arch/sparc64/kernel/entry.S Sun Jul 27 10:13:39 2003 @@ -911,10 +911,15 @@ sllx %g1, 63, %g2; \ or %g4, %g2, %g4; \ /* Get log entry pointer for this cpu at this trap level. */ \ + BRANCH_IF_JALAPENO(g2,g3,50f) \ ldxa [%g0] ASI_SAFARI_CONFIG, %g2; \ srlx %g2, 17, %g2; \ - and %g2, 0x3ff, %g2; \ - sllx %g2, 9, %g2; \ + ba,pt %xcc, 60f; \ + and %g2, 0x3ff, %g2; \ +50: ldxa [%g0] ASI_JBUS_CONFIG, %g2; \ + srlx %g2, 17, %g2; \ + and %g2, 0x1f, %g2; \ +60: sllx %g2, 9, %g2; \ sethi %hi(cheetah_error_log), %g3; \ ldx [%g3 + %lo(cheetah_error_log)], %g3; \ brz,pn %g3, 80f; \ diff -Nru a/arch/sparc64/kernel/head.S b/arch/sparc64/kernel/head.S --- a/arch/sparc64/kernel/head.S Sun Jul 27 10:13:44 2003 +++ b/arch/sparc64/kernel/head.S Sun Jul 27 10:13:44 2003 @@ -66,7 +66,7 @@ sparc_ramdisk_size: .word 0 .xword reboot_command - .xword bootstr_len + .xword bootstr_info .word _end /* We must be careful, 32-bit OpenBOOT will get confused if it @@ -645,11 +645,18 @@ nop not_starfire: + BRANCH_IF_JALAPENO(g1,g5,is_jalapeno) BRANCH_IF_ANY_CHEETAH(g1,g5,is_cheetah) ba,pt %xcc, not_cheetah nop +is_jalapeno: + ldxa [%g0] ASI_JBUS_CONFIG, %g1 + srlx %g1, 17, %g1 + ba,pt %xcc, set_worklist + and %g1, 0x1f, %g1 ! 5bit JBUS ID + is_cheetah: ldxa [%g0] ASI_SAFARI_CONFIG, %g1 srlx %g1, 17, %g1 @@ -740,8 +747,9 @@ .data .align 8 - .globl prom_tba + .globl prom_tba, tlb_type prom_tba: .xword 0 +tlb_type: .word 0 /* Must NOT end up in BSS */ .section ".fixup",#alloc,#execinstr .globl __ret_efault __ret_efault: diff -Nru a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c --- a/arch/sparc64/kernel/irq.c Sun Jul 27 10:13:51 2003 +++ b/arch/sparc64/kernel/irq.c Sun Jul 27 10:13:51 2003 @@ -162,12 +162,24 @@ return; if (tlb_type == cheetah || tlb_type == cheetah_plus) { - /* We set it to our Safari AID. */ - __asm__ __volatile__("ldxa [%%g0] %1, %0" - : "=r" (tid) - : "i" (ASI_SAFARI_CONFIG)); - tid = ((tid & (0x3ffUL<<17)) << 9); - tid &= IMAP_AID_SAFARI; + unsigned long ver; + + __asm__ ("rdpr %%ver, %0" : "=r" (ver)); + if ((ver >> 32) == 0x003e0016) { + /* We set it to our JBUS ID. */ + __asm__ __volatile__("ldxa [%%g0] %1, %0" + : "=r" (tid) + : "i" (ASI_JBUS_CONFIG)); + tid = ((tid & (0x1fUL<<17)) << 9); + tid &= IMAP_TID_JBUS; + } else { + /* We set it to our Safari AID. */ + __asm__ __volatile__("ldxa [%%g0] %1, %0" + : "=r" (tid) + : "i" (ASI_SAFARI_CONFIG)); + tid = ((tid & (0x3ffUL<<17)) << 9); + tid &= IMAP_AID_SAFARI; + } } else if (this_is_starfire == 0) { /* We set it to our UPA MID. */ __asm__ __volatile__("ldxa [%%g0] %1, %0" diff -Nru a/arch/sparc64/kernel/isa.c b/arch/sparc64/kernel/isa.c --- a/arch/sparc64/kernel/isa.c Sun Jul 27 10:13:43 2003 +++ b/arch/sparc64/kernel/isa.c Sun Jul 27 10:13:43 2003 @@ -20,22 +20,23 @@ printk(" [%s", isa_dev->prom_name); } -static void __init isa_dev_get_resource(struct sparc_isa_device *isa_dev) +static void __init isa_dev_get_resource(struct sparc_isa_device *isa_dev, + struct linux_prom_registers *pregs, + int pregs_size) { - struct linux_prom_registers regs[PROMREG_MAX]; unsigned long base, len; int prop_len; prop_len = prom_getproperty(isa_dev->prom_node, "reg", - (char *) regs, sizeof(regs)); + (char *) pregs, pregs_size); if (prop_len <= 0) return; /* Only the first one is interesting. */ - len = regs[0].reg_size; - base = (((unsigned long)regs[0].which_io << 32) | - (unsigned long)regs[0].phys_addr); + len = pregs[0].reg_size; + base = (((unsigned long)pregs[0].which_io << 32) | + (unsigned long)pregs[0].phys_addr); base += isa_dev->bus->parent->io_space.start; isa_dev->resource.start = base; @@ -53,6 +54,9 @@ * * The P1275 standard for ISA devices seems to also have been * totally ignored. + * + * On later systems, an interrupt-map and interrupt-map-mask scheme + * akin to EBUS is used. */ static struct { int obp_irq; @@ -67,33 +71,72 @@ { 0, 0x00 } /* end of table */ }; -static void __init isa_dev_get_irq(struct sparc_isa_device *isa_dev) +static int __init isa_dev_get_irq_using_imap(struct sparc_isa_device *isa_dev, + struct sparc_isa_bridge *isa_br, + int *interrupt, + struct linux_prom_registers *pregs) +{ + unsigned int hi, lo, irq; + int i; + + hi = pregs->which_io & isa_br->isa_intmask.phys_hi; + lo = pregs->phys_addr & isa_br->isa_intmask.phys_lo; + irq = *interrupt & isa_br->isa_intmask.interrupt; + for (i = 0; i < isa_br->num_isa_intmap; i++) { + if ((isa_br->isa_intmap[i].phys_hi == hi) && + (isa_br->isa_intmap[i].phys_lo == lo) && + (isa_br->isa_intmap[i].interrupt == irq)) { + *interrupt = isa_br->isa_intmap[i].cinterrupt; + return 0; + } + } + return -1; +} + +static void __init isa_dev_get_irq(struct sparc_isa_device *isa_dev, + struct linux_prom_registers *pregs) { int irq_prop; irq_prop = prom_getintdefault(isa_dev->prom_node, "interrupts", -1); if (irq_prop <= 0) { - isa_dev->irq = PCI_IRQ_NONE; + goto no_irq; } else { + struct pci_controller_info *pcic; + struct pci_pbm_info *pbm; int i; + if (isa_dev->bus->num_isa_intmap) { + if (!isa_dev_get_irq_using_imap(isa_dev, + isa_dev->bus, + &irq_prop, + pregs)) + goto route_irq; + } + for (i = 0; grover_irq_table[i].obp_irq != 0; i++) { if (grover_irq_table[i].obp_irq == irq_prop) { - struct pci_controller_info *pcic; - struct pci_pbm_info *pbm; int ino = grover_irq_table[i].pci_ino; - if (ino == 0) { - isa_dev->irq = PCI_IRQ_NONE; - } else { - pbm = isa_dev->bus->parent; - pcic = pbm->parent; - isa_dev->irq = pcic->irq_build(pbm, NULL, ino); - } + if (ino == 0) + goto no_irq; + + irq_prop = ino; + goto route_irq; } } + goto no_irq; + +route_irq: + pbm = isa_dev->bus->parent; + pcic = pbm->parent; + isa_dev->irq = pcic->irq_build(pbm, NULL, irq_prop); + return; } + +no_irq: + isa_dev->irq = PCI_IRQ_NONE; } static void __init isa_fill_children(struct sparc_isa_device *parent_isa_dev) @@ -105,6 +148,7 @@ printk(" ->"); while (node != 0) { + struct linux_prom_registers regs[PROMREG_MAX]; struct sparc_isa_device *isa_dev; int prop_len; @@ -138,8 +182,8 @@ if (prop_len <= 0) isa_dev->compatible[0] = '\0'; - isa_dev_get_resource(isa_dev); - isa_dev_get_irq(isa_dev); + isa_dev_get_resource(isa_dev, regs, sizeof(regs)); + isa_dev_get_irq(isa_dev, regs); report_dev(isa_dev, 1); @@ -152,6 +196,7 @@ int node = prom_getchild(isa_br->prom_node); while (node != 0) { + struct linux_prom_registers regs[PROMREG_MAX]; struct sparc_isa_device *isa_dev; int prop_len; @@ -194,8 +239,8 @@ if (prop_len <= 0) isa_dev->compatible[0] = '\0'; - isa_dev_get_resource(isa_dev); - isa_dev_get_irq(isa_dev); + isa_dev_get_resource(isa_dev, regs, sizeof(regs)); + isa_dev_get_irq(isa_dev, regs); report_dev(isa_dev, 0); @@ -259,6 +304,21 @@ else isa_br->num_isa_ranges = (prop_len / sizeof(struct linux_prom_isa_ranges)); + + prop_len = prom_getproperty(isa_br->prom_node, + "interrupt-map", + (char *) isa_br->isa_intmap, + sizeof(isa_br->isa_intmap)); + if (prop_len <= 0) + isa_br->num_isa_intmap = 0; + else + isa_br->num_isa_intmap = + (prop_len / sizeof(struct linux_prom_isa_intmap)); + + prop_len = prom_getproperty(isa_br->prom_node, + "interrupt-map-mask", + (char *) &(isa_br->isa_intmask), + sizeof(isa_br->isa_intmask)); printk("isa%d:", isa_br->index); diff -Nru a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c --- a/arch/sparc64/kernel/pci.c Sun Jul 27 10:13:39 2003 +++ b/arch/sparc64/kernel/pci.c Sun Jul 27 10:13:39 2003 @@ -46,26 +46,6 @@ /* Each PCI controller found gets a unique index. */ int pci_num_controllers = 0; -/* Given an 8-bit PCI bus number, this yields the - * controlling PBM module info. - * - * Some explanation is in order here. The Linux APIs for - * the PCI subsystem require that the configuration space - * types are enough to signify PCI configuration space - * accesses correctly. This gives us 8-bits for the bus - * number, however we have multiple PCI controllers on - * UltraSparc systems. - * - * So what we do is give the PCI busses under each controller - * a unique portion of the 8-bit PCI bus number space. - * Therefore one can obtain the controller from the bus - * number. For example, say PSYCHO PBM-A a subordinate bus - * space of 0 to 4, and PBM-B has a space of 0 to 2. PBM-A - * will use 0 to 4, and PBM-B will use 5 to 7. - */ -struct pci_pbm_info *pci_bus2pbm[256]; -unsigned char pci_highest_busnum = 0; - /* At boot time the user can give the kernel a command * line option which controls if and how PCI devices * are reordered at PCI bus probing time. @@ -205,6 +185,8 @@ extern void sabre_init(int, char *); extern void psycho_init(int, char *); extern void schizo_init(int, char *); +extern void schizo_plus_init(int, char *); +extern void tomatillo_init(int, char *); static struct { char *model_name; @@ -216,12 +198,16 @@ { "SUNW,psycho", psycho_init }, { "pci108e,8000", psycho_init }, { "SUNW,schizo", schizo_init }, - { "pci108e,8001", schizo_init } + { "pci108e,8001", schizo_init }, + { "SUNW,schizo+", schizo_plus_init }, + { "pci108e,8002", schizo_plus_init }, + { "SUNW,tomatillo", tomatillo_init }, + { "pci108e,a801", tomatillo_init }, }; #define PCI_NUM_CONTROLLER_TYPES (sizeof(pci_controller_table) / \ sizeof(pci_controller_table[0])) -static void pci_controller_init(char *model_name, int namelen, int node) +static int pci_controller_init(char *model_name, int namelen, int node) { int i; @@ -230,12 +216,14 @@ pci_controller_table[i].model_name, namelen)) { pci_controller_table[i].init(node, model_name); - return; + return 1; } } printk("PCI: Warning unknown controller, model name [%s]\n", model_name); printk("PCI: Ignoring controller...\n"); + + return 0; } static int pci_is_controller(char *model_name, int namelen, int node) @@ -252,37 +240,47 @@ return 0; } -/* Is there some PCI controller in the system? */ -int pcic_present(void) + +static int pci_controller_scan(int (*handler)(char *, int, int)) { - char namebuf[16]; + char namebuf[64]; int node; + int count = 0; node = prom_getchild(prom_root_node); while ((node = prom_searchsiblings(node, "pci")) != 0) { - int len, ret; + int len; - len = prom_getproperty(node, "model", - namebuf, sizeof(namebuf)); + if ((len = prom_getproperty(node, "model", namebuf, sizeof(namebuf))) > 0 || + (len = prom_getproperty(node, "compatible", namebuf, sizeof(namebuf))) > 0) { + int item_len = 0; + + /* Our value may be a multi-valued string in the + * case of some compatible properties. For sanity, + * only try the first one. */ + + while (namebuf[item_len] && len) { + len--; + item_len++; + } - ret = 0; - if (len > 0) { - ret = pci_is_controller(namebuf, len, node); - } else { - len = prom_getproperty(node, "compatible", - namebuf, sizeof(namebuf)); - if (len > 0) - ret = pci_is_controller(namebuf, len, node); + if (handler(namebuf, item_len, node)) + count++; } - if (ret) - return ret; node = prom_getsibling(node); if (!node) break; } - return 0; + return count; +} + + +/* Is there some PCI controller in the system? */ +int pcic_present(void) +{ + return pci_controller_scan(pci_is_controller); } /* Find each controller in the system, attach and initialize @@ -292,28 +290,9 @@ */ static void pci_controller_probe(void) { - char namebuf[16]; - int node; - printk("PCI: Probing for controllers.\n"); - node = prom_getchild(prom_root_node); - while ((node = prom_searchsiblings(node, "pci")) != 0) { - int len; - len = prom_getproperty(node, "model", - namebuf, sizeof(namebuf)); - if (len > 0) - pci_controller_init(namebuf, len, node); - else { - len = prom_getproperty(node, "compatible", - namebuf, sizeof(namebuf)); - if (len > 0) - pci_controller_init(namebuf, len, node); - } - node = prom_getsibling(node); - if (!node) - break; - } + pci_controller_scan(pci_controller_init); } static void pci_scan_each_controller_bus(void) @@ -387,10 +366,9 @@ pbus->resource[1] = &pbm->mem_space; } -/* NOTE: This can get called before we've fixed up pdev->sysdata. */ int pci_claim_resource(struct pci_dev *pdev, int resource) { - struct pci_pbm_info *pbm = pci_bus2pbm[pdev->bus->number]; + struct pci_pbm_info *pbm = pdev->bus->sysdata; struct resource *res = &pdev->resource[resource]; struct resource *root; @@ -535,7 +513,7 @@ void pcibios_resource_to_bus(struct pci_dev *pdev, struct pci_bus_region *region, struct resource *res) { - struct pci_pbm_info *pbm = pci_bus2pbm[pdev->bus->number]; + struct pci_pbm_info *pbm = pdev->bus->sysdata; struct resource zero_res, *root; zero_res.start = 0; @@ -556,7 +534,7 @@ void pcibios_bus_to_resource(struct pci_dev *pdev, struct resource *res, struct pci_bus_region *region) { - struct pci_pbm_info *pbm = pci_bus2pbm[pdev->bus->number]; + struct pci_pbm_info *pbm = pdev->bus->sysdata; struct resource *root; res->start = region->start; @@ -804,28 +782,29 @@ /* Return the domain nuber for this pci bus */ -int pci_domain_nr(struct pci_bus *bus) +int pci_domain_nr(struct pci_bus *pbus) { - struct pcidev_cookie *cookie = bus->sysdata; + struct pci_pbm_info *pbm = pbus->sysdata; int ret; - if (cookie != NULL) { - struct pci_pbm_info *pbm = cookie->pbm; - if (pbm == NULL || pbm->parent == NULL) { - ret = -ENXIO; - } else { - struct pci_controller_info *p = pbm->parent; - - ret = p->index; - if (p->pbms_same_domain == 0) - ret = ((ret << 1) + - ((pbm == &pbm->parent->pbm_B) ? 1 : 0)); - } - } else { + if (pbm == NULL || pbm->parent == NULL) { ret = -ENXIO; + } else { + struct pci_controller_info *p = pbm->parent; + + ret = p->index; + if (p->pbms_same_domain == 0) + ret = ((ret << 1) + + ((pbm == &pbm->parent->pbm_B) ? 1 : 0)); } return ret; +} + +int pci_name_bus(char *name, struct pci_bus *bus) +{ + sprintf(name, "%04x:%02x", pci_domain_nr(bus), bus->number); + return 0; } int pcibios_prep_mwi(struct pci_dev *dev) diff -Nru a/arch/sparc64/kernel/pci_common.c b/arch/sparc64/kernel/pci_common.c --- a/arch/sparc64/kernel/pci_common.c Sun Jul 27 10:13:42 2003 +++ b/arch/sparc64/kernel/pci_common.c Sun Jul 27 10:13:42 2003 @@ -54,6 +54,7 @@ (pdev->vendor == PCI_VENDOR_ID_SUN) && (pdev->device == PCI_DEVICE_ID_SUN_PBM || pdev->device == PCI_DEVICE_ID_SUN_SCHIZO || + pdev->device == PCI_DEVICE_ID_SUN_TOMATILLO || pdev->device == PCI_DEVICE_ID_SUN_SABRE || pdev->device == PCI_DEVICE_ID_SUN_HUMMINGBIRD)) { *nregs = 0; @@ -685,7 +686,7 @@ struct pcidev_cookie *pcp = pdev->sysdata; struct pci_pbm_info *pbm = pcp->pbm; struct pci_controller_info *p = pbm->parent; - unsigned int portid = p->portid; + unsigned int portid = pbm->portid; unsigned int prom_irq; int prom_node = pcp->prom_node; int err; diff -Nru a/arch/sparc64/kernel/pci_impl.h b/arch/sparc64/kernel/pci_impl.h --- a/arch/sparc64/kernel/pci_impl.h Sun Jul 27 10:13:46 2003 +++ b/arch/sparc64/kernel/pci_impl.h Sun Jul 27 10:13:46 2003 @@ -14,8 +14,6 @@ extern spinlock_t pci_controller_lock; extern struct pci_controller_info *pci_controller_root; -extern struct pci_pbm_info *pci_bus2pbm[256]; -extern unsigned char pci_highest_busnum; extern int pci_num_controllers; /* PCI bus scanning and fixup support. */ diff -Nru a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c --- a/arch/sparc64/kernel/pci_psycho.c Sun Jul 27 10:13:47 2003 +++ b/arch/sparc64/kernel/pci_psycho.c Sun Jul 27 10:13:47 2003 @@ -111,7 +111,7 @@ static int psycho_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, int where, int size, u32 *value) { - struct pci_pbm_info *pbm = pci_bus2pbm[bus_dev->number]; + struct pci_pbm_info *pbm = bus_dev->sysdata; unsigned char bus = bus_dev->number; u32 *addr; u16 tmp16; @@ -166,7 +166,7 @@ static int psycho_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, int where, int size, u32 value) { - struct pci_pbm_info *pbm = pci_bus2pbm[bus_dev->number]; + struct pci_pbm_info *pbm = bus_dev->sysdata; unsigned char bus = bus_dev->number; u32 *addr; @@ -348,7 +348,6 @@ struct pci_dev *pdev, unsigned int ino) { - struct pci_controller_info *p = pbm->parent; struct ino_bucket *bucket; unsigned long imap, iclr; unsigned long imap_off, iclr_off; @@ -373,11 +372,11 @@ if (PIL_RESERVED(pil)) BUG(); - imap = p->controller_regs + imap_off; + imap = pbm->controller_regs + imap_off; imap += 4; iclr_off = psycho_iclr_offset(ino); - iclr = p->controller_regs + iclr_off; + iclr = pbm->controller_regs + iclr_off; iclr += 4; if ((ino & 0x20) == 0) @@ -444,7 +443,7 @@ int is_pbm_a) { struct pci_strbuf *strbuf = &pbm->stc; - unsigned long regbase = p->controller_regs; + unsigned long regbase = p->pbm_A.controller_regs; unsigned long err_base, tag_base, line_base; u64 control; int i; @@ -639,7 +638,7 @@ psycho_write(iommu->iommu_control, control | PSYCHO_IOMMU_CTRL_DENAB); for (i = 0; i < 16; i++) { - unsigned long base = p->controller_regs; + unsigned long base = p->pbm_A.controller_regs; iommu_tag[i] = psycho_read(base + PSYCHO_IOMMU_TAG + (i * 8UL)); @@ -716,8 +715,8 @@ static irqreturn_t psycho_ue_intr(int irq, void *dev_id, struct pt_regs *regs) { struct pci_controller_info *p = dev_id; - unsigned long afsr_reg = p->controller_regs + PSYCHO_UE_AFSR; - unsigned long afar_reg = p->controller_regs + PSYCHO_UE_AFAR; + unsigned long afsr_reg = p->pbm_A.controller_regs + PSYCHO_UE_AFSR; + unsigned long afar_reg = p->pbm_A.controller_regs + PSYCHO_UE_AFAR; unsigned long afsr, afar, error_bits; int reported; @@ -793,8 +792,8 @@ static irqreturn_t psycho_ce_intr(int irq, void *dev_id, struct pt_regs *regs) { struct pci_controller_info *p = dev_id; - unsigned long afsr_reg = p->controller_regs + PSYCHO_CE_AFSR; - unsigned long afar_reg = p->controller_regs + PSYCHO_CE_AFAR; + unsigned long afsr_reg = p->pbm_A.controller_regs + PSYCHO_CE_AFSR; + unsigned long afar_reg = p->pbm_A.controller_regs + PSYCHO_CE_AFAR; unsigned long afsr, afar, error_bits; int reported; @@ -885,11 +884,11 @@ is_pbm_a = (pbm == &pbm->parent->pbm_A); if (is_pbm_a) { - afsr_reg = p->controller_regs + PSYCHO_PCI_AFSR_A; - afar_reg = p->controller_regs + PSYCHO_PCI_AFAR_A; + afsr_reg = p->pbm_A.controller_regs + PSYCHO_PCI_AFSR_A; + afar_reg = p->pbm_A.controller_regs + PSYCHO_PCI_AFAR_A; } else { - afsr_reg = p->controller_regs + PSYCHO_PCI_AFSR_B; - afar_reg = p->controller_regs + PSYCHO_PCI_AFAR_B; + afsr_reg = p->pbm_A.controller_regs + PSYCHO_PCI_AFSR_B; + afar_reg = p->pbm_A.controller_regs + PSYCHO_PCI_AFAR_B; } /* Latch error status. */ @@ -988,8 +987,8 @@ static void __init psycho_register_error_handlers(struct pci_controller_info *p) { struct pci_pbm_info *pbm = &p->pbm_A; /* arbitrary */ - unsigned long base = p->controller_regs; - unsigned int irq, portid = p->portid; + unsigned long base = p->pbm_A.controller_regs; + unsigned int irq, portid = pbm->portid; u64 tmp; /* Build IRQs and register handlers. */ @@ -1103,107 +1102,6 @@ pci_write_config_dword(pdev, where + 4, 0); } -/* We have to do the config space accesses by hand, thus... */ -#define PBM_BRIDGE_BUS 0x40 -#define PBM_BRIDGE_SUBORDINATE 0x41 -static void __init pbm_renumber(struct pci_pbm_info *pbm, u8 orig_busno) -{ - u8 *addr, busno; - int nbus; - - busno = pci_highest_busnum; - nbus = pbm->pci_last_busno - pbm->pci_first_busno; - - addr = psycho_pci_config_mkaddr(pbm, orig_busno, - 0, PBM_BRIDGE_BUS); - pci_config_write8(addr, busno); - addr = psycho_pci_config_mkaddr(pbm, busno, - 0, PBM_BRIDGE_SUBORDINATE); - pci_config_write8(addr, busno + nbus); - - pbm->pci_first_busno = busno; - pbm->pci_last_busno = busno + nbus; - pci_highest_busnum = busno + nbus + 1; - - do { - pci_bus2pbm[busno++] = pbm; - } while (nbus--); -} - -/* We have to do the config space accesses by hand here since - * the pci_bus2pbm array is not ready yet. - */ -static void __init pbm_pci_bridge_renumber(struct pci_pbm_info *pbm, - u8 busno) -{ - u32 devfn, l, class; - u8 hdr_type; - int is_multi = 0; - - for(devfn = 0; devfn < 0xff; ++devfn) { - u32 *dwaddr; - u8 *baddr; - - if (PCI_FUNC(devfn) != 0 && is_multi == 0) - continue; - - /* Anything there? */ - dwaddr = psycho_pci_config_mkaddr(pbm, busno, devfn, PCI_VENDOR_ID); - l = 0xffffffff; - pci_config_read32(dwaddr, &l); - if (l == 0xffffffff || l == 0x00000000 || - l == 0x0000ffff || l == 0xffff0000) { - is_multi = 0; - continue; - } - - baddr = psycho_pci_config_mkaddr(pbm, busno, devfn, PCI_HEADER_TYPE); - pci_config_read8(baddr, &hdr_type); - if (PCI_FUNC(devfn) == 0) - is_multi = hdr_type & 0x80; - - dwaddr = psycho_pci_config_mkaddr(pbm, busno, devfn, PCI_CLASS_REVISION); - class = 0xffffffff; - pci_config_read32(dwaddr, &class); - if ((class >> 16) == PCI_CLASS_BRIDGE_PCI) { - u32 buses = 0xffffffff; - - dwaddr = psycho_pci_config_mkaddr(pbm, busno, devfn, - PCI_PRIMARY_BUS); - pci_config_read32(dwaddr, &buses); - pbm_pci_bridge_renumber(pbm, (buses >> 8) & 0xff); - buses &= 0xff000000; - pci_config_write32(dwaddr, buses); - } - } -} - -static void __init pbm_bridge_reconfigure(struct pci_controller_info *p) -{ - struct pci_pbm_info *pbm; - u8 *addr; - - /* Clear out primary/secondary/subordinate bus numbers on - * all PCI-to-PCI bridges under each PBM. The generic bus - * probing will fix them up. - */ - pbm_pci_bridge_renumber(&p->pbm_B, p->pbm_B.pci_first_busno); - pbm_pci_bridge_renumber(&p->pbm_A, p->pbm_A.pci_first_busno); - - /* Move PBM A out of the way. */ - pbm = &p->pbm_A; - addr = psycho_pci_config_mkaddr(pbm, pbm->pci_first_busno, - 0, PBM_BRIDGE_BUS); - pci_config_write8(addr, 0xff); - addr = psycho_pci_config_mkaddr(pbm, 0xff, - 0, PBM_BRIDGE_SUBORDINATE); - pci_config_write8(addr, 0xff); - - /* Now we can safely renumber both PBMs. */ - pbm_renumber(&p->pbm_B, p->pbm_B.pci_first_busno); - pbm_renumber(&p->pbm_A, 0xff); -} - static void __init pbm_config_busmastering(struct pci_pbm_info *pbm) { u8 *addr; @@ -1251,7 +1149,6 @@ static void __init psycho_scan_bus(struct pci_controller_info *p) { - pbm_bridge_reconfigure(p); pbm_config_busmastering(&p->pbm_B); p->pbm_B.is_66mhz_capable = 0; pbm_config_busmastering(&p->pbm_A); @@ -1276,26 +1173,26 @@ iommu->iommu_cur_ctx = 0; /* Register addresses. */ - iommu->iommu_control = p->controller_regs + PSYCHO_IOMMU_CONTROL; - iommu->iommu_tsbbase = p->controller_regs + PSYCHO_IOMMU_TSBBASE; - iommu->iommu_flush = p->controller_regs + PSYCHO_IOMMU_FLUSH; + iommu->iommu_control = p->pbm_A.controller_regs + PSYCHO_IOMMU_CONTROL; + iommu->iommu_tsbbase = p->pbm_A.controller_regs + PSYCHO_IOMMU_TSBBASE; + iommu->iommu_flush = p->pbm_A.controller_regs + PSYCHO_IOMMU_FLUSH; /* PSYCHO's IOMMU lacks ctx flushing. */ iommu->iommu_ctxflush = 0; /* We use the main control register of PSYCHO as the write * completion register. */ - iommu->write_complete_reg = p->controller_regs + PSYCHO_CONTROL; + iommu->write_complete_reg = p->pbm_A.controller_regs + PSYCHO_CONTROL; /* * Invalidate TLB Entries. */ - control = psycho_read(p->controller_regs + PSYCHO_IOMMU_CONTROL); + control = psycho_read(p->pbm_A.controller_regs + PSYCHO_IOMMU_CONTROL); control |= PSYCHO_IOMMU_CTRL_DENAB; - psycho_write(p->controller_regs + PSYCHO_IOMMU_CONTROL, control); + psycho_write(p->pbm_A.controller_regs + PSYCHO_IOMMU_CONTROL, control); for(i = 0; i < 16; i++) { - psycho_write(p->controller_regs + PSYCHO_IOMMU_TAG + (i * 8UL), 0); - psycho_write(p->controller_regs + PSYCHO_IOMMU_DATA + (i * 8UL), 0); + psycho_write(p->pbm_A.controller_regs + PSYCHO_IOMMU_TAG + (i * 8UL), 0); + psycho_write(p->pbm_A.controller_regs + PSYCHO_IOMMU_DATA + (i * 8UL), 0); } /* Leave diag mode enabled for full-flushing done @@ -1326,16 +1223,16 @@ iommu->alloc_info[i].next = 0; } - psycho_write(p->controller_regs + PSYCHO_IOMMU_TSBBASE, __pa(tsbbase)); + psycho_write(p->pbm_A.controller_regs + PSYCHO_IOMMU_TSBBASE, __pa(tsbbase)); - control = psycho_read(p->controller_regs + PSYCHO_IOMMU_CONTROL); + control = psycho_read(p->pbm_A.controller_regs + PSYCHO_IOMMU_CONTROL); control &= ~(PSYCHO_IOMMU_CTRL_TSBSZ | PSYCHO_IOMMU_CTRL_TBWSZ); control |= (PSYCHO_IOMMU_TSBSZ_128K | PSYCHO_IOMMU_CTRL_ENAB); - psycho_write(p->controller_regs + PSYCHO_IOMMU_CONTROL, control); + psycho_write(p->pbm_A.controller_regs + PSYCHO_IOMMU_CONTROL, control); /* If necessary, hook us up for starfire IRQ translations. */ if(this_is_starfire) - p->starfire_cookie = starfire_hookup(p->portid); + p->starfire_cookie = starfire_hookup(p->pbm_A.portid); else p->starfire_cookie = NULL; } @@ -1357,28 +1254,28 @@ u64 tmp; /* PROM sets the IRQ retry value too low, increase it. */ - psycho_write(p->controller_regs + PSYCHO_IRQ_RETRY, 0xff); + psycho_write(p->pbm_A.controller_regs + PSYCHO_IRQ_RETRY, 0xff); /* Enable arbiter for all PCI slots. */ - tmp = psycho_read(p->controller_regs + PSYCHO_PCIA_CTRL); + tmp = psycho_read(p->pbm_A.controller_regs + PSYCHO_PCIA_CTRL); tmp |= PSYCHO_PCICTRL_AEN; - psycho_write(p->controller_regs + PSYCHO_PCIA_CTRL, tmp); + psycho_write(p->pbm_A.controller_regs + PSYCHO_PCIA_CTRL, tmp); - tmp = psycho_read(p->controller_regs + PSYCHO_PCIB_CTRL); + tmp = psycho_read(p->pbm_A.controller_regs + PSYCHO_PCIB_CTRL); tmp |= PSYCHO_PCICTRL_AEN; - psycho_write(p->controller_regs + PSYCHO_PCIB_CTRL, tmp); + psycho_write(p->pbm_A.controller_regs + PSYCHO_PCIB_CTRL, tmp); /* Disable DMA write / PIO read synchronization on * both PCI bus segments. * [ U2P Erratum 1243770, STP2223BGA data sheet ] */ - tmp = psycho_read(p->controller_regs + PSYCHO_PCIA_DIAG); + tmp = psycho_read(p->pbm_A.controller_regs + PSYCHO_PCIA_DIAG); tmp |= PSYCHO_PCIDIAG_DDWSYNC; - psycho_write(p->controller_regs + PSYCHO_PCIA_DIAG, tmp); + psycho_write(p->pbm_A.controller_regs + PSYCHO_PCIA_DIAG, tmp); - tmp = psycho_read(p->controller_regs + PSYCHO_PCIB_DIAG); + tmp = psycho_read(p->pbm_A.controller_regs + PSYCHO_PCIB_DIAG); tmp |= PSYCHO_PCIDIAG_DDWSYNC; - psycho_write(p->controller_regs + PSYCHO_PCIB_DIAG, tmp); + psycho_write(p->pbm_A.controller_regs + PSYCHO_PCIB_DIAG, tmp); } static void __init pbm_register_toplevel_resources(struct pci_controller_info *p, @@ -1401,7 +1298,7 @@ struct pci_pbm_info *pbm, int is_pbm_a) { - unsigned long base = p->controller_regs; + unsigned long base = pbm->controller_regs; u64 control; if (is_pbm_a) { @@ -1466,14 +1363,21 @@ if (is_pbm_a) { pbm = &p->pbm_A; pbm->pci_first_slot = 1; - pbm->io_space.start = p->controller_regs + PSYCHO_IOSPACE_A; - pbm->mem_space.start = p->controller_regs + PSYCHO_MEMSPACE_A; + pbm->io_space.start = pbm->controller_regs + PSYCHO_IOSPACE_A; + pbm->mem_space.start = pbm->controller_regs + PSYCHO_MEMSPACE_A; } else { pbm = &p->pbm_B; pbm->pci_first_slot = 2; - pbm->io_space.start = p->controller_regs + PSYCHO_IOSPACE_B; - pbm->mem_space.start = p->controller_regs + PSYCHO_MEMSPACE_B; + pbm->io_space.start = pbm->controller_regs + PSYCHO_IOSPACE_B; + pbm->mem_space.start = pbm->controller_regs + PSYCHO_MEMSPACE_B; } + + pbm->chip_type = PBM_CHIP_TYPE_PSYCHO; + pbm->chip_version = + prom_getintdefault(prom_node, "version#", 0); + pbm->chip_revision = + prom_getintdefault(prom_node, "module-revision#", 0); + pbm->io_space.end = pbm->io_space.start + PSYCHO_IOSPACE_SIZE; pbm->io_space.flags = IORESOURCE_IO; pbm->mem_space.end = pbm->mem_space.start + PSYCHO_MEMSPACE_SIZE; @@ -1541,7 +1445,7 @@ spin_lock_irqsave(&pci_controller_lock, flags); for(p = pci_controller_root; p; p = p->next) { - if (p->portid == upa_portid) { + if (p->pbm_A.portid == upa_portid) { spin_unlock_irqrestore(&pci_controller_lock, flags); is_pbm_a = (p->pbm_A.prom_node == 0); psycho_pbm_init(p, node, is_pbm_a); @@ -1569,7 +1473,8 @@ pci_controller_root = p; spin_unlock_irqrestore(&pci_controller_lock, flags); - p->portid = upa_portid; + p->pbm_A.portid = upa_portid; + p->pbm_B.portid = upa_portid; p->index = pci_num_controllers++; p->pbms_same_domain = 0; p->scan_bus = psycho_scan_bus; @@ -1586,9 +1491,10 @@ prom_halt(); } - p->controller_regs = pr_regs[2].phys_addr; + p->pbm_A.controller_regs = pr_regs[2].phys_addr; + p->pbm_B.controller_regs = pr_regs[2].phys_addr; printk("PCI: Found PSYCHO, control regs at %016lx\n", - p->controller_regs); + p->pbm_A.controller_regs); p->pbm_A.config_space = p->pbm_B.config_space = (pr_regs[2].phys_addr + PSYCHO_CONFIGSPACE); diff -Nru a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c --- a/arch/sparc64/kernel/pci_sabre.c Sun Jul 27 10:13:52 2003 +++ b/arch/sparc64/kernel/pci_sabre.c Sun Jul 27 10:13:52 2003 @@ -262,7 +262,7 @@ static int __sabre_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, int where, int size, u32 *value) { - struct pci_pbm_info *pbm = pci_bus2pbm[bus_dev->number]; + struct pci_pbm_info *pbm = bus_dev->sysdata; unsigned char bus = bus_dev->number; u32 *addr; u16 tmp16; @@ -388,7 +388,7 @@ static int __sabre_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, int where, int size, u32 value) { - struct pci_pbm_info *pbm = pci_bus2pbm[bus_dev->number]; + struct pci_pbm_info *pbm = bus_dev->sysdata; unsigned char bus = bus_dev->number; u32 *addr; @@ -591,7 +591,6 @@ struct pci_dev *pdev, unsigned int ino) { - struct pci_controller_info *p = pbm->parent; struct ino_bucket *bucket; unsigned long imap, iclr; unsigned long imap_off, iclr_off; @@ -616,11 +615,11 @@ if (PIL_RESERVED(pil)) BUG(); - imap = p->controller_regs + imap_off; + imap = pbm->controller_regs + imap_off; imap += 4; iclr_off = sabre_iclr_offset(ino); - iclr = p->controller_regs + iclr_off; + iclr = pbm->controller_regs + iclr_off; iclr += 4; if ((ino & 0x20) == 0) @@ -698,7 +697,7 @@ sabre_write(iommu->iommu_control, (control | SABRE_IOMMUCTRL_DENAB)); for (i = 0; i < 16; i++) { - unsigned long base = p->controller_regs; + unsigned long base = p->pbm_A.controller_regs; iommu_tag[i] = sabre_read(base + SABRE_IOMMU_TAG + (i * 8UL)); @@ -747,8 +746,8 @@ static irqreturn_t sabre_ue_intr(int irq, void *dev_id, struct pt_regs *regs) { struct pci_controller_info *p = dev_id; - unsigned long afsr_reg = p->controller_regs + SABRE_UE_AFSR; - unsigned long afar_reg = p->controller_regs + SABRE_UECE_AFAR; + unsigned long afsr_reg = p->pbm_A.controller_regs + SABRE_UE_AFSR; + unsigned long afar_reg = p->pbm_A.controller_regs + SABRE_UECE_AFAR; unsigned long afsr, afar, error_bits; int reported; @@ -807,8 +806,8 @@ static irqreturn_t sabre_ce_intr(int irq, void *dev_id, struct pt_regs *regs) { struct pci_controller_info *p = dev_id; - unsigned long afsr_reg = p->controller_regs + SABRE_CE_AFSR; - unsigned long afar_reg = p->controller_regs + SABRE_UECE_AFAR; + unsigned long afsr_reg = p->pbm_A.controller_regs + SABRE_CE_AFSR; + unsigned long afar_reg = p->pbm_A.controller_regs + SABRE_UECE_AFAR; unsigned long afsr, afar, error_bits; int reported; @@ -867,8 +866,8 @@ unsigned long afsr, afar, error_bits; int reported; - afsr_reg = p->controller_regs + SABRE_PIOAFSR; - afar_reg = p->controller_regs + SABRE_PIOAFAR; + afsr_reg = p->pbm_A.controller_regs + SABRE_PIOAFSR; + afar_reg = p->pbm_A.controller_regs + SABRE_PIOAFAR; /* Latch error status. */ afar = sabre_read(afar_reg); @@ -962,8 +961,8 @@ static void __init sabre_register_error_handlers(struct pci_controller_info *p) { struct pci_pbm_info *pbm = &p->pbm_A; /* arbitrary */ - unsigned long base = p->controller_regs; - unsigned long irq, portid = p->portid; + unsigned long base = pbm->controller_regs; + unsigned long irq, portid = pbm->portid; u64 tmp; /* We clear the error bits in the appropriate AFSR before @@ -1010,14 +1009,13 @@ struct resource *res, struct resource *root) { - struct pci_pbm_info *pbm = pci_bus2pbm[pdev->bus->number]; - struct pci_controller_info *p = pbm->parent; + struct pci_pbm_info *pbm = pdev->bus->sysdata; unsigned long base; if (res->flags & IORESOURCE_IO) - base = p->controller_regs + SABRE_IOSPACE; + base = pbm->controller_regs + SABRE_IOSPACE; else - base = p->controller_regs + SABRE_MEMSPACE; + base = pbm->controller_regs + SABRE_MEMSPACE; res->start += base; res->end += base; @@ -1027,7 +1025,6 @@ { struct pcidev_cookie *pcp = pdev->sysdata; struct pci_pbm_info *pbm = pcp->pbm; - struct pci_controller_info *p = pbm->parent; struct resource *res; unsigned long base; u32 reg; @@ -1045,9 +1042,9 @@ is_64bit = 0; if (res->flags & IORESOURCE_IO) - base = p->controller_regs + SABRE_IOSPACE; + base = pbm->controller_regs + SABRE_IOSPACE; else { - base = p->controller_regs + SABRE_MEMSPACE; + base = pbm->controller_regs + SABRE_MEMSPACE; if ((res->flags & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == PCI_BASE_ADDRESS_MEM_TYPE_64) is_64bit = 1; @@ -1150,11 +1147,8 @@ p->pbm_A.is_66mhz_capable = 0; p->pbm_B.is_66mhz_capable = 0; - /* Unlike for PSYCHO, we can only have one SABRE - * in a system. Having multiple SABREs is thus - * and error, and as a consequence we do not need - * to do any bus renumbering but we do have to have - * the pci_bus2pbm array setup properly. + /* This driver has not been verified to handle + * multiple SABREs yet, so trap this. * * Also note that the SABRE host bridge is hardwired * to live at bus 0. @@ -1167,7 +1161,6 @@ cookie = alloc_bridge_cookie(&p->pbm_A); - /* The pci_bus2pbm table has already been setup in sabre_init. */ sabre_bus = pci_scan_bus(p->pci_first_busno, p->pci_ops, &p->pbm_A); @@ -1233,21 +1226,21 @@ iommu->iommu_cur_ctx = 0; /* Register addresses. */ - iommu->iommu_control = p->controller_regs + SABRE_IOMMU_CONTROL; - iommu->iommu_tsbbase = p->controller_regs + SABRE_IOMMU_TSBBASE; - iommu->iommu_flush = p->controller_regs + SABRE_IOMMU_FLUSH; - iommu->write_complete_reg = p->controller_regs + SABRE_WRSYNC; + iommu->iommu_control = p->pbm_A.controller_regs + SABRE_IOMMU_CONTROL; + iommu->iommu_tsbbase = p->pbm_A.controller_regs + SABRE_IOMMU_TSBBASE; + iommu->iommu_flush = p->pbm_A.controller_regs + SABRE_IOMMU_FLUSH; + iommu->write_complete_reg = p->pbm_A.controller_regs + SABRE_WRSYNC; /* Sabre's IOMMU lacks ctx flushing. */ iommu->iommu_ctxflush = 0; /* Invalidate TLB Entries. */ - control = sabre_read(p->controller_regs + SABRE_IOMMU_CONTROL); + control = sabre_read(p->pbm_A.controller_regs + SABRE_IOMMU_CONTROL); control |= SABRE_IOMMUCTRL_DENAB; - sabre_write(p->controller_regs + SABRE_IOMMU_CONTROL, control); + sabre_write(p->pbm_A.controller_regs + SABRE_IOMMU_CONTROL, control); for(i = 0; i < 16; i++) { - sabre_write(p->controller_regs + SABRE_IOMMU_TAG + (i * 8UL), 0); - sabre_write(p->controller_regs + SABRE_IOMMU_DATA + (i * 8UL), 0); + sabre_write(p->pbm_A.controller_regs + SABRE_IOMMU_TAG + (i * 8UL), 0); + sabre_write(p->pbm_A.controller_regs + SABRE_IOMMU_DATA + (i * 8UL), 0); } /* Leave diag mode enabled for full-flushing done @@ -1264,9 +1257,9 @@ iommu->dma_addr_mask = dma_mask; memset((char *)tsbbase, 0, PAGE_SIZE << order); - sabre_write(p->controller_regs + SABRE_IOMMU_TSBBASE, __pa(tsbbase)); + sabre_write(p->pbm_A.controller_regs + SABRE_IOMMU_TSBBASE, __pa(tsbbase)); - control = sabre_read(p->controller_regs + SABRE_IOMMU_CONTROL); + control = sabre_read(p->pbm_A.controller_regs + SABRE_IOMMU_CONTROL); control &= ~(SABRE_IOMMUCTRL_TSBSZ | SABRE_IOMMUCTRL_TBWSZ); control |= SABRE_IOMMUCTRL_ENAB; switch(tsbsize) { @@ -1283,7 +1276,7 @@ prom_halt(); break; } - sabre_write(p->controller_regs + SABRE_IOMMU_CONTROL, control); + sabre_write(p->pbm_A.controller_regs + SABRE_IOMMU_CONTROL, control); /* We start with no consistent mappings. */ iommu->lowest_consistent_map = @@ -1299,8 +1292,8 @@ struct pci_pbm_info *pbm) { char *name = pbm->name; - unsigned long ibase = p->controller_regs + SABRE_IOSPACE; - unsigned long mbase = p->controller_regs + SABRE_MEMSPACE; + unsigned long ibase = p->pbm_A.controller_regs + SABRE_IOSPACE; + unsigned long mbase = p->pbm_A.controller_regs + SABRE_MEMSPACE; unsigned int devfn; unsigned long first, last, i; u8 *addr, map; @@ -1393,16 +1386,12 @@ pbm = &p->pbm_B; else pbm = &p->pbm_A; + pbm->chip_type = PBM_CHIP_TYPE_SABRE; pbm->parent = p; pbm->prom_node = node; pbm->pci_first_slot = 1; pbm->pci_first_busno = busrange[0]; pbm->pci_last_busno = busrange[1]; - for (err = pbm->pci_first_busno; - err <= pbm->pci_last_busno; - err++) - pci_bus2pbm[err] = pbm; - prom_getstring(node, "name", pbm->prom_name, sizeof(pbm->prom_name)); err = prom_getproperty(node, "ranges", @@ -1449,10 +1438,6 @@ pbm->prom_node = sabre_node; pbm->pci_first_busno = p->pci_first_busno; pbm->pci_last_busno = p->pci_last_busno; - for (err = pbm->pci_first_busno; - err <= pbm->pci_last_busno; - err++) - pci_bus2pbm[err] = pbm; prom_getstring(sabre_node, "name", pbm->prom_name, sizeof(pbm->prom_name)); err = prom_getproperty(sabre_node, "ranges", @@ -1488,11 +1473,11 @@ pbm->io_space.name = pbm->mem_space.name = pbm->name; /* Hack up top-level resources. */ - pbm->io_space.start = p->controller_regs + SABRE_IOSPACE; + pbm->io_space.start = p->pbm_A.controller_regs + SABRE_IOSPACE; pbm->io_space.end = pbm->io_space.start + (1UL << 24) - 1UL; pbm->io_space.flags = IORESOURCE_IO; - pbm->mem_space.start = p->controller_regs + SABRE_MEMSPACE; + pbm->mem_space.start = p->pbm_A.controller_regs + SABRE_MEMSPACE; pbm->mem_space.end = pbm->mem_space.start + (unsigned long)dma_begin - 1UL; pbm->mem_space.flags = IORESOURCE_MEM; @@ -1520,7 +1505,7 @@ u32 busrange[2]; u32 vdma[2]; u32 upa_portid, dma_mask; - int bus; + u64 clear_irq; hummingbird_p = 0; if (!strcmp(model_name, "pci108e,a001")) @@ -1567,7 +1552,8 @@ pci_controller_root = p; spin_unlock_irqrestore(&pci_controller_lock, flags); - p->portid = upa_portid; + p->pbm_A.portid = upa_portid; + p->pbm_B.portid = upa_portid; p->index = pci_num_controllers++; p->pbms_same_domain = 1; p->scan_bus = sabre_scan_bus; @@ -1590,20 +1576,31 @@ /* * First REG in property is base of entire SABRE register space. */ - p->controller_regs = pr_regs[0].phys_addr; - pci_dma_wsync = p->controller_regs + SABRE_WRSYNC; + p->pbm_A.controller_regs = pr_regs[0].phys_addr; + p->pbm_B.controller_regs = pr_regs[0].phys_addr; + pci_dma_wsync = p->pbm_A.controller_regs + SABRE_WRSYNC; printk("PCI: Found SABRE, main regs at %016lx, wsync at %016lx\n", - p->controller_regs, pci_dma_wsync); + p->pbm_A.controller_regs, pci_dma_wsync); + + /* Clear interrupts */ + + /* PCI first */ + for (clear_irq = SABRE_ICLR_A_SLOT0; clear_irq < SABRE_ICLR_B_SLOT0 + 0x80; clear_irq += 8) + sabre_write(p->pbm_A.controller_regs + clear_irq, 0x0UL); + + /* Then OBIO */ + for (clear_irq = SABRE_ICLR_SCSI; clear_irq < SABRE_ICLR_SCSI + 0x80; clear_irq += 8) + sabre_write(p->pbm_A.controller_regs + clear_irq, 0x0UL); /* Error interrupts are enabled later after the bus scan. */ - sabre_write(p->controller_regs + SABRE_PCICTRL, + sabre_write(p->pbm_A.controller_regs + SABRE_PCICTRL, (SABRE_PCICTRL_MRLEN | SABRE_PCICTRL_SERR | SABRE_PCICTRL_ARBPARK | SABRE_PCICTRL_AEN)); /* Now map in PCI config space for entire SABRE. */ p->pbm_A.config_space = p->pbm_B.config_space = - (p->controller_regs + SABRE_CONFIGSPACE); + (p->pbm_A.controller_regs + SABRE_CONFIGSPACE); printk("SABRE: Shared PCI config space at %016lx\n", p->pbm_A.config_space); @@ -1649,12 +1646,6 @@ p->pci_first_busno = busrange[0]; p->pci_last_busno = busrange[1]; - - /* - * Handle config space reads through any Simba on APB. - */ - for (bus = p->pci_first_busno; bus <= p->pci_last_busno; bus++) - pci_bus2pbm[bus] = &p->pbm_A; /* * Look for APB underneath. diff -Nru a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c --- a/arch/sparc64/kernel/pci_schizo.c Sun Jul 27 10:13:48 2003 +++ b/arch/sparc64/kernel/pci_schizo.c Sun Jul 27 10:13:48 2003 @@ -1,7 +1,7 @@ /* $Id: pci_schizo.c,v 1.24 2002/01/23 11:27:32 davem Exp $ - * pci_schizo.c: SCHIZO specific PCI controller support. + * pci_schizo.c: SCHIZO/TOMATILLO specific PCI controller support. * - * Copyright (C) 2001 David S. Miller (davem@redhat.com) + * Copyright (C) 2001, 2002, 2003 David S. Miller (davem@redhat.com) */ #include @@ -46,13 +46,7 @@ * block requires more space in Schizo's address space than * they predicted, thus requiring an address space reorg when * the newer Schizo is taped out. - * - * These offsets look weird because I keep in p->controller_regs - * the second PROM register property minus 0x10000 which is the - * base of the Safari and UPA64S registers of SCHIZO. */ -#define SCHIZO_PBM_A_REGS_OFF (0x600000UL - 0x400000UL) -#define SCHIZO_PBM_B_REGS_OFF (0x700000UL - 0x400000UL) /* Streaming buffer control register. */ #define SCHIZO_STRBUF_CTRL_LPTR 0x00000000000000f0UL /* LRU Lock Pointer */ @@ -102,25 +96,21 @@ { if (!pbm) return NULL; + bus -= pbm->pci_first_busno; return (void *) (SCHIZO_CONFIG_BASE(pbm) | SCHIZO_CONFIG_ENCODE(bus, devfn, where)); } -/* 4 slots on pbm A, and 6 slots on pbm B. In both cases - * slot 0 is the SCHIZO host bridge itself. - */ +/* Just make sure the bus number is in range. */ static int schizo_out_of_range(struct pci_pbm_info *pbm, unsigned char bus, unsigned char devfn) { - return ((pbm->parent == 0) || - ((pbm == &pbm->parent->pbm_B) && - (bus == pbm->pci_first_busno) && - PCI_SLOT(devfn) > 6) || - ((pbm == &pbm->parent->pbm_A) && - (bus == pbm->pci_first_busno) && - PCI_SLOT(devfn) > 4)); + if (bus < pbm->pci_first_busno || + bus > pbm->pci_last_busno) + return 1; + return 0; } /* SCHIZO PCI configuration space accessors. */ @@ -128,7 +118,7 @@ static int schizo_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, int where, int size, u32 *value) { - struct pci_pbm_info *pbm = pci_bus2pbm[bus_dev->number]; + struct pci_pbm_info *pbm = bus_dev->sysdata; unsigned char bus = bus_dev->number; u32 *addr; u16 tmp16; @@ -183,7 +173,7 @@ static int schizo_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, int where, int size, u32 value) { - struct pci_pbm_info *pbm = pci_bus2pbm[bus_dev->number]; + struct pci_pbm_info *pbm = bus_dev->sysdata; unsigned char bus = bus_dev->number; u32 *addr; @@ -214,6 +204,7 @@ where); return PCIBIOS_SUCCESSFUL; } + pci_config_write32(addr, value); } return PCIBIOS_SUCCESSFUL; @@ -339,17 +330,11 @@ struct pci_dev *pdev, unsigned int ino) { - struct pci_controller_info *p = pbm->parent; struct ino_bucket *bucket; - unsigned long imap, iclr, pbm_off; + unsigned long imap, iclr; unsigned long imap_off, iclr_off; int pil; - if (pbm == &p->pbm_A) - pbm_off = SCHIZO_PBM_A_REGS_OFF; - else - pbm_off = SCHIZO_PBM_B_REGS_OFF; - ino &= PCI_IRQ_INO; imap_off = schizo_imap_offset(ino); @@ -359,11 +344,11 @@ if (PIL_RESERVED(pil)) BUG(); - imap = p->controller_regs + pbm_off + imap_off; + imap = pbm->pbm_regs + imap_off; imap += 4; iclr_off = schizo_iclr_offset(ino); - iclr = p->controller_regs + pbm_off + iclr_off; + iclr = pbm->pbm_regs + iclr_off; iclr += 4; /* On Schizo, no inofixup occurs. This is because each @@ -388,6 +373,13 @@ static unsigned long stc_tag_buf[16]; static unsigned long stc_line_buf[16]; +/* These offsets look weird because I keep in pbm->controller_regs + * the second PROM register property minus 0x10000 which is the + * base of the Safari and UPA64S registers of SCHIZO. + */ +#define SCHIZO_PBM_A_REGS_OFF (0x600000UL - 0x400000UL) +#define SCHIZO_PBM_B_REGS_OFF (0x700000UL - 0x400000UL) + static void schizo_clear_other_err_intr(int irq) { struct ino_bucket *bucket = __bucket(irq); @@ -419,19 +411,12 @@ static void __schizo_check_stc_error_pbm(struct pci_pbm_info *pbm, enum schizo_error_type type) { - struct pci_controller_info *p = pbm->parent; struct pci_strbuf *strbuf = &pbm->stc; - unsigned long regbase = p->controller_regs; + unsigned long regbase = pbm->pbm_regs; unsigned long err_base, tag_base, line_base; u64 control; - char pbm_name = (pbm == &p->pbm_A ? 'A' : 'B'); int i; - if (pbm == &p->pbm_A) - regbase += SCHIZO_PBM_A_REGS_OFF; - else - regbase += SCHIZO_PBM_B_REGS_OFF; - err_base = regbase + SCHIZO_STC_ERR; tag_base = regbase + SCHIZO_STC_TAG; line_base = regbase + SCHIZO_STC_LINE; @@ -477,8 +462,8 @@ unsigned long errval = stc_error_buf[j]; if (errval != 0) { saw_error++; - printk("SCHIZO%d: PBM-%c STC_ERR(%d)[wr(%d)rd(%d)]\n", - p->index, pbm_name, + printk("%s: STC_ERR(%d)[wr(%d)rd(%d)]\n", + pbm->name, j, (errval & SCHIZO_STCERR_WRITE) ? 1 : 0, (errval & SCHIZO_STCERR_READ) ? 1 : 0); @@ -487,8 +472,8 @@ if (saw_error != 0) { unsigned long tagval = stc_tag_buf[i]; unsigned long lineval = stc_line_buf[i]; - printk("SCHIZO%d: PBM-%c STC_TAG(%d)[PA(%016lx)VA(%08lx)V(%d)R(%d)]\n", - p->index, pbm_name, + printk("%s: STC_TAG(%d)[PA(%016lx)VA(%08lx)V(%d)R(%d)]\n", + pbm->name, i, ((tagval & SCHIZO_STCTAG_PPN) >> 19UL), (tagval & SCHIZO_STCTAG_VPN), @@ -496,9 +481,9 @@ ((tagval & SCHIZO_STCTAG_READ) ? 1 : 0)); /* XXX Should spit out per-bank error information... -DaveM */ - printk("SCHIZO%d: PBM-%c STC_LINE(%d)[LIDX(%lx)SP(%lx)LADDR(%lx)EP(%lx)" + printk("%s: STC_LINE(%d)[LIDX(%lx)SP(%lx)LADDR(%lx)EP(%lx)" "V(%d)FOFN(%d)]\n", - p->index, pbm_name, + pbm->name, i, ((lineval & SCHIZO_STCLINE_LINDX) >> 23UL), ((lineval & SCHIZO_STCLINE_SPTR) >> 13UL), @@ -534,13 +519,11 @@ static void schizo_check_iommu_error_pbm(struct pci_pbm_info *pbm, enum schizo_error_type type) { - struct pci_controller_info *p = pbm->parent; struct pci_iommu *iommu = pbm->iommu; unsigned long iommu_tag[16]; unsigned long iommu_data[16]; unsigned long flags; u64 control; - char pbm_name = (pbm == &p->pbm_A ? 'A' : 'B'); int i; spin_lock_irqsave(&iommu->lock, flags); @@ -568,8 +551,8 @@ type_string = "ECC Error"; break; }; - printk("SCHIZO%d: PBM-%c IOMMU Error, type[%s]\n", - p->index, pbm_name, type_string); + printk("%s: IOMMU Error, type[%s]\n", + pbm->name, type_string); /* Put the IOMMU into diagnostic mode and probe * it's TLB for entries with error status. @@ -584,11 +567,7 @@ schizo_write(iommu->iommu_control, control | SCHIZO_IOMMU_CTRL_DENAB); - base = p->controller_regs; - if (pbm == &p->pbm_A) - base += SCHIZO_PBM_A_REGS_OFF; - else - base += SCHIZO_PBM_B_REGS_OFF; + base = pbm->pbm_regs; for (i = 0; i < 16; i++) { iommu_tag[i] = @@ -627,22 +606,23 @@ type_string = "ECC Error"; break; }; - printk("SCHIZO%d: PBM-%c IOMMU TAG(%d)[error(%s) ctx(%x) wr(%d) str(%d) " + printk("%s: IOMMU TAG(%d)[error(%s) ctx(%x) wr(%d) str(%d) " "sz(%dK) vpg(%08lx)]\n", - p->index, pbm_name, i, type_string, + pbm->name, i, type_string, (int)((tag & SCHIZO_IOMMU_TAG_CTXT) >> 25UL), ((tag & SCHIZO_IOMMU_TAG_WRITE) ? 1 : 0), ((tag & SCHIZO_IOMMU_TAG_STREAM) ? 1 : 0), ((tag & SCHIZO_IOMMU_TAG_SIZE) ? 64 : 8), (tag & SCHIZO_IOMMU_TAG_VPAGE) << IOMMU_PAGE_SHIFT); - printk("SCHIZO%d: PBM-%c IOMMU DATA(%d)[valid(%d) cache(%d) ppg(%016lx)]\n", - p->index, pbm_name, i, + printk("%s: IOMMU DATA(%d)[valid(%d) cache(%d) ppg(%016lx)]\n", + pbm->name, i, ((data & SCHIZO_IOMMU_DATA_VALID) ? 1 : 0), ((data & SCHIZO_IOMMU_DATA_CACHE) ? 1 : 0), (data & SCHIZO_IOMMU_DATA_PPAGE) << IOMMU_PAGE_SHIFT); } } - __schizo_check_stc_error_pbm(pbm, type); + if (pbm->stc.strbuf_enabled) + __schizo_check_stc_error_pbm(pbm, type); spin_unlock_irqrestore(&iommu->lock, flags); } @@ -657,26 +637,26 @@ #define SCHIZO_UE_AFSR 0x10030UL #define SCHIZO_UE_AFAR 0x10038UL -#define SCHIZO_UEAFSR_PPIO 0x8000000000000000UL -#define SCHIZO_UEAFSR_PDRD 0x4000000000000000UL -#define SCHIZO_UEAFSR_PDWR 0x2000000000000000UL -#define SCHIZO_UEAFSR_SPIO 0x1000000000000000UL -#define SCHIZO_UEAFSR_SDMA 0x0800000000000000UL -#define SCHIZO_UEAFSR_ERRPNDG 0x0300000000000000UL -#define SCHIZO_UEAFSR_BMSK 0x000003ff00000000UL -#define SCHIZO_UEAFSR_QOFF 0x00000000c0000000UL -#define SCHIZO_UEAFSR_AID 0x000000001f000000UL -#define SCHIZO_UEAFSR_PARTIAL 0x0000000000800000UL -#define SCHIZO_UEAFSR_OWNEDIN 0x0000000000400000UL -#define SCHIZO_UEAFSR_MTAGSYND 0x00000000000f0000UL -#define SCHIZO_UEAFSR_MTAG 0x000000000000e000UL -#define SCHIZO_UEAFSR_ECCSYND 0x00000000000001ffUL +#define SCHIZO_UEAFSR_PPIO 0x8000000000000000UL /* Safari */ +#define SCHIZO_UEAFSR_PDRD 0x4000000000000000UL /* Safari/Tomatillo */ +#define SCHIZO_UEAFSR_PDWR 0x2000000000000000UL /* Safari */ +#define SCHIZO_UEAFSR_SPIO 0x1000000000000000UL /* Safari */ +#define SCHIZO_UEAFSR_SDMA 0x0800000000000000UL /* Safari/Tomatillo */ +#define SCHIZO_UEAFSR_ERRPNDG 0x0300000000000000UL /* Safari */ +#define SCHIZO_UEAFSR_BMSK 0x000003ff00000000UL /* Safari */ +#define SCHIZO_UEAFSR_QOFF 0x00000000c0000000UL /* Safari/Tomatillo */ +#define SCHIZO_UEAFSR_AID 0x000000001f000000UL /* Safari/Tomatillo */ +#define SCHIZO_UEAFSR_PARTIAL 0x0000000000800000UL /* Safari */ +#define SCHIZO_UEAFSR_OWNEDIN 0x0000000000400000UL /* Safari */ +#define SCHIZO_UEAFSR_MTAGSYND 0x00000000000f0000UL /* Safari */ +#define SCHIZO_UEAFSR_MTAG 0x000000000000e000UL /* Safari */ +#define SCHIZO_UEAFSR_ECCSYND 0x00000000000001ffUL /* Safari */ static irqreturn_t schizo_ue_intr(int irq, void *dev_id, struct pt_regs *regs) { struct pci_controller_info *p = dev_id; - unsigned long afsr_reg = p->controller_regs + SCHIZO_UE_AFSR; - unsigned long afar_reg = p->controller_regs + SCHIZO_UE_AFAR; + unsigned long afsr_reg = p->pbm_B.controller_regs + SCHIZO_UE_AFSR; + unsigned long afar_reg = p->pbm_B.controller_regs + SCHIZO_UE_AFAR; unsigned long afsr, afar, error_bits; int reported, limit; @@ -701,7 +681,7 @@ schizo_write(afsr_reg, error_bits); /* Log the error. */ - printk("SCHIZO%d: Uncorrectable Error, primary error type[%s]\n", + printk("PCI%d: Uncorrectable Error, primary error type[%s]\n", p->index, (((error_bits & SCHIZO_UEAFSR_PPIO) ? "PIO" : @@ -709,20 +689,20 @@ "DMA Read" : ((error_bits & SCHIZO_UEAFSR_PDWR) ? "DMA Write" : "???"))))); - printk("SCHIZO%d: bytemask[%04lx] qword_offset[%lx] SAFARI_AID[%02lx]\n", + printk("PCI%d: bytemask[%04lx] qword_offset[%lx] SAFARI_AID[%02lx]\n", p->index, (afsr & SCHIZO_UEAFSR_BMSK) >> 32UL, (afsr & SCHIZO_UEAFSR_QOFF) >> 30UL, (afsr & SCHIZO_UEAFSR_AID) >> 24UL); - printk("SCHIZO%d: partial[%d] owned_in[%d] mtag[%lx] mtag_synd[%lx] ecc_sync[%lx]\n", + printk("PCI%d: partial[%d] owned_in[%d] mtag[%lx] mtag_synd[%lx] ecc_sync[%lx]\n", p->index, (afsr & SCHIZO_UEAFSR_PARTIAL) ? 1 : 0, (afsr & SCHIZO_UEAFSR_OWNEDIN) ? 1 : 0, (afsr & SCHIZO_UEAFSR_MTAG) >> 13UL, (afsr & SCHIZO_UEAFSR_MTAGSYND) >> 16UL, (afsr & SCHIZO_UEAFSR_ECCSYND) >> 0UL); - printk("SCHIZO%d: UE AFAR [%016lx]\n", p->index, afar); - printk("SCHIZO%d: UE Secondary errors [", p->index); + printk("PCI%d: UE AFAR [%016lx]\n", p->index, afar); + printk("PCI%d: UE Secondary errors [", p->index); reported = 0; if (afsr & SCHIZO_UEAFSR_SPIO) { reported++; @@ -765,8 +745,8 @@ static irqreturn_t schizo_ce_intr(int irq, void *dev_id, struct pt_regs *regs) { struct pci_controller_info *p = dev_id; - unsigned long afsr_reg = p->controller_regs + SCHIZO_CE_AFSR; - unsigned long afar_reg = p->controller_regs + SCHIZO_CE_AFAR; + unsigned long afsr_reg = p->pbm_B.controller_regs + SCHIZO_CE_AFSR; + unsigned long afar_reg = p->pbm_B.controller_regs + SCHIZO_CE_AFAR; unsigned long afsr, afar, error_bits; int reported, limit; @@ -791,7 +771,7 @@ schizo_write(afsr_reg, error_bits); /* Log the error. */ - printk("SCHIZO%d: Correctable Error, primary error type[%s]\n", + printk("PCI%d: Correctable Error, primary error type[%s]\n", p->index, (((error_bits & SCHIZO_CEAFSR_PPIO) ? "PIO" : @@ -803,20 +783,20 @@ /* XXX Use syndrome and afar to print out module string just like * XXX UDB CE trap handler does... -DaveM */ - printk("SCHIZO%d: bytemask[%04lx] qword_offset[%lx] SAFARI_AID[%02lx]\n", + printk("PCI%d: bytemask[%04lx] qword_offset[%lx] SAFARI_AID[%02lx]\n", p->index, (afsr & SCHIZO_UEAFSR_BMSK) >> 32UL, (afsr & SCHIZO_UEAFSR_QOFF) >> 30UL, (afsr & SCHIZO_UEAFSR_AID) >> 24UL); - printk("SCHIZO%d: partial[%d] owned_in[%d] mtag[%lx] mtag_synd[%lx] ecc_sync[%lx]\n", + printk("PCI%d: partial[%d] owned_in[%d] mtag[%lx] mtag_synd[%lx] ecc_sync[%lx]\n", p->index, (afsr & SCHIZO_UEAFSR_PARTIAL) ? 1 : 0, (afsr & SCHIZO_UEAFSR_OWNEDIN) ? 1 : 0, (afsr & SCHIZO_UEAFSR_MTAG) >> 13UL, (afsr & SCHIZO_UEAFSR_MTAGSYND) >> 16UL, (afsr & SCHIZO_UEAFSR_ECCSYND) >> 0UL); - printk("SCHIZO%d: CE AFAR [%016lx]\n", p->index, afar); - printk("SCHIZO%d: CE Secondary errors [", p->index); + printk("PCI%d: CE AFAR [%016lx]\n", p->index, afar); + printk("PCI%d: CE Secondary errors [", p->index); reported = 0; if (afsr & SCHIZO_CEAFSR_SPIO) { reported++; @@ -838,23 +818,23 @@ #define SCHIZO_PCI_AFSR 0x2010UL #define SCHIZO_PCI_AFAR 0x2018UL -#define SCHIZO_PCIAFSR_PMA 0x8000000000000000UL -#define SCHIZO_PCIAFSR_PTA 0x4000000000000000UL -#define SCHIZO_PCIAFSR_PRTRY 0x2000000000000000UL -#define SCHIZO_PCIAFSR_PPERR 0x1000000000000000UL -#define SCHIZO_PCIAFSR_PTTO 0x0800000000000000UL -#define SCHIZO_PCIAFSR_PUNUS 0x0400000000000000UL -#define SCHIZO_PCIAFSR_SMA 0x0200000000000000UL -#define SCHIZO_PCIAFSR_STA 0x0100000000000000UL -#define SCHIZO_PCIAFSR_SRTRY 0x0080000000000000UL -#define SCHIZO_PCIAFSR_SPERR 0x0040000000000000UL -#define SCHIZO_PCIAFSR_STTO 0x0020000000000000UL -#define SCHIZO_PCIAFSR_SUNUS 0x0010000000000000UL -#define SCHIZO_PCIAFSR_BMSK 0x000003ff00000000UL -#define SCHIZO_PCIAFSR_BLK 0x0000000080000000UL -#define SCHIZO_PCIAFSR_CFG 0x0000000040000000UL -#define SCHIZO_PCIAFSR_MEM 0x0000000020000000UL -#define SCHIZO_PCIAFSR_IO 0x0000000010000000UL +#define SCHIZO_PCIAFSR_PMA 0x8000000000000000UL /* Schizo/Tomatillo */ +#define SCHIZO_PCIAFSR_PTA 0x4000000000000000UL /* Schizo/Tomatillo */ +#define SCHIZO_PCIAFSR_PRTRY 0x2000000000000000UL /* Schizo/Tomatillo */ +#define SCHIZO_PCIAFSR_PPERR 0x1000000000000000UL /* Schizo/Tomatillo */ +#define SCHIZO_PCIAFSR_PTTO 0x0800000000000000UL /* Schizo/Tomatillo */ +#define SCHIZO_PCIAFSR_PUNUS 0x0400000000000000UL /* Schizo */ +#define SCHIZO_PCIAFSR_SMA 0x0200000000000000UL /* Schizo/Tomatillo */ +#define SCHIZO_PCIAFSR_STA 0x0100000000000000UL /* Schizo/Tomatillo */ +#define SCHIZO_PCIAFSR_SRTRY 0x0080000000000000UL /* Schizo/Tomatillo */ +#define SCHIZO_PCIAFSR_SPERR 0x0040000000000000UL /* Schizo/Tomatillo */ +#define SCHIZO_PCIAFSR_STTO 0x0020000000000000UL /* Schizo/Tomatillo */ +#define SCHIZO_PCIAFSR_SUNUS 0x0010000000000000UL /* Schizo */ +#define SCHIZO_PCIAFSR_BMSK 0x000003ff00000000UL /* Schizo/Tomatillo */ +#define SCHIZO_PCIAFSR_BLK 0x0000000080000000UL /* Schizo/Tomatillo */ +#define SCHIZO_PCIAFSR_CFG 0x0000000040000000UL /* Schizo/Tomatillo */ +#define SCHIZO_PCIAFSR_MEM 0x0000000020000000UL /* Schizo/Tomatillo */ +#define SCHIZO_PCIAFSR_IO 0x0000000010000000UL /* Schizo/Tomatillo */ static irqreturn_t schizo_pcierr_intr(int irq, void *dev_id, struct pt_regs *regs) { @@ -863,16 +843,8 @@ unsigned long afsr_reg, afar_reg, base; unsigned long afsr, afar, error_bits; int reported; - char pbm_name; - base = p->controller_regs; - if (pbm == &pbm->parent->pbm_A) { - base += SCHIZO_PBM_A_REGS_OFF; - pbm_name = 'A'; - } else { - base += SCHIZO_PBM_B_REGS_OFF; - pbm_name = 'B'; - } + base = pbm->pbm_regs; afsr_reg = base + SCHIZO_PCI_AFSR; afar_reg = base + SCHIZO_PCI_AFAR; @@ -894,8 +866,8 @@ schizo_write(afsr_reg, error_bits); /* Log the error. */ - printk("SCHIZO%d: PBM-%c PCI Error, primary error type[%s]\n", - p->index, pbm_name, + printk("%s: PCI Error, primary error type[%s]\n", + pbm->name, (((error_bits & SCHIZO_PCIAFSR_PMA) ? "Master Abort" : ((error_bits & SCHIZO_PCIAFSR_PTA) ? @@ -908,8 +880,8 @@ "Timeout" : ((error_bits & SCHIZO_PCIAFSR_PUNUS) ? "Bus Unusable" : "???")))))))); - printk("SCHIZO%d: PBM-%c bytemask[%04lx] was_block(%d) space(%s)\n", - p->index, pbm_name, + printk("%s: bytemask[%04lx] was_block(%d) space(%s)\n", + pbm->name, (afsr & SCHIZO_PCIAFSR_BMSK) >> 32UL, (afsr & SCHIZO_PCIAFSR_BLK) ? 1 : 0, ((afsr & SCHIZO_PCIAFSR_CFG) ? @@ -918,10 +890,10 @@ "Memory" : ((afsr & SCHIZO_PCIAFSR_IO) ? "I/O" : "???")))); - printk("SCHIZO%d: PBM-%c PCI AFAR [%016lx]\n", - p->index, pbm_name, afar); - printk("SCHIZO%d: PBM-%c PCI Secondary errors [", - p->index, pbm_name); + printk("%s: PCI AFAR [%016lx]\n", + pbm->name, afar); + printk("%s: PCI Secondary errors [", + pbm->name); reported = 0; if (afsr & SCHIZO_PCIAFSR_SMA) { reported++; @@ -986,24 +958,37 @@ #define SAFARI_ERRLOG_ERROUT 0x8000000000000000UL -#define SAFARI_ERROR_BADCMD 0x4000000000000000UL -#define SAFARI_ERROR_SSMDIS 0x2000000000000000UL -#define SAFARI_ERROR_BADMA 0x1000000000000000UL -#define SAFARI_ERROR_BADMB 0x0800000000000000UL -#define SAFARI_ERROR_BADMC 0x0400000000000000UL -#define SAFARI_ERROR_CPU1PS 0x0000000000002000UL -#define SAFARI_ERROR_CPU1PB 0x0000000000001000UL -#define SAFARI_ERROR_CPU0PS 0x0000000000000800UL -#define SAFARI_ERROR_CPU0PB 0x0000000000000400UL -#define SAFARI_ERROR_CIQTO 0x0000000000000200UL -#define SAFARI_ERROR_LPQTO 0x0000000000000100UL -#define SAFARI_ERROR_SFPQTO 0x0000000000000080UL -#define SAFARI_ERROR_UFPQTO 0x0000000000000040UL -#define SAFARI_ERROR_APERR 0x0000000000000020UL -#define SAFARI_ERROR_UNMAP 0x0000000000000010UL -#define SAFARI_ERROR_BUSERR 0x0000000000000004UL -#define SAFARI_ERROR_TIMEOUT 0x0000000000000002UL -#define SAFARI_ERROR_ILL 0x0000000000000001UL +#define BUS_ERROR_BADCMD 0x4000000000000000UL /* Schizo/Tomatillo */ +#define BUS_ERROR_SSMDIS 0x2000000000000000UL /* Safari */ +#define BUS_ERROR_BADMA 0x1000000000000000UL /* Safari */ +#define BUS_ERROR_BADMB 0x0800000000000000UL /* Safari */ +#define BUS_ERROR_BADMC 0x0400000000000000UL /* Safari */ +#define BUS_ERROR_SNOOP_GR 0x0000000000200000UL /* Tomatillo */ +#define BUS_ERROR_SNOOP_PCI 0x0000000000100000UL /* Tomatillo */ +#define BUS_ERROR_SNOOP_RD 0x0000000000080000UL /* Tomatillo */ +#define BUS_ERROR_SNOOP_RDS 0x0000000000020000UL /* Tomatillo */ +#define BUS_ERROR_SNOOP_RDSA 0x0000000000010000UL /* Tomatillo */ +#define BUS_ERROR_SNOOP_OWN 0x0000000000008000UL /* Tomatillo */ +#define BUS_ERROR_SNOOP_RDO 0x0000000000004000UL /* Tomatillo */ +#define BUS_ERROR_CPU1PS 0x0000000000002000UL /* Safari */ +#define BUS_ERROR_WDATA_PERR 0x0000000000002000UL /* Tomatillo */ +#define BUS_ERROR_CPU1PB 0x0000000000001000UL /* Safari */ +#define BUS_ERROR_CTRL_PERR 0x0000000000001000UL /* Tomatillo */ +#define BUS_ERROR_CPU0PS 0x0000000000000800UL /* Safari */ +#define BUS_ERROR_SNOOP_ERR 0x0000000000000800UL /* Tomatillo */ +#define BUS_ERROR_CPU0PB 0x0000000000000400UL /* Safari */ +#define BUS_ERROR_JBUS_ILL_B 0x0000000000000400UL /* Tomatillo */ +#define BUS_ERROR_CIQTO 0x0000000000000200UL /* Safari */ +#define BUS_ERROR_LPQTO 0x0000000000000100UL /* Safari */ +#define BUS_ERROR_JBUS_ILL_C 0x0000000000000100UL /* Tomatillo */ +#define BUS_ERROR_SFPQTO 0x0000000000000080UL /* Safari */ +#define BUS_ERROR_UFPQTO 0x0000000000000040UL /* Safari */ +#define BUS_ERROR_RD_PERR 0x0000000000000040UL /* Tomatillo */ +#define BUS_ERROR_APERR 0x0000000000000020UL /* Safari/Tomatillo */ +#define BUS_ERROR_UNMAP 0x0000000000000010UL /* Safari/Tomatillo */ +#define BUS_ERROR_BUSERR 0x0000000000000004UL /* Safari/Tomatillo */ +#define BUS_ERROR_TIMEOUT 0x0000000000000002UL /* Safari/Tomatillo */ +#define BUS_ERROR_ILL 0x0000000000000001UL /* Safari */ /* We only expect UNMAP errors here. The rest of the Safari errors * are marked fatal and thus cause a system reset. @@ -1013,19 +998,19 @@ struct pci_controller_info *p = dev_id; u64 errlog; - errlog = schizo_read(p->controller_regs + SCHIZO_SAFARI_ERRLOG); - schizo_write(p->controller_regs + SCHIZO_SAFARI_ERRLOG, + errlog = schizo_read(p->pbm_B.controller_regs + SCHIZO_SAFARI_ERRLOG); + schizo_write(p->pbm_B.controller_regs + SCHIZO_SAFARI_ERRLOG, errlog & ~(SAFARI_ERRLOG_ERROUT)); - if (!(errlog & SAFARI_ERROR_UNMAP)) { - printk("SCHIZO%d: Unexpected Safari error interrupt, errlog[%016lx]\n", + if (!(errlog & BUS_ERROR_UNMAP)) { + printk("PCI%d: Unexpected Safari/JBUS error interrupt, errlog[%016lx]\n", p->index, errlog); schizo_clear_other_err_intr(irq); return IRQ_HANDLED; } - printk("SCHIZO%d: Safari interrupt, UNMAPPED error, interrogating IOMMUs.\n", + printk("PCI%d: Safari/JBUS interrupt, UNMAPPED error, interrogating IOMMUs.\n", p->index); schizo_check_iommu_error(p, SAFARI_ERR); @@ -1050,36 +1035,198 @@ #define SCHIZO_PCIERR_B_INO 0x33 /* PBM B PCI bus error */ #define SCHIZO_SERR_INO 0x34 /* Safari interface error */ -#define SCHIZO_PCIA_CTRL (SCHIZO_PBM_A_REGS_OFF + 0x2000UL) -#define SCHIZO_PCIB_CTRL (SCHIZO_PBM_B_REGS_OFF + 0x2000UL) -#define SCHIZO_PCICTRL_BUS_UNUS (1UL << 63UL) -#define SCHIZO_PCICTRL_ESLCK (1UL << 51UL) -#define SCHIZO_PCICTRL_ERRSLOT (7UL << 48UL) -#define SCHIZO_PCICTRL_TTO_ERR (1UL << 38UL) -#define SCHIZO_PCICTRL_RTRY_ERR (1UL << 37UL) -#define SCHIZO_PCICTRL_DTO_ERR (1UL << 36UL) -#define SCHIZO_PCICTRL_SBH_ERR (1UL << 35UL) -#define SCHIZO_PCICTRL_SERR (1UL << 34UL) -#define SCHIZO_PCICTRL_PCISPD (1UL << 33UL) -#define SCHIZO_PCICTRL_PTO (3UL << 24UL) -#define SCHIZO_PCICTRL_DTO_INT (1UL << 19UL) -#define SCHIZO_PCICTRL_SBH_INT (1UL << 18UL) -#define SCHIZO_PCICTRL_EEN (1UL << 17UL) -#define SCHIZO_PCICTRL_PARK (1UL << 16UL) -#define SCHIZO_PCICTRL_PCIRST (1UL << 8UL) -#define SCHIZO_PCICTRL_ARB (0x3fUL << 0UL) +#define SCHIZO_PCI_CTRL (0x2000UL) +#define SCHIZO_PCICTRL_BUS_UNUS (1UL << 63UL) /* Safari */ +#define SCHIZO_PCICTRL_ARB_PRIO (0x1ff << 52UL) /* Tomatillo */ +#define SCHIZO_PCICTRL_ESLCK (1UL << 51UL) /* Safari */ +#define SCHIZO_PCICTRL_ERRSLOT (7UL << 48UL) /* Safari */ +#define SCHIZO_PCICTRL_TTO_ERR (1UL << 38UL) /* Safari/Tomatillo */ +#define SCHIZO_PCICTRL_RTRY_ERR (1UL << 37UL) /* Safari/Tomatillo */ +#define SCHIZO_PCICTRL_DTO_ERR (1UL << 36UL) /* Safari/Tomatillo */ +#define SCHIZO_PCICTRL_SBH_ERR (1UL << 35UL) /* Safari */ +#define SCHIZO_PCICTRL_SERR (1UL << 34UL) /* Safari/Tomatillo */ +#define SCHIZO_PCICTRL_PCISPD (1UL << 33UL) /* Safari */ +#define SCHIZO_PCICTRL_MRM_PREF (1UL << 28UL) /* Tomatillo */ +#define SCHIZO_PCICTRL_RDO_PREF (1UL << 27UL) /* Tomatillo */ +#define SCHIZO_PCICTRL_RDL_PREF (1UL << 26UL) /* Tomatillo */ +#define SCHIZO_PCICTRL_PTO (3UL << 24UL) /* Safari/Tomatillo */ +#define SCHIZO_PCICTRL_PTO_SHIFT 24UL +#define SCHIZO_PCICTRL_TRWSW (7UL << 21UL) /* Tomatillo */ +#define SCHIZO_PCICTRL_F_TGT_A (1UL << 20UL) /* Tomatillo */ +#define SCHIZO_PCICTRL_S_DTO_INT (1UL << 19UL) /* Safari */ +#define SCHIZO_PCICTRL_F_TGT_RT (1UL << 19UL) /* Tomatillo */ +#define SCHIZO_PCICTRL_SBH_INT (1UL << 18UL) /* Safari */ +#define SCHIZO_PCICTRL_T_DTO_INT (1UL << 18UL) /* Tomatillo */ +#define SCHIZO_PCICTRL_EEN (1UL << 17UL) /* Safari/Tomatillo */ +#define SCHIZO_PCICTRL_PARK (1UL << 16UL) /* Safari/Tomatillo */ +#define SCHIZO_PCICTRL_PCIRST (1UL << 8UL) /* Safari */ +#define SCHIZO_PCICTRL_ARB_S (0x3fUL << 0UL) /* Safari */ +#define SCHIZO_PCICTRL_ARB_T (0xffUL << 0UL) /* Tomatillo */ + +/* How the Tomatillo IRQs are routed around is pure guesswork here. + * + * All the Tomatillo devices I see in prtconf dumps seem to have only + * a single PCI bus unit attached to it. It would seem they are seperate + * devices because their PortID (ie. JBUS ID) values are all different + * and thus the registers are mapped to totally different locations. + * + * However, two Tomatillo's look "similar" in that the only difference + * in their PortID is the lowest bit. + * + * So if we were to ignore this lower bit, it certainly looks like two + * PCI bus units of the same Tomatillo. I still have not really + * figured this out... + */ +static void __init tomatillo_register_error_handlers(struct pci_controller_info *p) +{ + struct pci_pbm_info *pbm; + unsigned int irq; + struct ino_bucket *bucket; + u64 tmp, err_mask; + int is_pbm_a; + + pbm = &p->pbm_B; + is_pbm_a = 0; + + /* Build IRQs and register handlers. */ + irq = schizo_irq_build(pbm, NULL, (pbm->portid << 6) | SCHIZO_UE_INO); + if (request_irq(irq, schizo_ue_intr, + SA_SHIRQ, "TOMATILLO UE", p) < 0) { + prom_printf("TOMATILLO%d: Cannot register UE interrupt.\n", + p->index); + prom_halt(); + } + bucket = __bucket(irq); + tmp = readl(bucket->imap); + upa_writel(tmp, (pbm->pbm_regs + + schizo_imap_offset(SCHIZO_UE_INO) + 4)); + + irq = schizo_irq_build(pbm, NULL, (pbm->portid << 6) | SCHIZO_CE_INO); + if (request_irq(irq, schizo_ce_intr, + SA_SHIRQ, "TOMATILLO CE", p) < 0) { + prom_printf("TOMATILLO%d: Cannot register CE interrupt.\n", + p->index); + prom_halt(); + } + bucket = __bucket(irq); + tmp = upa_readl(bucket->imap); + upa_writel(tmp, (pbm->pbm_regs + + schizo_imap_offset(SCHIZO_CE_INO) + 4)); + + pbm = &p->pbm_A; + is_pbm_a = 1; + + irq = schizo_irq_build(pbm, NULL, ((pbm->portid << 6) | + SCHIZO_PCIERR_A_INO)); + if (request_irq(irq, schizo_pcierr_intr, + SA_SHIRQ, "TOMATILLO PCIERR", pbm) < 0) { + prom_printf("%s: Cannot register PciERR interrupt.\n", + pbm->name); + prom_halt(); + } + bucket = __bucket(irq); + tmp = upa_readl(bucket->imap); + upa_writel(tmp, (pbm->pbm_regs + + schizo_imap_offset(SCHIZO_PCIERR_A_INO) + 4)); + + pbm = &p->pbm_B; + is_pbm_a = 0; + + irq = schizo_irq_build(pbm, NULL, ((pbm->portid << 6) | + SCHIZO_PCIERR_B_INO)); + if (request_irq(irq, schizo_pcierr_intr, + SA_SHIRQ, "TOMATILLO PCIERR", pbm) < 0) { + prom_printf("%s: Cannot register PciERR interrupt.\n", + pbm->name); + prom_halt(); + } + bucket = __bucket(irq); + tmp = upa_readl(bucket->imap); + upa_writel(tmp, (pbm->pbm_regs + + schizo_imap_offset(SCHIZO_PCIERR_B_INO) + 4)); + + irq = schizo_irq_build(pbm, NULL, (pbm->portid << 6) | SCHIZO_SERR_INO); + if (request_irq(irq, schizo_safarierr_intr, + SA_SHIRQ, "TOMATILLO SERR", p) < 0) { + prom_printf("%s: Cannot register SafariERR interrupt.\n", + pbm->name); + prom_halt(); + } + bucket = __bucket(irq); + tmp = upa_readl(bucket->imap); + upa_writel(tmp, (pbm->pbm_regs + + schizo_imap_offset(SCHIZO_SERR_INO) + 4)); + + /* Enable UE and CE interrupts for controller. */ + schizo_write(p->pbm_A.controller_regs + SCHIZO_ECC_CTRL, + (SCHIZO_ECCCTRL_EE | + SCHIZO_ECCCTRL_UE | + SCHIZO_ECCCTRL_CE)); + + schizo_write(p->pbm_B.controller_regs + SCHIZO_ECC_CTRL, + (SCHIZO_ECCCTRL_EE | + SCHIZO_ECCCTRL_UE | + SCHIZO_ECCCTRL_CE)); + + /* Enable PCI Error interrupts and clear error + * bits. + */ + err_mask = (SCHIZO_PCICTRL_BUS_UNUS | + SCHIZO_PCICTRL_TTO_ERR | + SCHIZO_PCICTRL_RTRY_ERR | + SCHIZO_PCICTRL_DTO_ERR | + SCHIZO_PCICTRL_SERR | + SCHIZO_PCICTRL_EEN); + + tmp = schizo_read(p->pbm_A.pbm_regs + SCHIZO_PCI_CTRL); + tmp |= err_mask; + schizo_write(p->pbm_A.pbm_regs + SCHIZO_PCI_CTRL, tmp); + + tmp = schizo_read(p->pbm_B.pbm_regs + SCHIZO_PCI_CTRL); + tmp |= err_mask; + schizo_write(p->pbm_B.pbm_regs + SCHIZO_PCI_CTRL, tmp); + + err_mask = (SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_PTA | + SCHIZO_PCIAFSR_PRTRY | SCHIZO_PCIAFSR_PPERR | + SCHIZO_PCIAFSR_PTTO | + SCHIZO_PCIAFSR_SMA | SCHIZO_PCIAFSR_STA | + SCHIZO_PCIAFSR_SRTRY | SCHIZO_PCIAFSR_SPERR | + SCHIZO_PCIAFSR_STTO); + + schizo_write(p->pbm_A.pbm_regs + SCHIZO_PCI_AFSR, err_mask); + schizo_write(p->pbm_B.pbm_regs + SCHIZO_PCI_AFSR, err_mask); + + err_mask = (BUS_ERROR_BADCMD | BUS_ERROR_SNOOP_GR | + BUS_ERROR_SNOOP_PCI | BUS_ERROR_SNOOP_RD | + BUS_ERROR_SNOOP_RDS | BUS_ERROR_SNOOP_RDSA | + BUS_ERROR_SNOOP_OWN | BUS_ERROR_SNOOP_RDO | + BUS_ERROR_WDATA_PERR | BUS_ERROR_CTRL_PERR | + BUS_ERROR_SNOOP_ERR | BUS_ERROR_JBUS_ILL_B | + BUS_ERROR_JBUS_ILL_C | BUS_ERROR_RD_PERR | + BUS_ERROR_APERR | BUS_ERROR_UNMAP | + BUS_ERROR_BUSERR | BUS_ERROR_TIMEOUT); + + schizo_write(p->pbm_A.controller_regs + SCHIZO_SAFARI_ERRCTRL, + (SCHIZO_SAFERRCTRL_EN | err_mask)); + schizo_write(p->pbm_B.controller_regs + SCHIZO_SAFARI_ERRCTRL, + (SCHIZO_SAFERRCTRL_EN | err_mask)); + + schizo_write(p->pbm_A.controller_regs + SCHIZO_SAFARI_IRQCTRL, + (SCHIZO_SAFIRQCTRL_EN | (BUS_ERROR_UNMAP))); + schizo_write(p->pbm_B.controller_regs + SCHIZO_SAFARI_IRQCTRL, + (SCHIZO_SAFIRQCTRL_EN | (BUS_ERROR_UNMAP))); +} static void __init schizo_register_error_handlers(struct pci_controller_info *p) { struct pci_pbm_info *pbm_a = &p->pbm_A; struct pci_pbm_info *pbm_b = &p->pbm_B; - unsigned long base = p->controller_regs; - unsigned int irq, portid = p->portid; + unsigned int irq; struct ino_bucket *bucket; - u64 tmp; + u64 tmp, err_mask; /* Build IRQs and register handlers. */ - irq = schizo_irq_build(pbm_b, NULL, (portid << 6) | SCHIZO_UE_INO); + irq = schizo_irq_build(pbm_b, NULL, (pbm_b->portid << 6) | SCHIZO_UE_INO); if (request_irq(irq, schizo_ue_intr, SA_SHIRQ, "SCHIZO UE", p) < 0) { prom_printf("SCHIZO%d: Cannot register UE interrupt.\n", @@ -1088,9 +1235,9 @@ } bucket = __bucket(irq); tmp = readl(bucket->imap); - upa_writel(tmp, (base + SCHIZO_PBM_B_REGS_OFF + schizo_imap_offset(SCHIZO_UE_INO) + 4)); + upa_writel(tmp, (pbm_b->pbm_regs + schizo_imap_offset(SCHIZO_UE_INO) + 4)); - irq = schizo_irq_build(pbm_b, NULL, (portid << 6) | SCHIZO_CE_INO); + irq = schizo_irq_build(pbm_b, NULL, (pbm_b->portid << 6) | SCHIZO_CE_INO); if (request_irq(irq, schizo_ce_intr, SA_SHIRQ, "SCHIZO CE", p) < 0) { prom_printf("SCHIZO%d: Cannot register CE interrupt.\n", @@ -1099,9 +1246,9 @@ } bucket = __bucket(irq); tmp = upa_readl(bucket->imap); - upa_writel(tmp, (base + SCHIZO_PBM_B_REGS_OFF + schizo_imap_offset(SCHIZO_CE_INO) + 4)); + upa_writel(tmp, (pbm_b->pbm_regs + schizo_imap_offset(SCHIZO_CE_INO) + 4)); - irq = schizo_irq_build(pbm_a, NULL, (portid << 6) | SCHIZO_PCIERR_A_INO); + irq = schizo_irq_build(pbm_a, NULL, (pbm_a->portid << 6) | SCHIZO_PCIERR_A_INO); if (request_irq(irq, schizo_pcierr_intr, SA_SHIRQ, "SCHIZO PCIERR", pbm_a) < 0) { prom_printf("SCHIZO%d(PBMA): Cannot register PciERR interrupt.\n", @@ -1110,9 +1257,9 @@ } bucket = __bucket(irq); tmp = upa_readl(bucket->imap); - upa_writel(tmp, (base + SCHIZO_PBM_A_REGS_OFF + schizo_imap_offset(SCHIZO_PCIERR_A_INO) + 4)); + upa_writel(tmp, (pbm_a->pbm_regs + schizo_imap_offset(SCHIZO_PCIERR_A_INO) + 4)); - irq = schizo_irq_build(pbm_b, NULL, (portid << 6) | SCHIZO_PCIERR_B_INO); + irq = schizo_irq_build(pbm_b, NULL, (pbm_b->portid << 6) | SCHIZO_PCIERR_B_INO); if (request_irq(irq, schizo_pcierr_intr, SA_SHIRQ, "SCHIZO PCIERR", pbm_b) < 0) { prom_printf("SCHIZO%d(PBMB): Cannot register PciERR interrupt.\n", @@ -1121,9 +1268,9 @@ } bucket = __bucket(irq); tmp = upa_readl(bucket->imap); - upa_writel(tmp, (base + SCHIZO_PBM_B_REGS_OFF + schizo_imap_offset(SCHIZO_PCIERR_B_INO) + 4)); + upa_writel(tmp, (pbm_b->pbm_regs + schizo_imap_offset(SCHIZO_PCIERR_B_INO) + 4)); - irq = schizo_irq_build(pbm_b, NULL, (portid << 6) | SCHIZO_SERR_INO); + irq = schizo_irq_build(pbm_b, NULL, (pbm_b->portid << 6) | SCHIZO_SERR_INO); if (request_irq(irq, schizo_safarierr_intr, SA_SHIRQ, "SCHIZO SERR", p) < 0) { prom_printf("SCHIZO%d(PBMB): Cannot register SafariERR interrupt.\n", @@ -1132,49 +1279,44 @@ } bucket = __bucket(irq); tmp = upa_readl(bucket->imap); - upa_writel(tmp, (base + SCHIZO_PBM_B_REGS_OFF + schizo_imap_offset(SCHIZO_SERR_INO) + 4)); + upa_writel(tmp, (pbm_b->pbm_regs + schizo_imap_offset(SCHIZO_SERR_INO) + 4)); /* Enable UE and CE interrupts for controller. */ - schizo_write(base + SCHIZO_ECC_CTRL, + schizo_write(pbm_a->controller_regs + SCHIZO_ECC_CTRL, (SCHIZO_ECCCTRL_EE | SCHIZO_ECCCTRL_UE | SCHIZO_ECCCTRL_CE)); + err_mask = (SCHIZO_PCICTRL_BUS_UNUS | + SCHIZO_PCICTRL_ESLCK | + SCHIZO_PCICTRL_TTO_ERR | + SCHIZO_PCICTRL_RTRY_ERR | + SCHIZO_PCICTRL_DTO_ERR | + SCHIZO_PCICTRL_SBH_ERR | + SCHIZO_PCICTRL_SERR | + SCHIZO_PCICTRL_SBH_INT | + SCHIZO_PCICTRL_EEN); + /* Enable PCI Error interrupts and clear error * bits for each PBM. */ - tmp = schizo_read(base + SCHIZO_PCIA_CTRL); - tmp |= (SCHIZO_PCICTRL_BUS_UNUS | - SCHIZO_PCICTRL_ESLCK | - SCHIZO_PCICTRL_TTO_ERR | - SCHIZO_PCICTRL_RTRY_ERR | - SCHIZO_PCICTRL_DTO_ERR | - SCHIZO_PCICTRL_SBH_ERR | - SCHIZO_PCICTRL_SERR | - SCHIZO_PCICTRL_SBH_INT | - SCHIZO_PCICTRL_EEN); - schizo_write(base + SCHIZO_PCIA_CTRL, tmp); - - tmp = schizo_read(base + SCHIZO_PCIB_CTRL); - tmp |= (SCHIZO_PCICTRL_BUS_UNUS | - SCHIZO_PCICTRL_ESLCK | - SCHIZO_PCICTRL_TTO_ERR | - SCHIZO_PCICTRL_RTRY_ERR | - SCHIZO_PCICTRL_DTO_ERR | - SCHIZO_PCICTRL_SBH_ERR | - SCHIZO_PCICTRL_SERR | - SCHIZO_PCICTRL_SBH_INT | - SCHIZO_PCICTRL_EEN); - schizo_write(base + SCHIZO_PCIB_CTRL, tmp); + tmp = schizo_read(pbm_a->pbm_regs + SCHIZO_PCI_CTRL); + tmp |= err_mask; + schizo_write(pbm_a->pbm_regs + SCHIZO_PCI_CTRL, tmp); - schizo_write(base + SCHIZO_PBM_A_REGS_OFF + SCHIZO_PCI_AFSR, + schizo_write(pbm_a->pbm_regs + SCHIZO_PCI_AFSR, (SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_PTA | SCHIZO_PCIAFSR_PRTRY | SCHIZO_PCIAFSR_PPERR | SCHIZO_PCIAFSR_PTTO | SCHIZO_PCIAFSR_PUNUS | SCHIZO_PCIAFSR_SMA | SCHIZO_PCIAFSR_STA | SCHIZO_PCIAFSR_SRTRY | SCHIZO_PCIAFSR_SPERR | SCHIZO_PCIAFSR_STTO | SCHIZO_PCIAFSR_SUNUS)); - schizo_write(base + SCHIZO_PBM_B_REGS_OFF + SCHIZO_PCI_AFSR, + + tmp = schizo_read(pbm_b->pbm_regs + SCHIZO_PCI_CTRL); + tmp |= err_mask; + schizo_write(pbm_b->pbm_regs + SCHIZO_PCI_CTRL, tmp); + + schizo_write(pbm_b->pbm_regs + SCHIZO_PCI_AFSR, (SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_PTA | SCHIZO_PCIAFSR_PRTRY | SCHIZO_PCIAFSR_PPERR | SCHIZO_PCIAFSR_PTTO | SCHIZO_PCIAFSR_PUNUS | @@ -1182,9 +1324,19 @@ SCHIZO_PCIAFSR_SRTRY | SCHIZO_PCIAFSR_SPERR | SCHIZO_PCIAFSR_STTO | SCHIZO_PCIAFSR_SUNUS)); - /* Make all Safari error conditions fatal except unmapped errors - * which we make generate interrupts. + /* Make all Safari error conditions fatal except unmapped + * errors which we make generate interrupts. */ + err_mask = (BUS_ERROR_BADCMD | BUS_ERROR_SSMDIS | + BUS_ERROR_BADMA | BUS_ERROR_BADMB | + BUS_ERROR_BADMC | + BUS_ERROR_CPU1PS | BUS_ERROR_CPU1PB | + BUS_ERROR_CPU0PS | BUS_ERROR_CPU0PB | + BUS_ERROR_CIQTO | + BUS_ERROR_LPQTO | BUS_ERROR_SFPQTO | + BUS_ERROR_UFPQTO | BUS_ERROR_APERR | + BUS_ERROR_BUSERR | BUS_ERROR_TIMEOUT | + BUS_ERROR_ILL); #if 1 /* XXX Something wrong with some Excalibur systems * XXX Sun is shipping. The behavior on a 2-cpu @@ -1193,134 +1345,15 @@ * XXX their error status bits are cleared. Just * XXX ignore them for now. -DaveM */ - schizo_write(base + SCHIZO_SAFARI_ERRCTRL, - (SCHIZO_SAFERRCTRL_EN | - (SAFARI_ERROR_BADCMD | SAFARI_ERROR_SSMDIS | - SAFARI_ERROR_BADMA | SAFARI_ERROR_BADMB | - SAFARI_ERROR_BADMC | - SAFARI_ERROR_CIQTO | - SAFARI_ERROR_LPQTO | SAFARI_ERROR_SFPQTO | - SAFARI_ERROR_UFPQTO | SAFARI_ERROR_APERR | - SAFARI_ERROR_BUSERR | SAFARI_ERROR_TIMEOUT | - SAFARI_ERROR_ILL))); -#else - schizo_write(base + SCHIZO_SAFARI_ERRCTRL, - (SCHIZO_SAFERRCTRL_EN | - (SAFARI_ERROR_BADCMD | SAFARI_ERROR_SSMDIS | - SAFARI_ERROR_BADMA | SAFARI_ERROR_BADMB | - SAFARI_ERROR_BADMC | - SAFARI_ERROR_CPU1PS | SAFARI_ERROR_CPU1PB | - SAFARI_ERROR_CPU0PS | SAFARI_ERROR_CPU0PB | - SAFARI_ERROR_CIQTO | - SAFARI_ERROR_LPQTO | SAFARI_ERROR_SFPQTO | - SAFARI_ERROR_UFPQTO | SAFARI_ERROR_APERR | - SAFARI_ERROR_BUSERR | SAFARI_ERROR_TIMEOUT | - SAFARI_ERROR_ILL))); + err_mask &= ~(BUS_ERROR_CPU1PS | BUS_ERROR_CPU1PB | + BUS_ERROR_CPU0PS | BUS_ERROR_CPU0PB); #endif - schizo_write(base + SCHIZO_SAFARI_IRQCTRL, - (SCHIZO_SAFIRQCTRL_EN | (SAFARI_ERROR_UNMAP))); -} - -/* We have to do the config space accesses by hand, thus... */ -#define PBM_BRIDGE_BUS 0x40 -#define PBM_BRIDGE_SUBORDINATE 0x41 -static void __init pbm_renumber(struct pci_pbm_info *pbm, u8 orig_busno) -{ - u8 *addr, busno; - int nbus; - - busno = pci_highest_busnum; - nbus = pbm->pci_last_busno - pbm->pci_first_busno; - - addr = schizo_pci_config_mkaddr(pbm, orig_busno, - 0, PBM_BRIDGE_BUS); - pci_config_write8(addr, busno); - addr = schizo_pci_config_mkaddr(pbm, busno, - 0, PBM_BRIDGE_SUBORDINATE); - pci_config_write8(addr, busno + nbus); - - pbm->pci_first_busno = busno; - pbm->pci_last_busno = busno + nbus; - pci_highest_busnum = busno + nbus + 1; + schizo_write(pbm_a->controller_regs + SCHIZO_SAFARI_ERRCTRL, + (SCHIZO_SAFERRCTRL_EN | err_mask)); - do { - pci_bus2pbm[busno++] = pbm; - } while (nbus--); -} - -/* We have to do the config space accesses by hand here since - * the pci_bus2pbm array is not ready yet. - */ -static void __init pbm_pci_bridge_renumber(struct pci_pbm_info *pbm, - u8 busno) -{ - u32 devfn, l, class; - u8 hdr_type; - int is_multi = 0; - - for(devfn = 0; devfn < 0xff; ++devfn) { - u32 *dwaddr; - u8 *baddr; - - if (PCI_FUNC(devfn) != 0 && is_multi == 0) - continue; - - /* Anything there? */ - dwaddr = schizo_pci_config_mkaddr(pbm, busno, devfn, PCI_VENDOR_ID); - l = 0xffffffff; - pci_config_read32(dwaddr, &l); - if (l == 0xffffffff || l == 0x00000000 || - l == 0x0000ffff || l == 0xffff0000) { - is_multi = 0; - continue; - } - - baddr = schizo_pci_config_mkaddr(pbm, busno, devfn, PCI_HEADER_TYPE); - pci_config_read8(baddr, &hdr_type); - if (PCI_FUNC(devfn) == 0) - is_multi = hdr_type & 0x80; - - dwaddr = schizo_pci_config_mkaddr(pbm, busno, devfn, PCI_CLASS_REVISION); - class = 0xffffffff; - pci_config_read32(dwaddr, &class); - if ((class >> 16) == PCI_CLASS_BRIDGE_PCI) { - u32 buses = 0xffffffff; - - dwaddr = schizo_pci_config_mkaddr(pbm, busno, devfn, - PCI_PRIMARY_BUS); - pci_config_read32(dwaddr, &buses); - pbm_pci_bridge_renumber(pbm, (buses >> 8) & 0xff); - buses &= 0xff000000; - pci_config_write32(dwaddr, buses); - } - } -} - -static void __init pbm_bridge_reconfigure(struct pci_controller_info *p) -{ - struct pci_pbm_info *pbm; - u8 *addr; - - /* Clear out primary/secondary/subordinate bus numbers on - * all PCI-to-PCI bridges under each PBM. The generic bus - * probing will fix them up. - */ - pbm_pci_bridge_renumber(&p->pbm_B, p->pbm_B.pci_first_busno); - pbm_pci_bridge_renumber(&p->pbm_A, p->pbm_A.pci_first_busno); - - /* Move PBM A out of the way. */ - pbm = &p->pbm_A; - addr = schizo_pci_config_mkaddr(pbm, pbm->pci_first_busno, - 0, PBM_BRIDGE_BUS); - pci_config_write8(addr, 0xff); - addr = schizo_pci_config_mkaddr(pbm, 0xff, - 0, PBM_BRIDGE_SUBORDINATE); - pci_config_write8(addr, 0xff); - - /* Now we can safely renumber both PBMs. */ - pbm_renumber(&p->pbm_B, p->pbm_B.pci_first_busno); - pbm_renumber(&p->pbm_A, 0xff); + schizo_write(pbm_a->controller_regs + SCHIZO_SAFARI_IRQCTRL, + (SCHIZO_SAFIRQCTRL_EN | (BUS_ERROR_UNMAP))); } static void __init pbm_config_busmastering(struct pci_pbm_info *pbm) @@ -1346,7 +1379,7 @@ struct pcidev_cookie *cookie = kmalloc(sizeof(*cookie), GFP_KERNEL); if (!cookie) { - prom_printf("SCHIZO: Critical allocation failure.\n"); + prom_printf("%s: Critical allocation failure.\n", pbm->name); prom_halt(); } @@ -1368,20 +1401,41 @@ pci_setup_busmastering(pbm, pbm->pci_bus); } -static void __init schizo_scan_bus(struct pci_controller_info *p) +static void __init __schizo_scan_bus(struct pci_controller_info *p, + int chip_type) { - pbm_bridge_reconfigure(p); + if (!p->pbm_B.prom_node || !p->pbm_A.prom_node) { + printk("PCI: Only one PCI bus module of controller found.\n"); + printk("PCI: Ignoring entire controller.\n"); + return; + } + pbm_config_busmastering(&p->pbm_B); - p->pbm_B.is_66mhz_capable = 0; + p->pbm_B.is_66mhz_capable = + prom_getbool(p->pbm_B.prom_node, "66mhz-capable"); pbm_config_busmastering(&p->pbm_A); - p->pbm_A.is_66mhz_capable = 1; + p->pbm_A.is_66mhz_capable = + prom_getbool(p->pbm_A.prom_node, "66mhz-capable"); pbm_scan_bus(p, &p->pbm_B); pbm_scan_bus(p, &p->pbm_A); /* After the PCI bus scan is complete, we can register * the error interrupt handlers. */ - schizo_register_error_handlers(p); + if (chip_type == PBM_CHIP_TYPE_TOMATILLO) + tomatillo_register_error_handlers(p); + else + schizo_register_error_handlers(p); +} + +static void __init schizo_scan_bus(struct pci_controller_info *p) +{ + __schizo_scan_bus(p, PBM_CHIP_TYPE_SCHIZO); +} + +static void __init tomatillo_scan_bus(struct pci_controller_info *p) +{ + __schizo_scan_bus(p, PBM_CHIP_TYPE_TOMATILLO); } static void __init schizo_base_address_update(struct pci_dev *pdev, int resource) @@ -1437,68 +1491,72 @@ res->end += root->start; } -/* Interrogate Safari match/mask registers to figure out where - * PCI MEM, I/O, and Config space are for this PCI bus module. +/* Use ranges property to determine where PCI MEM, I/O, and Config + * space are for this PCI bus module. */ +static void schizo_determine_mem_io_space(struct pci_pbm_info *pbm) +{ + int i, saw_cfg, saw_mem, saw_io; -#define SCHIZO_PCI_A_MEM_MATCH 0x00040UL -#define SCHIZO_PCI_A_MEM_MASK 0x00048UL -#define SCHIZO_PCI_A_IO_MATCH 0x00050UL -#define SCHIZO_PCI_A_IO_MASK 0x00058UL -#define SCHIZO_PCI_B_MEM_MATCH 0x00060UL -#define SCHIZO_PCI_B_MEM_MASK 0x00068UL -#define SCHIZO_PCI_B_IO_MATCH 0x00070UL -#define SCHIZO_PCI_B_IO_MASK 0x00078UL - -static void schizo_determine_mem_io_space(struct pci_pbm_info *pbm, - int is_pbm_a, unsigned long reg_base) -{ - u64 mem_match, mem_mask; - u64 io_match; - u64 a; - - if (is_pbm_a) { - mem_match = reg_base + SCHIZO_PCI_A_MEM_MATCH; - io_match = reg_base + SCHIZO_PCI_A_IO_MATCH; - } else { - mem_match = reg_base + SCHIZO_PCI_B_MEM_MATCH; - io_match = reg_base + SCHIZO_PCI_B_IO_MATCH; - } - mem_mask = mem_match + 0x8UL; + saw_cfg = saw_mem = saw_io = 0; + for (i = 0; i < pbm->num_pbm_ranges; i++) { + struct linux_prom_pci_ranges *pr = &pbm->pbm_ranges[i]; + unsigned long a; + int type; - a = schizo_read(mem_match) & ~0x8000000000000000UL; + type = (pr->child_phys_hi >> 24) & 0x3; + a = (((unsigned long)pr->parent_phys_hi << 32UL) | + ((unsigned long)pr->parent_phys_lo << 0UL)); - /* It should be 2GB in size but the decode is set for the full - * 4GB so we have to add the 2G by hand. - */ - pbm->mem_space.start = a; - pbm->mem_space.end = a + 0x80000000; - pbm->mem_space.flags = IORESOURCE_MEM; + switch (type) { + case 0: + /* PCI config space, 16MB */ + pbm->config_space = a; + saw_cfg = 1; + break; - /* This 32MB area is divided into two pieces. The first - * 16MB is Config space, the next 16MB is I/O space. - */ + case 1: + /* 16-bit IO space, 16MB */ + pbm->io_space.start = a; + pbm->io_space.end = a + ((16UL*1024UL*1024UL) - 1UL); + pbm->io_space.flags = IORESOURCE_IO; + saw_io = 1; + break; - a = schizo_read(io_match) & ~0x8000000000000000UL; - pbm->config_space = a; - printk("SCHIZO PBM%c: Local PCI config space at %016lx\n", - (is_pbm_a ? 'A' : 'B'), pbm->config_space); + case 2: + /* 32-bit MEM space, 2GB */ + pbm->mem_space.start = a; + pbm->mem_space.end = a + (0x80000000UL - 1UL); + pbm->mem_space.flags = IORESOURCE_MEM; + saw_mem = 1; + break; - a += (16UL * 1024UL * 1024UL); - pbm->io_space.start = a; - pbm->io_space.end = a + ((16UL * 1024UL * 1024UL) - 1UL); - pbm->io_space.flags = IORESOURCE_IO; + default: + break; + }; + } + + if (!saw_cfg || !saw_io || !saw_mem) { + prom_printf("%s: Fatal error, missing %s PBM range.\n", + pbm->name, + ((!saw_cfg ? + "CFG" : + (!saw_io ? + "IO" : "MEM")))); + prom_halt(); + } + + printk("%s: PCI CFG[%lx] IO[%lx] MEM[%lx]\n", + pbm->name, + pbm->config_space, + pbm->io_space.start, + pbm->mem_space.start); } static void __init pbm_register_toplevel_resources(struct pci_controller_info *p, struct pci_pbm_info *pbm) { - char *name = pbm->name; - - sprintf(name, "SCHIZO%d PBM%c", - p->index, - (pbm == &p->pbm_A ? 'A' : 'B')); - pbm->io_space.name = pbm->mem_space.name = name; + pbm->io_space.name = pbm->mem_space.name = pbm->name; request_resource(&ioport_resource, &pbm->io_space); request_resource(&iomem_resource, &pbm->mem_space); @@ -1506,40 +1564,29 @@ &pbm->mem_space); } -#define SCHIZO_STRBUF_CONTROL_A (SCHIZO_PBM_A_REGS_OFF + 0x02800UL) -#define SCHIZO_STRBUF_FLUSH_A (SCHIZO_PBM_A_REGS_OFF + 0x02808UL) -#define SCHIZO_STRBUF_FSYNC_A (SCHIZO_PBM_A_REGS_OFF + 0x02810UL) -#define SCHIZO_STRBUF_CTXFLUSH_A (SCHIZO_PBM_A_REGS_OFF + 0x02818UL) -#define SCHIZO_STRBUF_CTXMATCH_A (SCHIZO_PBM_A_REGS_OFF + 0x10000UL) - -#define SCHIZO_STRBUF_CONTROL_B (SCHIZO_PBM_B_REGS_OFF + 0x02800UL) -#define SCHIZO_STRBUF_FLUSH_B (SCHIZO_PBM_B_REGS_OFF + 0x02808UL) -#define SCHIZO_STRBUF_FSYNC_B (SCHIZO_PBM_B_REGS_OFF + 0x02810UL) -#define SCHIZO_STRBUF_CTXFLUSH_B (SCHIZO_PBM_B_REGS_OFF + 0x02818UL) -#define SCHIZO_STRBUF_CTXMATCH_B (SCHIZO_PBM_B_REGS_OFF + 0x10000UL) - -static void schizo_pbm_strbuf_init(struct pci_controller_info *p, - struct pci_pbm_info *pbm, - int is_pbm_a) +#define SCHIZO_STRBUF_CONTROL (0x02800UL) +#define SCHIZO_STRBUF_FLUSH (0x02808UL) +#define SCHIZO_STRBUF_FSYNC (0x02810UL) +#define SCHIZO_STRBUF_CTXFLUSH (0x02818UL) +#define SCHIZO_STRBUF_CTXMATCH (0x10000UL) + +static void schizo_pbm_strbuf_init(struct pci_pbm_info *pbm) { - unsigned long base = p->controller_regs; + unsigned long base = pbm->pbm_regs; u64 control; - /* SCHIZO has context flushing. */ - if (is_pbm_a) { - pbm->stc.strbuf_control = base + SCHIZO_STRBUF_CONTROL_A; - pbm->stc.strbuf_pflush = base + SCHIZO_STRBUF_FLUSH_A; - pbm->stc.strbuf_fsync = base + SCHIZO_STRBUF_FSYNC_A; - pbm->stc.strbuf_ctxflush = base + SCHIZO_STRBUF_CTXFLUSH_A; - pbm->stc.strbuf_ctxmatch_base = base + SCHIZO_STRBUF_CTXMATCH_A; - } else { - pbm->stc.strbuf_control = base + SCHIZO_STRBUF_CONTROL_B; - pbm->stc.strbuf_pflush = base + SCHIZO_STRBUF_FLUSH_B; - pbm->stc.strbuf_fsync = base + SCHIZO_STRBUF_FSYNC_B; - pbm->stc.strbuf_ctxflush = base + SCHIZO_STRBUF_CTXFLUSH_B; - pbm->stc.strbuf_ctxmatch_base = base + SCHIZO_STRBUF_CTXMATCH_B; + if (pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO) { + /* TOMATILLO lacks streaming cache. */ + return; } + /* SCHIZO has context flushing. */ + pbm->stc.strbuf_control = base + SCHIZO_STRBUF_CONTROL; + pbm->stc.strbuf_pflush = base + SCHIZO_STRBUF_FLUSH; + pbm->stc.strbuf_fsync = base + SCHIZO_STRBUF_FSYNC; + pbm->stc.strbuf_ctxflush = base + SCHIZO_STRBUF_CTXFLUSH; + pbm->stc.strbuf_ctxmatch_base = base + SCHIZO_STRBUF_CTXMATCH; + pbm->stc.strbuf_flushflag = (volatile unsigned long *) ((((unsigned long)&pbm->stc.__flushflag_buf[0]) + 63UL) @@ -1561,22 +1608,12 @@ pbm->stc.strbuf_enabled = 1; } -#define SCHIZO_IOMMU_CONTROL_A (SCHIZO_PBM_A_REGS_OFF + 0x00200UL) -#define SCHIZO_IOMMU_TSBBASE_A (SCHIZO_PBM_A_REGS_OFF + 0x00208UL) -#define SCHIZO_IOMMU_FLUSH_A (SCHIZO_PBM_A_REGS_OFF + 0x00210UL) -#define SCHIZO_IOMMU_CTXFLUSH_A (SCHIZO_PBM_A_REGS_OFF + 0x00218UL) -#define SCHIZO_IOMMU_TAG_A (SCHIZO_PBM_A_REGS_OFF + 0x0a580UL) -#define SCHIZO_IOMMU_DATA_A (SCHIZO_PBM_A_REGS_OFF + 0x0a600UL) -#define SCHIZO_IOMMU_CONTROL_B (SCHIZO_PBM_B_REGS_OFF + 0x00200UL) -#define SCHIZO_IOMMU_TSBBASE_B (SCHIZO_PBM_B_REGS_OFF + 0x00208UL) -#define SCHIZO_IOMMU_FLUSH_B (SCHIZO_PBM_B_REGS_OFF + 0x00210UL) -#define SCHIZO_IOMMU_CTXFLUSH_B (SCHIZO_PBM_B_REGS_OFF + 0x00218UL) -#define SCHIZO_IOMMU_TAG_B (SCHIZO_PBM_B_REGS_OFF + 0x0a580UL) -#define SCHIZO_IOMMU_DATA_B (SCHIZO_PBM_B_REGS_OFF + 0x0a600UL) - -static void schizo_pbm_iommu_init(struct pci_controller_info *p, - struct pci_pbm_info *pbm, - int is_pbm_a) +#define SCHIZO_IOMMU_CONTROL (0x00200UL) +#define SCHIZO_IOMMU_TSBBASE (0x00208UL) +#define SCHIZO_IOMMU_FLUSH (0x00210UL) +#define SCHIZO_IOMMU_CTXFLUSH (0x00218UL) + +static void schizo_pbm_iommu_init(struct pci_pbm_info *pbm) { struct pci_iommu *iommu = pbm->iommu; unsigned long tsbbase, i, tagbase, database; @@ -1587,22 +1624,15 @@ iommu->iommu_cur_ctx = 0; /* Register addresses, SCHIZO has iommu ctx flushing. */ - if (is_pbm_a) { - iommu->iommu_control = p->controller_regs + SCHIZO_IOMMU_CONTROL_A; - iommu->iommu_tsbbase = p->controller_regs + SCHIZO_IOMMU_TSBBASE_A; - iommu->iommu_flush = p->controller_regs + SCHIZO_IOMMU_FLUSH_A; - iommu->iommu_ctxflush = p->controller_regs + SCHIZO_IOMMU_CTXFLUSH_A; - } else { - iommu->iommu_control = p->controller_regs + SCHIZO_IOMMU_CONTROL_B; - iommu->iommu_tsbbase = p->controller_regs + SCHIZO_IOMMU_TSBBASE_B; - iommu->iommu_flush = p->controller_regs + SCHIZO_IOMMU_FLUSH_B; - iommu->iommu_ctxflush = p->controller_regs + SCHIZO_IOMMU_CTXFLUSH_B; - } + iommu->iommu_control = pbm->pbm_regs + SCHIZO_IOMMU_CONTROL; + iommu->iommu_tsbbase = pbm->pbm_regs + SCHIZO_IOMMU_TSBBASE; + iommu->iommu_flush = pbm->pbm_regs + SCHIZO_IOMMU_FLUSH; + iommu->iommu_ctxflush = pbm->pbm_regs + SCHIZO_IOMMU_CTXFLUSH; /* We use the main control/status register of SCHIZO as the write * completion register. */ - iommu->write_complete_reg = p->controller_regs + 0x10000UL; + iommu->write_complete_reg = pbm->controller_regs + 0x10000UL; /* * Invalidate TLB Entries. @@ -1611,13 +1641,11 @@ control |= SCHIZO_IOMMU_CTRL_DENAB; schizo_write(iommu->iommu_control, control); - if (is_pbm_a) - tagbase = SCHIZO_IOMMU_TAG_A, database = SCHIZO_IOMMU_DATA_A; - else - tagbase = SCHIZO_IOMMU_TAG_B, database = SCHIZO_IOMMU_DATA_B; + tagbase = SCHIZO_IOMMU_TAG, database = SCHIZO_IOMMU_DATA; + for(i = 0; i < 16; i++) { - schizo_write(p->controller_regs + tagbase + (i * 8UL), 0); - schizo_write(p->controller_regs + database + (i * 8UL), 0); + schizo_write(pbm->pbm_regs + tagbase + (i * 8UL), 0); + schizo_write(pbm->pbm_regs + database + (i * 8UL), 0); } /* Leave diag mode enabled for full-flushing done @@ -1630,7 +1658,7 @@ */ tsbbase = __get_free_pages(GFP_KERNEL, get_order(IO_TSB_SIZE)); if (!tsbbase) { - prom_printf("SCHIZO_IOMMU: Error, gfp(tsb) failed.\n"); + prom_printf("%s: Error, gfp(tsb) failed.\n", pbm->name); prom_halt(); } iommu->page_table = (iopte_t *)tsbbase; @@ -1656,24 +1684,179 @@ schizo_write(iommu->iommu_control, control); } -static void schizo_pbm_init(struct pci_controller_info *p, - int prom_node, int is_pbm_a) +#define SCHIZO_PCI_IRQ_RETRY (0x1a00UL) +#define SCHIZO_IRQ_RETRY_INF 0xffUL + +#define SCHIZO_PCI_DIAG (0x2020UL) +#define SCHIZO_PCIDIAG_D_BADECC (1UL << 10UL) /* Disable BAD ECC errors (Schizo) */ +#define SCHIZO_PCIDIAG_D_BYPASS (1UL << 9UL) /* Disable MMU bypass mode (Schizo/Tomatillo) */ +#define SCHIZO_PCIDIAG_D_TTO (1UL << 8UL) /* Disable TTO errors (Schizo/Tomatillo) */ +#define SCHIZO_PCIDIAG_D_RTRYARB (1UL << 7UL) /* Disable retry arbitration (Schizo) */ +#define SCHIZO_PCIDIAG_D_RETRY (1UL << 6UL) /* Disable retry limit (Schizo/Tomatillo) */ +#define SCHIZO_PCIDIAG_D_INTSYNC (1UL << 5UL) /* Disable interrupt/DMA synch (Schizo/Tomatillo) */ +#define SCHIZO_PCIDIAG_I_DMA_PARITY (1UL << 3UL) /* Invert DMA parity (Schizo/Tomatillo) */ +#define SCHIZO_PCIDIAG_I_PIOD_PARITY (1UL << 2UL) /* Invert PIO data parity (Schizo/Tomatillo) */ +#define SCHIZO_PCIDIAG_I_PIOA_PARITY (1UL << 1UL) /* Invert PIO address parity (Schizo/Tomatillo) */ + +#define TOMATILLO_PCI_IOC_CSR (0x2248UL) +#define TOMATILLO_IOC_PART_WPENAB 0x0000000000080000UL +#define TOMATILLO_IOC_RDMULT_PENAB 0x0000000000040000UL +#define TOMATILLO_IOC_RDONE_PENAB 0x0000000000020000UL +#define TOMATILLO_IOC_RDLINE_PENAB 0x0000000000010000UL +#define TOMATILLO_IOC_RDMULT_PLEN 0x000000000000c000UL +#define TOMATILLO_IOC_RDMULT_PLEN_SHIFT 14UL +#define TOMATILLO_IOC_RDONE_PLEN 0x0000000000003000UL +#define TOMATILLO_IOC_RDONE_PLEN_SHIFT 12UL +#define TOMATILLO_IOC_RDLINE_PLEN 0x0000000000000c00UL +#define TOMATILLO_IOC_RDLINE_PLEN_SHIFT 10UL +#define TOMATILLO_IOC_PREF_OFF 0x00000000000003f8UL +#define TOMATILLO_IOC_PREF_OFF_SHIFT 3UL +#define TOMATILLO_IOC_RDMULT_CPENAB 0x0000000000000004UL +#define TOMATILLO_IOC_RDONE_CPENAB 0x0000000000000002UL +#define TOMATILLO_IOC_RDLINE_CPENAB 0x0000000000000001UL + +#define TOMATILLO_PCI_IOC_TDIAG (0x2250UL) +#define TOMATILLO_PCI_IOC_DDIAG (0x2290UL) + +static void __init schizo_pbm_hw_init(struct pci_pbm_info *pbm) { + u64 tmp; + + /* Set IRQ retry to infinity. */ + schizo_write(pbm->pbm_regs + SCHIZO_PCI_IRQ_RETRY, + SCHIZO_IRQ_RETRY_INF); + + /* Enable arbiter for all PCI slots. Also, disable PCI interval + * timer so that DTO (Discard TimeOuts) are not reported because + * some Schizo revisions report them erroneously. + */ + tmp = schizo_read(pbm->pbm_regs + SCHIZO_PCI_CTRL); + if (pbm->chip_type == PBM_CHIP_TYPE_SCHIZO_PLUS && + pbm->chip_version == 0x5 && + pbm->chip_revision == 0x1) + tmp |= 0x0f; + else + tmp |= 0xff; + + if (pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO && + pbm->chip_version == 0x2) { + tmp &= ~SCHIZO_PCICTRL_PTO; + tmp |= 0x3UL << SCHIZO_PCICTRL_PTO_SHIFT; + } + + if (!prom_getbool(pbm->prom_node, "no-bus-parking")) + tmp |= SCHIZO_PCICTRL_PARK; + + if (pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO) + tmp |= SCHIZO_PCICTRL_MRM_PREF; + + schizo_write(pbm->pbm_regs + SCHIZO_PCI_CTRL, tmp); + + tmp = schizo_read(pbm->pbm_regs + SCHIZO_PCI_DIAG); + tmp &= ~(SCHIZO_PCIDIAG_D_RTRYARB | + SCHIZO_PCIDIAG_D_RETRY | + SCHIZO_PCIDIAG_D_INTSYNC); + schizo_write(pbm->pbm_regs + SCHIZO_PCI_DIAG, tmp); + + if (pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO) { + /* Clear prefetch lengths to workaround a bug in + * Jalapeno... + */ + tmp = (TOMATILLO_IOC_PART_WPENAB | + (1 << TOMATILLO_IOC_PREF_OFF_SHIFT) | + TOMATILLO_IOC_RDMULT_CPENAB | + TOMATILLO_IOC_RDONE_CPENAB | + TOMATILLO_IOC_RDLINE_CPENAB); + + schizo_write(pbm->pbm_regs + TOMATILLO_PCI_IOC_CSR, + tmp); + } +} + +static void __init schizo_pbm_init(struct pci_controller_info *p, + int prom_node, u32 portid, + int chip_type) +{ + struct linux_prom64_registers pr_regs[4]; unsigned int busrange[2]; struct pci_pbm_info *pbm; + const char *chipset_name; + int is_pbm_a; int err; + switch (chip_type) { + case PBM_CHIP_TYPE_TOMATILLO: + chipset_name = "TOMATILLO"; + break; + + case PBM_CHIP_TYPE_SCHIZO_PLUS: + chipset_name = "SCHIZO+"; + break; + + case PBM_CHIP_TYPE_SCHIZO: + default: + chipset_name = "SCHIZO"; + break; + }; + + /* For SCHIZO, three OBP regs: + * 1) PBM controller regs + * 2) Schizo front-end controller regs (same for both PBMs) + * 3) PBM PCI config space + * + * For TOMATILLO, four OBP regs: + * 1) PBM controller regs + * 2) Tomatillo front-end controller regs + * 3) PBM PCI config space + * 4) Ichip regs + */ + err = prom_getproperty(prom_node, "reg", + (char *)&pr_regs[0], + sizeof(pr_regs)); + if (err == 0 || err == -1) { + prom_printf("%s: Fatal error, no reg property.\n", + chipset_name); + prom_halt(); + } + + is_pbm_a = ((pr_regs[0].phys_addr & 0x00700000) == 0x00600000); + if (is_pbm_a) pbm = &p->pbm_A; else pbm = &p->pbm_B; - schizo_determine_mem_io_space(pbm, is_pbm_a, p->controller_regs); - pbm_register_toplevel_resources(p, pbm); - + pbm->portid = portid; pbm->parent = p; pbm->prom_node = prom_node; pbm->pci_first_slot = 1; + + pbm->chip_type = chip_type; + pbm->chip_version = + prom_getintdefault(prom_node, "version#", 0); + pbm->chip_revision = + prom_getintdefault(prom_node, "module-revision#", 0); + + pbm->pbm_regs = pr_regs[0].phys_addr; + pbm->controller_regs = pr_regs[1].phys_addr - 0x10000UL; + + sprintf(pbm->name, + (chip_type == PBM_CHIP_TYPE_TOMATILLO ? + "TOMATILLO%d PBM%c" : + "SCHIZO%d PBM%c"), + p->index, + (pbm == &p->pbm_A ? 'A' : 'B')); + + printk("%s: ver[%x:%x], portid %x, " + "cregs[%lx] pregs[%lx]\n", + pbm->name, + pbm->chip_version, pbm->chip_revision, + pbm->portid, + pbm->controller_regs, + pbm->pbm_regs); + + schizo_pbm_hw_init(pbm); + prom_getstring(prom_node, "name", pbm->prom_name, sizeof(pbm->prom_name)); @@ -1681,11 +1864,17 @@ err = prom_getproperty(prom_node, "ranges", (char *) pbm->pbm_ranges, sizeof(pbm->pbm_ranges)); - if (err != -1) - pbm->num_pbm_ranges = - (err / sizeof(struct linux_prom_pci_ranges)); - else - pbm->num_pbm_ranges = 0; + if (err == 0 || err == -1) { + prom_printf("%s: Fatal error, no ranges property.\n", + pbm->name); + prom_halt(); + } + + pbm->num_pbm_ranges = + (err / sizeof(struct linux_prom_pci_ranges)); + + schizo_determine_mem_io_space(pbm); + pbm_register_toplevel_resources(p, pbm); err = prom_getproperty(prom_node, "interrupt-map", (char *)pbm->pbm_intmap, @@ -1696,8 +1885,8 @@ (char *)&pbm->pbm_intmask, sizeof(pbm->pbm_intmask)); if (err == -1) { - prom_printf("SCHIZO-PBM: Fatal error, no " - "interrupt-map-mask.\n"); + prom_printf("%s: Fatal error, no " + "interrupt-map-mask.\n", pbm->name); prom_halt(); } } else { @@ -1709,91 +1898,51 @@ (char *)&busrange[0], sizeof(busrange)); if (err == 0 || err == -1) { - prom_printf("SCHIZO-PBM: Fatal error, no bus-range.\n"); + prom_printf("%s: Fatal error, no bus-range.\n", pbm->name); prom_halt(); } pbm->pci_first_busno = busrange[0]; pbm->pci_last_busno = busrange[1]; - schizo_pbm_iommu_init(p, pbm, is_pbm_a); - schizo_pbm_strbuf_init(p, pbm, is_pbm_a); + schizo_pbm_iommu_init(pbm); + schizo_pbm_strbuf_init(pbm); } -#define SCHIZO_PCIA_IRQ_RETRY (SCHIZO_PBM_A_REGS_OFF + 0x1a00UL) -#define SCHIZO_PCIB_IRQ_RETRY (SCHIZO_PBM_B_REGS_OFF + 0x1a00UL) -#define SCHIZO_IRQ_RETRY_INF 0xffUL - -#define SCHIZO_PCIA_DIAG (SCHIZO_PBM_A_REGS_OFF + 0x2020UL) -#define SCHIZO_PCIB_DIAG (SCHIZO_PBM_B_REGS_OFF + 0x2020UL) -#define SCHIZO_PCIDIAG_D_BADECC (1UL << 10UL) /* Disable BAD ECC errors */ -#define SCHIZO_PCIDIAG_D_BYPASS (1UL << 9UL) /* Disable MMU bypass mode */ -#define SCHIZO_PCIDIAG_D_TTO (1UL << 8UL) /* Disable TTO errors */ -#define SCHIZO_PCIDIAG_D_RTRYARB (1UL << 7UL) /* Disable retry arbitration */ -#define SCHIZO_PCIDIAG_D_RETRY (1UL << 6UL) /* Disable retry limit */ -#define SCHIZO_PCIDIAG_D_INTSYNC (1UL << 5UL) /* Disable interrupt/DMA synch */ -#define SCHIZO_PCIDIAG_I_DMA_PARITY (1UL << 3UL) /* Invert DMA parity */ -#define SCHIZO_PCIDIAG_I_PIOD_PARITY (1UL << 2UL) /* Invert PIO data parity */ -#define SCHIZO_PCIDIAG_I_PIOA_PARITY (1UL << 1U)L /* Invert PIO address parity */ - -static void schizo_controller_hwinit(struct pci_controller_info *p) +static inline int portid_compare(u32 x, u32 y, int chip_type) { - unsigned long pbm_a_base, pbm_b_base; - u64 tmp; - - pbm_a_base = p->controller_regs + SCHIZO_PBM_A_REGS_OFF; - pbm_b_base = p->controller_regs + SCHIZO_PBM_B_REGS_OFF; - - /* Set IRQ retry to infinity. */ - schizo_write(p->controller_regs + SCHIZO_PCIA_IRQ_RETRY, - SCHIZO_IRQ_RETRY_INF); - schizo_write(p->controller_regs + SCHIZO_PCIB_IRQ_RETRY, - SCHIZO_IRQ_RETRY_INF); - - /* Enable arbiter for all PCI slots. Also, disable PCI interval - * timer so that DTO (Discard TimeOuts) are not reported because - * some Schizo revisions report them erroneously. - */ - - tmp = schizo_read(p->controller_regs + SCHIZO_PCIA_CTRL); - tmp |= SCHIZO_PCICTRL_ARB; - tmp &= ~SCHIZO_PCICTRL_PTO; - schizo_write(p->controller_regs + SCHIZO_PCIA_CTRL, tmp); - - tmp = schizo_read(p->controller_regs + SCHIZO_PCIB_CTRL); - tmp |= SCHIZO_PCICTRL_ARB; - tmp &= ~SCHIZO_PCICTRL_PTO; - schizo_write(p->controller_regs + SCHIZO_PCIB_CTRL, tmp); - - /* Disable TTO error reporting (won't happen anyway since we - * disabled the PCI interval timer above) and retry arbitration - * (can cause hangs in some Schizo revisions). - */ - tmp = schizo_read(p->controller_regs + SCHIZO_PCIA_DIAG); - tmp |= (SCHIZO_PCIDIAG_D_TTO | SCHIZO_PCIDIAG_D_RTRYARB); - schizo_write(p->controller_regs + SCHIZO_PCIA_DIAG, tmp); - - tmp = schizo_read(p->controller_regs + SCHIZO_PCIB_DIAG); - tmp |= (SCHIZO_PCIDIAG_D_TTO | SCHIZO_PCIDIAG_D_RTRYARB); - schizo_write(p->controller_regs + SCHIZO_PCIB_DIAG, tmp); + if (chip_type == PBM_CHIP_TYPE_TOMATILLO) { + if (x == (y ^ 1)) + return 1; + return 0; + } + return (x == y); } -void __init schizo_init(int node, char *model_name) +static void __init __schizo_init(int node, char *model_name, int chip_type) { - struct linux_prom64_registers pr_regs[3]; struct pci_controller_info *p; struct pci_iommu *iommu; unsigned long flags; + int is_pbm_a; u32 portid; - int is_pbm_a, err; portid = prom_getintdefault(node, "portid", 0xff); spin_lock_irqsave(&pci_controller_lock, flags); for(p = pci_controller_root; p; p = p->next) { - if (p->portid == portid) { + struct pci_pbm_info *pbm; + + if (p->pbm_A.prom_node && p->pbm_B.prom_node) + continue; + + pbm = (p->pbm_A.prom_node ? + &p->pbm_A : + &p->pbm_B); + + if (portid_compare(pbm->portid, portid, chip_type)) { spin_unlock_irqrestore(&pci_controller_lock, flags); is_pbm_a = (p->pbm_A.prom_node == 0); - schizo_pbm_init(p, node, is_pbm_a); + schizo_pbm_init(p, node, portid, chip_type); return; } } @@ -1827,38 +1976,33 @@ pci_controller_root = p; spin_unlock_irqrestore(&pci_controller_lock, flags); - p->portid = portid; p->index = pci_num_controllers++; p->pbms_same_domain = 0; - p->scan_bus = schizo_scan_bus; + p->scan_bus = (chip_type == PBM_CHIP_TYPE_TOMATILLO ? + tomatillo_scan_bus : + schizo_scan_bus); p->irq_build = schizo_irq_build; p->base_address_update = schizo_base_address_update; p->resource_adjust = schizo_resource_adjust; p->pci_ops = &schizo_ops; - /* Three OBP regs: - * 1) PBM controller regs - * 2) Schizo front-end controller regs (same for both PBMs) - * 3) PBM PCI config space - */ - err = prom_getproperty(node, "reg", - (char *)&pr_regs[0], - sizeof(pr_regs)); - if (err == 0 || err == -1) { - prom_printf("SCHIZO: Fatal error, no reg property.\n"); - prom_halt(); - } - - p->controller_regs = pr_regs[1].phys_addr - 0x10000UL; - printk("PCI: Found SCHIZO, control regs at %016lx\n", - p->controller_regs); - /* Like PSYCHO we have a 2GB aligned area for memory space. */ pci_memspace_mask = 0x7fffffffUL; - /* Init core controller. */ - schizo_controller_hwinit(p); + schizo_pbm_init(p, node, portid, chip_type); +} - is_pbm_a = ((pr_regs[0].phys_addr & 0x00700000) == 0x00600000); - schizo_pbm_init(p, node, is_pbm_a); +void __init schizo_init(int node, char *model_name) +{ + __schizo_init(node, model_name, PBM_CHIP_TYPE_SCHIZO); +} + +void __init schizo_plus_init(int node, char *model_name) +{ + __schizo_init(node, model_name, PBM_CHIP_TYPE_SCHIZO_PLUS); +} + +void __init tomatillo_init(int node, char *model_name) +{ + __schizo_init(node, model_name, PBM_CHIP_TYPE_TOMATILLO); } diff -Nru a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c --- a/arch/sparc64/kernel/setup.c Sun Jul 27 10:13:43 2003 +++ b/arch/sparc64/kernel/setup.c Sun Jul 27 10:13:43 2003 @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include diff -Nru a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c --- a/arch/sparc64/kernel/smp.c Sun Jul 27 10:13:39 2003 +++ b/arch/sparc64/kernel/smp.c Sun Jul 27 10:13:39 2003 @@ -445,12 +445,19 @@ #endif static void cheetah_xcall_deliver(u64 data0, u64 data1, u64 data2, unsigned long mask) { - u64 pstate; - int nack_busy_id; + u64 pstate, ver; + int nack_busy_id, is_jalapeno; if (!mask) return; + /* Unfortunately, someone at Sun had the brilliant idea to make the + * busy/nack fields hard-coded by ITID number for this Ultra-III + * derivative processor. + */ + __asm__ ("rdpr %%ver, %0" : "=r" (ver)); + is_jalapeno = ((ver >> 32) == 0x003e0016); + __asm__ __volatile__("rdpr %%pstate, %0" : "=r" (pstate)); retry: @@ -476,12 +483,14 @@ if (work_mask & (1UL << i)) { u64 target = (i << 14) | 0x70; - target |= (nack_busy_id++ << 24); + if (!is_jalapeno) + target |= (nack_busy_id << 24); __asm__ __volatile__( "stxa %%g0, [%0] %1\n\t" "membar #Sync\n\t" : /* no outputs */ : "r" (target), "i" (ASI_INTR_W)); + nack_busy_id++; work_mask &= ~(1UL << i); if (!work_mask) break; @@ -531,8 +540,14 @@ */ for (i = 0; i < NR_CPUS; i++) { if (work_mask & (1UL << i)) { - if ((dispatch_stat & - (0x2 << this_busy_nack)) == 0) + u64 check_mask; + + if (is_jalapeno) + check_mask = (0x2UL << (2*i)); + else + check_mask = (0x2UL << + this_busy_nack); + if ((dispatch_stat & check_mask) == 0) mask &= ~(1UL << i); this_busy_nack += 2; work_mask &= ~(1UL << i); diff -Nru a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c --- a/arch/sparc64/kernel/sparc64_ksyms.c Sun Jul 27 10:13:50 2003 +++ b/arch/sparc64/kernel/sparc64_ksyms.c Sun Jul 27 10:13:50 2003 @@ -176,6 +176,8 @@ /* Atomic counter implementation. */ EXPORT_SYMBOL(__atomic_add); EXPORT_SYMBOL(__atomic_sub); +EXPORT_SYMBOL(__atomic64_add); +EXPORT_SYMBOL(__atomic64_sub); #ifdef CONFIG_SMP EXPORT_SYMBOL(atomic_dec_and_lock); #endif @@ -219,16 +221,16 @@ EXPORT_SYMBOL(sbus_dma_sync_single); EXPORT_SYMBOL(sbus_dma_sync_sg); #endif -#ifdef CONFIG_PCI -EXPORT_SYMBOL(ebus_chain); -EXPORT_SYMBOL(isa_chain); -EXPORT_SYMBOL(pci_memspace_mask); EXPORT_SYMBOL(outsb); EXPORT_SYMBOL(outsw); EXPORT_SYMBOL(outsl); EXPORT_SYMBOL(insb); EXPORT_SYMBOL(insw); EXPORT_SYMBOL(insl); +#ifdef CONFIG_PCI +EXPORT_SYMBOL(ebus_chain); +EXPORT_SYMBOL(isa_chain); +EXPORT_SYMBOL(pci_memspace_mask); EXPORT_SYMBOL(pci_alloc_consistent); EXPORT_SYMBOL(pci_free_consistent); EXPORT_SYMBOL(pci_map_single); diff -Nru a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c --- a/arch/sparc64/kernel/time.c Sun Jul 27 10:13:45 2003 +++ b/arch/sparc64/kernel/time.c Sun Jul 27 10:13:45 2003 @@ -41,6 +41,7 @@ #include #include #include +#include spinlock_t mostek_lock = SPIN_LOCK_UNLOCKED; spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED; @@ -449,7 +450,6 @@ return; { - extern int _stext; extern int rwlock_impl_begin, rwlock_impl_end; extern int atomic_impl_begin, atomic_impl_end; extern int __memcpy_begin, __memcpy_end; @@ -468,7 +468,7 @@ pc < (unsigned long) &__bitops_end)) pc = o7; - pc -= (unsigned long) &_stext; + pc -= (unsigned long) _stext; pc >>= prof_shift; if(pc >= prof_len) @@ -792,6 +792,7 @@ strcmp(model, "mk48t08") && strcmp(model, "mk48t59") && strcmp(model, "m5819") && + strcmp(model, "m5819p") && strcmp(model, "ds1287")) { if (cbus != NULL) { prom_printf("clock_probe: Central bus lacks timer chip.\n"); @@ -850,7 +851,8 @@ } if (!strcmp(model, "ds1287") || - !strcmp(model, "m5819")) { + !strcmp(model, "m5819") || + !strcmp(model, "m5819p")) { ds1287_regs = edev->resource[0].start; } else { mstk48t59_regs = edev->resource[0].start; @@ -870,7 +872,8 @@ prom_halt(); } if (!strcmp(model, "ds1287") || - !strcmp(model, "m5819")) { + !strcmp(model, "m5819") || + !strcmp(model, "m5819p")) { ds1287_regs = isadev->resource.start; } else { mstk48t59_regs = isadev->resource.start; diff -Nru a/arch/sparc64/kernel/unaligned.c b/arch/sparc64/kernel/unaligned.c --- a/arch/sparc64/kernel/unaligned.c Sun Jul 27 10:13:43 2003 +++ b/arch/sparc64/kernel/unaligned.c Sun Jul 27 10:13:43 2003 @@ -484,7 +484,9 @@ extern void do_fpother(struct pt_regs *regs); extern void do_privact(struct pt_regs *regs); -extern void data_access_exception(struct pt_regs *regs); +extern void data_access_exception(struct pt_regs *regs, + unsigned long sfsr, + unsigned long sfar); int handle_ldf_stq(u32 insn, struct pt_regs *regs) { @@ -527,14 +529,14 @@ break; } default: - data_access_exception(regs); + data_access_exception(regs, 0, addr); return 1; } if (put_user (first >> 32, (u32 *)addr) || __put_user ((u32)first, (u32 *)(addr + 4)) || __put_user (second >> 32, (u32 *)(addr + 8)) || __put_user ((u32)second, (u32 *)(addr + 12))) { - data_access_exception(regs); + data_access_exception(regs, 0, addr); return 1; } } else { @@ -547,7 +549,7 @@ do_privact(regs); return 1; } else if (asi > ASI_SNFL) { - data_access_exception(regs); + data_access_exception(regs, 0, addr); return 1; } switch (insn & 0x180000) { @@ -564,7 +566,7 @@ err |= __get_user (data[i], (u32 *)(addr + 4*i)); } if (err && !(asi & 0x2 /* NF */)) { - data_access_exception(regs); + data_access_exception(regs, 0, addr); return 1; } if (asi & 0x8) /* Little */ { @@ -667,7 +669,7 @@ *(u64 *)(f->regs + freg) = value; current_thread_info()->fpsaved[0] |= flag; } else { -daex: data_access_exception(regs); +daex: data_access_exception(regs, sfsr, sfar); return; } advance(regs); @@ -711,7 +713,7 @@ __put_user ((u32)value, (u32 *)(sfar + 4))) goto daex; } else { -daex: data_access_exception(regs); +daex: data_access_exception(regs, sfsr, sfar); return; } advance(regs); diff -Nru a/arch/sparc64/lib/PeeCeeI.c b/arch/sparc64/lib/PeeCeeI.c --- a/arch/sparc64/lib/PeeCeeI.c Sun Jul 27 10:13:49 2003 +++ b/arch/sparc64/lib/PeeCeeI.c Sun Jul 27 10:13:49 2003 @@ -4,10 +4,6 @@ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) */ -#include - -#ifdef CONFIG_PCI - #include #include @@ -239,4 +235,3 @@ } } -#endif /* CONFIG_PCI */ diff -Nru a/arch/sparc64/lib/atomic.S b/arch/sparc64/lib/atomic.S --- a/arch/sparc64/lib/atomic.S Sun Jul 27 10:13:51 2003 +++ b/arch/sparc64/lib/atomic.S Sun Jul 27 10:13:51 2003 @@ -33,4 +33,27 @@ membar #StoreLoad | #StoreStore retl sub %g7, %o0, %o0 + + .globl __atomic64_add +__atomic64_add: /* %o0 = increment, %o1 = atomic_ptr */ + ldx [%o1], %g5 + add %g5, %o0, %g7 + casx [%o1], %g5, %g7 + cmp %g5, %g7 + bne,pn %xcc, __atomic64_add + membar #StoreLoad | #StoreStore + retl + add %g7, %o0, %o0 + + .globl __atomic64_sub +__atomic64_sub: /* %o0 = increment, %o1 = atomic_ptr */ + ldx [%o1], %g5 + sub %g5, %o0, %g7 + casx [%o1], %g5, %g7 + cmp %g5, %g7 + bne,pn %xcc, __atomic64_sub + membar #StoreLoad | #StoreStore + retl + sub %g7, %o0, %o0 + atomic_impl_end: diff -Nru a/arch/sparc64/lib/debuglocks.c b/arch/sparc64/lib/debuglocks.c --- a/arch/sparc64/lib/debuglocks.c Sun Jul 27 10:13:47 2003 +++ b/arch/sparc64/lib/debuglocks.c Sun Jul 27 10:13:47 2003 @@ -296,13 +296,4 @@ } } -int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock) -{ - spin_lock(lock); - if (atomic_dec_and_test(atomic)) - return 1; - spin_unlock(lock); - return 0; -} - #endif /* CONFIG_SMP && CONFIG_DEBUG_SPINLOCK */ diff -Nru a/arch/sparc64/mm/fault.c b/arch/sparc64/mm/fault.c --- a/arch/sparc64/mm/fault.c Sun Jul 27 10:13:52 2003 +++ b/arch/sparc64/mm/fault.c Sun Jul 27 10:13:52 2003 @@ -26,6 +26,7 @@ #include #include #include +#include #define ELEMENTS(arr) (sizeof (arr)/sizeof (arr[0])) @@ -320,10 +321,9 @@ if (regs->tstate & TSTATE_PRIV) { unsigned long tpc = regs->tpc; - extern unsigned int _etext; /* Sanity check the PC. */ - if ((tpc >= KERNBASE && tpc < (unsigned long) &_etext) || + if ((tpc >= KERNBASE && tpc < (unsigned long) _etext) || (tpc >= MODULES_VADDR && tpc < MODULES_END)) { /* Valid, no problems... */ } else { diff -Nru a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c --- a/arch/sparc64/mm/init.c Sun Jul 27 10:13:44 2003 +++ b/arch/sparc64/mm/init.c Sun Jul 27 10:13:44 2003 @@ -35,6 +35,7 @@ #include #include #include +#include DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); @@ -48,16 +49,14 @@ unsigned long phys_base; unsigned long pfn_base; -enum ultra_tlb_layout tlb_type = spitfire; - /* get_new_mmu_context() uses "cache + 1". */ spinlock_t ctx_alloc_lock = SPIN_LOCK_UNLOCKED; unsigned long tlb_context_cache = CTX_FIRST_VERSION - 1; #define CTX_BMAP_SLOTS (1UL << (CTX_VERSION_SHIFT - 6)) unsigned long mmu_context_bmap[CTX_BMAP_SLOTS]; -/* References to section boundaries */ -extern char __init_begin, __init_end, _start, _end, etext, edata; +/* References to special section boundaries */ +extern char _start[], _end[]; /* Initial ramdisk setup */ extern unsigned int sparc_ramdisk_image; @@ -1333,7 +1332,7 @@ * image. The kernel is hard mapped below PAGE_OFFSET in a * 4MB locked TLB translation. */ - start_pfn = PAGE_ALIGN((unsigned long) &_end) - + start_pfn = PAGE_ALIGN((unsigned long) _end) - ((unsigned long) KERNBASE); /* Adjust up to the physical address where the kernel begins. */ @@ -1349,7 +1348,7 @@ #ifdef CONFIG_BLK_DEV_INITRD /* Now have to check initial ramdisk, so that bootmap does not overwrite it */ if (sparc_ramdisk_image) { - if (sparc_ramdisk_image >= (unsigned long)&_end - 2 * PAGE_SIZE) + if (sparc_ramdisk_image >= (unsigned long)_end - 2 * PAGE_SIZE) sparc_ramdisk_image -= KERNBASE; initrd_start = sparc_ramdisk_image + phys_base; initrd_end = initrd_start + sparc_ramdisk_size; @@ -1426,7 +1425,7 @@ set_bit(0, mmu_context_bmap); - real_end = (unsigned long)&_end; + real_end = (unsigned long)_end; if ((real_end > ((unsigned long)KERNBASE + 0x400000))) bigkernel = 1; #ifdef CONFIG_BLK_DEV_INITRD @@ -1718,7 +1717,7 @@ memset(sparc64_valid_addr_bitmap, 0, i << 3); addr = PAGE_OFFSET + phys_base; - last = PAGE_ALIGN((unsigned long)&_end) - + last = PAGE_ALIGN((unsigned long)_end) - ((unsigned long) KERNBASE); last += PAGE_OFFSET + phys_base; while (addr < last) { @@ -1745,11 +1744,11 @@ SetPageReserved(mem_map_zero); clear_page(page_address(mem_map_zero)); - codepages = (((unsigned long) &etext) - ((unsigned long)&_start)); + codepages = (((unsigned long) _etext) - ((unsigned long) _start)); codepages = PAGE_ALIGN(codepages) >> PAGE_SHIFT; - datapages = (((unsigned long) &edata) - ((unsigned long)&etext)); + datapages = (((unsigned long) _edata) - ((unsigned long) _etext)); datapages = PAGE_ALIGN(datapages) >> PAGE_SHIFT; - initpages = (((unsigned long) &__init_end) - ((unsigned long) &__init_begin)); + initpages = (((unsigned long) __init_end) - ((unsigned long) __init_begin)); initpages = PAGE_ALIGN(initpages) >> PAGE_SHIFT; #ifndef CONFIG_SMP @@ -1812,8 +1811,8 @@ /* * The init section is aligned to 8k in vmlinux.lds. Page align for >8k pagesizes. */ - addr = PAGE_ALIGN((unsigned long)(&__init_begin)); - initend = (unsigned long)(&__init_end) & PAGE_MASK; + addr = PAGE_ALIGN((unsigned long)(__init_begin)); + initend = (unsigned long)(__init_end) & PAGE_MASK; for (; addr < initend; addr += PAGE_SIZE) { unsigned long page; struct page *p; diff -Nru a/arch/sparc64/prom/bootstr.c b/arch/sparc64/prom/bootstr.c --- a/arch/sparc64/prom/bootstr.c Sun Jul 27 10:13:41 2003 +++ b/arch/sparc64/prom/bootstr.c Sun Jul 27 10:13:41 2003 @@ -15,16 +15,22 @@ */ #define BARG_LEN 256 -int bootstr_len = BARG_LEN; -static int bootstr_valid = 0; -static char bootstr_buf[BARG_LEN] = { 0 }; +struct { + int bootstr_len; + int bootstr_valid; + char bootstr_buf[BARG_LEN]; +} bootstr_info = { + .bootstr_len = BARG_LEN, +}; char * __init prom_getbootargs(void) { /* This check saves us from a panic when bootfd patches args. */ - if (bootstr_valid) return bootstr_buf; - prom_getstring(prom_chosen_node, "bootargs", bootstr_buf, BARG_LEN); - bootstr_valid = 1; - return bootstr_buf; + if (bootstr_info.bootstr_valid) + return bootstr_info.bootstr_buf; + prom_getstring(prom_chosen_node, "bootargs", + bootstr_info.bootstr_buf, BARG_LEN); + bootstr_info.bootstr_valid = 1; + return bootstr_info.bootstr_buf; } diff -Nru a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c --- a/arch/um/drivers/ubd_kern.c Sun Jul 27 10:13:45 2003 +++ b/arch/um/drivers/ubd_kern.c Sun Jul 27 10:13:45 2003 @@ -15,7 +15,6 @@ #include "linux/config.h" #include "linux/module.h" -#include "linux/blk.h" #include "linux/blkdev.h" #include "linux/hdreg.h" #include "linux/init.h" diff -Nru a/arch/v850/Kconfig b/arch/v850/Kconfig --- a/arch/v850/Kconfig Sun Jul 27 10:13:45 2003 +++ b/arch/v850/Kconfig Sun Jul 27 10:13:45 2003 @@ -48,20 +48,24 @@ choice prompt "Platform" default GDB + config V850E_SIM + bool "GDB" config RTE_CB_MA1 bool "RTE-V850E/MA1-CB" config RTE_CB_NB85E bool "RTE-V850E/NB85E-CB" - config V850E_SIM - bool "GDB" + config RTE_CB_ME2 + bool "RTE-V850E/ME2-CB" + config V850E_AS85EP1 + bool "AS85EP1" config V850E2_SIM85E2C bool "sim85e2c" + config V850E2_SIM85E2S + bool "sim85e2s" config V850E2_FPGA85E2C bool "NA85E2C-FPGA" config V850E2_ANNA bool "Anna" - config V850E_AS85EP1 - bool "AS85EP1" endchoice @@ -78,41 +82,32 @@ bool depends RTE_CB_MA1 default y - # Similarly for the RTE-V850E/MA1-CB - V850E/TEG + # Similarly for the RTE-V850E/NB85E-CB - V850E/TEG config V850E_TEG bool depends RTE_CB_NB85E default y - - # NB85E processor core - config V850E_NB85E + # ... and the RTE-V850E/ME2-CB - V850E/ME2 + config V850E_ME2 bool - depends V850E_MA1 || V850E_TEG + depends RTE_CB_ME2 default y - config V850E_MA1_HIGHRES_TIMER - bool "High resolution timer support" - depends V850E_MA1 - - #### V850E2 processor-specific config + #### sim85e2-specific config - # V850E2 processors - config V850E2 + config V850E2_SIM85E2 bool - depends V850E2_SIM85E2C || V850E2_FPGA85E2C || V850E2_ANNA + depends V850E2_SIM85E2C || V850E2_SIM85E2S default y - # Processors based on the NA85E2A core - config V850E2_NA85E2A - bool - depends V850E2_ANNA - default y - # Processors based on the NA85E2C core - config V850E2_NA85E2C + #### V850E2 processor-specific config + + # V850E2 processors + config V850E2 bool - depends V850E2_SIM85E2C || V850E2_FPGA85E2C + depends V850E2_SIM85E2 || V850E2_FPGA85E2C || V850E2_ANNA default y @@ -121,7 +116,7 @@ # Boards in the RTE-x-CB series config RTE_CB bool - depends RTE_CB_MA1 || RTE_CB_NB85E + depends RTE_CB_MA1 || RTE_CB_NB85E || RTE_CB_ME2 default y config RTE_CB_MULTI @@ -129,7 +124,7 @@ # RTE_CB_NB85E can either have multi ROM support or not, but # other platforms (currently only RTE_CB_MA1) require it. prompt "Multi monitor ROM support" if RTE_CB_NB85E - depends RTE_CB + depends RTE_CB_MA1 || RTE_CB_NB85E default y config RTE_CB_MULTI_DBTRAP @@ -156,14 +151,42 @@ # The only PCI bus we support is on the RTE-MOTHER-A board config PCI bool - default y if RTE_MB_A_PCI + default RTE_MB_A_PCI + + + #### Some feature-specific configs + + # Everything except for the GDB simulator uses the same interrupt controller + config V850E_INTC + bool + default !V850E_SIM + + # Everything except for the various simulators uses the "Timer D" unit + config V850E_TIMER_D + bool + default !V850E_SIM && !V850E2_SIM85E2 + + # Cache control used on some v850e1 processors + config V850E_CACHE + bool + default V850E_TEG || V850E_ME2 + + # Cache control used on v850e2 processors; I think this should + # actually apply to more, but currently only the SIM85E2S uses it + config V850E2_CACHE + bool + default V850E2_SIM85E2S + + config NO_CACHE + bool + default !V850E_CACHE && !V850E2_CACHE #### Misc config config ROM_KERNEL bool "Kernel in ROM" - depends V850E2_ANNA || (RTE_CB && !RTE_CB_MULTI) + depends V850E2_ANNA || V850E_AS85EP1 || RTE_CB_ME2 # Some platforms pre-zero memory, in which case the kernel doesn't need to config ZERO_BSS @@ -177,9 +200,12 @@ int default 8 if V850E2_SIM85E2C || V850E2_FPGA85E2C + config V850E_HIGHRES_TIMER + bool "High resolution timer support" + depends V850E_TIMER_D config TIME_BOOTUP bool "Time bootup" - depends V850E_MA1_HIGHRES_TIMER + depends V850E_HIGHRES_TIMER config RESET_GUARD bool "Reset Guard" @@ -241,6 +267,7 @@ default y config KCORE_ELF + bool default y source "fs/Kconfig.binfmt" diff -Nru a/arch/v850/Makefile b/arch/v850/Makefile --- a/arch/v850/Makefile Sun Jul 27 10:13:52 2003 +++ b/arch/v850/Makefile Sun Jul 27 10:13:52 2003 @@ -27,7 +27,6 @@ # some reason) LDFLAGS_MODULE += --unique=.gnu.linkonce.this_module -LDFLAGS_BLOB := -b binary --oformat elf32-little OBJCOPY_FLAGS_BLOB := -I binary -O elf32-little -B v850e diff -Nru a/arch/v850/README b/arch/v850/README --- a/arch/v850/README Sun Jul 27 10:13:52 2003 +++ b/arch/v850/README Sun Jul 27 10:13:52 2003 @@ -2,20 +2,30 @@ + The gdb v850e simulator (CONFIG_V850E_SIM). - + The Midas labs RTE-V850E/MA1-CB evaluation board (CONFIG_RTE_CB_MA1), - with untested support for the RTE-V850E/NB85E-CB board - (CONFIG_RTE_CB_NB85E). This support has only been tested when running - with the Multi-debugger monitor ROM (for the Green Hills Multi debugger). - The optional NEC Solution Gear RTE-MOTHER-A motherboard is also - supported, which allows PCI boards to be used (CONFIG_RTE_MB_A_PCI). + + The Midas labs RTE-V850E/MA1-CB and RTE-V850E/NB85E-CB evaluation boards + (CONFIG_RTE_CB_MA1 and CONFIG_RTE_CB_NB85E). This support has only been + tested when running with the Multi-debugger monitor ROM (for the Green + Hills Multi debugger). The optional NEC Solution Gear RTE-MOTHER-A + motherboard is also supported, which allows PCI boards to be used + (CONFIG_RTE_MB_A_PCI). - + The sim85e2c simulator, which is a verilog simulation of the V850E2 - NA85E2C cpu core (CONFIG_V850E2_SIM85E2C). + + The Midas labs RTE-V850E/ME2-CB evaluation board (CONFIG_RTE_CB_ME2). + This has only been tested using a kernel downloaded via an ICE connection + using the Multi debugger. Support for the RTE-MOTHER-A is present, but + hasn't been tested (unlike the other Midas labs cpu boards, the + RTE-V850E/ME2-CB includes an ethernet adaptor). + + + The NEC AS85EP1 V850E evaluation chip/board (CONFIG_V850E_AS85EP1). + + + The NEC `Anna' (board/chip) implementation of the V850E2 processor + (CONFIG_V850E2_ANNA). + + + The sim85e2c and sim85e2s simulators, which are verilog simulations of + the V850E2 NA85E2C/NA85E2S cpu cores (CONFIG_V850E2_SIM85E2C and + CONFIG_V850E2_SIM85E2S). + A FPGA implementation of the V850E2 NA85E2C cpu core (CONFIG_V850E2_FPGA85E2C). - - + The `Anna' (board/chip) implementation of the V850E2 processor. Porting to anything with a V850E/MA1 or MA2 processor should be simple. See the file and the files it includes for an example of diff -Nru a/arch/v850/kernel/Makefile b/arch/v850/kernel/Makefile --- a/arch/v850/kernel/Makefile Sun Jul 27 10:13:52 2003 +++ b/arch/v850/kernel/Makefile Sun Jul 27 10:13:52 2003 @@ -15,24 +15,26 @@ signal.o irq.o mach.o ptrace.o bug.o obj-$(CONFIG_MODULES) += module.o v850_ksyms.o # chip-specific code -obj-$(CONFIG_V850E_NB85E) += nb85e_intc.o -obj-$(CONFIG_V850E_MA1) += ma.o nb85e_utils.o nb85e_timer_d.o -obj-$(CONFIG_V850E_TEG) += teg.o nb85e_utils.o nb85e_cache.o \ - nb85e_timer_d.o -obj-$(CONFIG_V850E2_ANNA) += anna.o nb85e_intc.o nb85e_utils.o \ - nb85e_timer_d.o -obj-$(CONFIG_V850E_AS85EP1) += as85ep1.o nb85e_intc.o nb85e_utils.o \ - nb85e_timer_d.o +obj-$(CONFIG_V850E_MA1) += ma.o +obj-$(CONFIG_V850E_ME2) += me2.o +obj-$(CONFIG_V850E_TEG) += teg.o +obj-$(CONFIG_V850E_AS85EP1) += as85ep1.o +obj-$(CONFIG_V850E2_ANNA) += anna.o # platform-specific code obj-$(CONFIG_V850E_SIM) += sim.o simcons.o -obj-$(CONFIG_V850E2_SIM85E2C) += sim85e2c.o nb85e_intc.o memcons.o -obj-$(CONFIG_V850E2_FPGA85E2C) += fpga85e2c.o nb85e_intc.o memcons.o +obj-$(CONFIG_V850E2_SIM85E2) += sim85e2.o memcons.o +obj-$(CONFIG_V850E2_FPGA85E2C) += fpga85e2c.o memcons.o obj-$(CONFIG_RTE_CB) += rte_cb.o rte_cb_leds.o obj-$(CONFIG_RTE_CB_MA1) += rte_ma1_cb.o +obj-$(CONFIG_RTE_CB_ME2) += rte_me2_cb.o obj-$(CONFIG_RTE_CB_NB85E) += rte_nb85e_cb.o obj-$(CONFIG_RTE_CB_MULTI) += rte_cb_multi.o obj-$(CONFIG_RTE_MB_A_PCI) += rte_mb_a_pci.o obj-$(CONFIG_RTE_GBUS_INT) += gbus_int.o # feature-specific code -obj-$(CONFIG_V850E_MA1_HIGHRES_TIMER) += highres_timer.o +obj-$(CONFIG_V850E_INTC) += v850e_intc.o +obj-$(CONFIG_V850E_TIMER_D) += v850e_timer_d.o v850e_utils.o +obj-$(CONFIG_V850E_CACHE) += v850e_cache.o +obj-$(CONFIG_V850E2_CACHE) += v850e2_cache.o +obj-$(CONFIG_V850E_HIGHRES_TIMER) += highres_timer.o obj-$(CONFIG_PROC_FS) += procfs.o diff -Nru a/arch/v850/kernel/anna.c b/arch/v850/kernel/anna.c --- a/arch/v850/kernel/anna.c Sun Jul 27 10:13:45 2003 +++ b/arch/v850/kernel/anna.c Sun Jul 27 10:13:45 2003 @@ -1,8 +1,8 @@ /* * arch/v850/kernel/anna.c -- Anna V850E2 evaluation chip/board * - * Copyright (C) 2002 NEC Corporation - * Copyright (C) 2002 Miles Bader + * Copyright (C) 2002,03 NEC Electronics Corporation + * Copyright (C) 2002,03 Miles Bader * * This file is subject to the terms and conditions of the GNU General * Public License. See the file COPYING in the main directory of this @@ -21,8 +21,8 @@ #include #include #include -#include -#include +#include +#include #include "mach.h" @@ -41,32 +41,34 @@ void __init mach_early_init (void) { - ANNA_ILBEN = 0; - ANNA_CSC(0) = 0x402F; - ANNA_CSC(1) = 0x4000; - ANNA_BPC = 0; - ANNA_BSC = 0xAAAA; - ANNA_BEC = 0; - ANNA_BHC = 0xFFFF; /* icache all memory, dcache all */ - ANNA_BCT(0) = 0xB088; - ANNA_BCT(1) = 0x0008; - ANNA_DWC(0) = 0x0027; - ANNA_DWC(1) = 0; - ANNA_BCC = 0x0006; - ANNA_ASC = 0; - ANNA_LBS = 0x0089; - ANNA_SCR3 = 0x21A9; - ANNA_RFS3 = 0x8121; + ANNA_ILBEN = 0; - nb85e_intc_disable_irqs (); + V850E2_CSC(0) = 0x402F; + V850E2_CSC(1) = 0x4000; + V850E2_BPC = 0; + V850E2_BSC = 0xAAAA; + V850E2_BEC = 0; + +#if 0 + V850E2_BHC = 0xFFFF; /* icache all memory, dcache all */ +#else + V850E2_BHC = 0; /* cache no memory */ +#endif + V850E2_BCT(0) = 0xB088; + V850E2_BCT(1) = 0x0008; + V850E2_DWC(0) = 0x0027; + V850E2_DWC(1) = 0; + V850E2_BCC = 0x0006; + V850E2_ASC = 0; + V850E2_LBS = 0x0089; + V850E2_SCR(3) = 0x21A9; + V850E2_RFS(3) = 0x8121; + + v850e_intc_disable_irqs (); } void __init mach_setup (char **cmdline) { -#ifdef CONFIG_V850E_NB85E_UART_CONSOLE - nb85e_uart_cons_init (1); -#endif - ANNA_PORT_PM (LEDS_PORT) = 0; /* Make all LED pins output pins. */ mach_tick = anna_led_tick; } @@ -95,12 +97,12 @@ void __init mach_sched_init (struct irqaction *timer_action) { /* Start hardware timer. */ - nb85e_timer_d_configure (0, HZ); + v850e_timer_d_configure (0, HZ); /* Install timer interrupt handler. */ setup_irq (IRQ_INTCMD(0), timer_action); } -static struct nb85e_intc_irq_init irq_inits[] = { +static struct v850e_intc_irq_init irq_inits[] = { { "IRQ", 0, NUM_MACH_IRQS, 1, 7 }, { "PIN", IRQ_INTP(0), IRQ_INTP_NUM, 1, 4 }, { "CCC", IRQ_INTCCC(0), IRQ_INTCCC_NUM, 1, 5 }, @@ -118,7 +120,7 @@ void __init mach_init_irqs (void) { - nb85e_intc_init_irq_types (irq_inits, hw_itypes); + v850e_intc_init_irq_types (irq_inits, hw_itypes); } void machine_restart (char *__unused) diff -Nru a/arch/v850/kernel/as85ep1.c b/arch/v850/kernel/as85ep1.c --- a/arch/v850/kernel/as85ep1.c Sun Jul 27 10:13:52 2003 +++ b/arch/v850/kernel/as85ep1.c Sun Jul 27 10:13:52 2003 @@ -1,8 +1,8 @@ /* * arch/v850/kernel/as85ep1.c -- AS85EP1 V850E evaluation chip/board * - * Copyright (C) 2002 NEC Corporation - * Copyright (C) 2002 Miles Bader + * Copyright (C) 2002,03 NEC Electronics Corporation + * Copyright (C) 2002,03 Miles Bader * * This file is subject to the terms and conditions of the GNU General * Public License. See the file COPYING in the main directory of this @@ -21,8 +21,8 @@ #include #include #include -#include -#include +#include +#include #include "mach.h" @@ -90,20 +90,14 @@ AS85EP1_IRAMM = 0x0; /* $BFbB"L?Na(BRAM$B$O!V(Bread-mode$B!W$K$J$j$^$9(B */ #endif /* !CONFIG_ROM_KERNEL */ - nb85e_intc_disable_irqs (); + v850e_intc_disable_irqs (); } void __init mach_setup (char **cmdline) { -#ifdef CONFIG_V850E_NB85E_UART_CONSOLE - nb85e_uart_cons_init (1); -#endif - AS85EP1_PORT_PMC (LEDS_PORT) = 0; /* Make the LEDs port an I/O port. */ AS85EP1_PORT_PM (LEDS_PORT) = 0; /* Make all the bits output pins. */ mach_tick = as85ep1_led_tick; - - ROOT_DEV = MKDEV (BLKMEM_MAJOR, 0); } void __init mach_get_physical_ram (unsigned long *ram_start, @@ -137,21 +131,21 @@ root_fs_image_end - root_fs_image_start); } -void mach_gettimeofday (struct timeval *tv) +void mach_gettimeofday (struct timespec *tv) { tv->tv_sec = 0; - tv->tv_usec = 0; + tv->tv_nsec = 0; } void __init mach_sched_init (struct irqaction *timer_action) { /* Start hardware timer. */ - nb85e_timer_d_configure (0, HZ); + v850e_timer_d_configure (0, HZ); /* Install timer interrupt handler. */ setup_irq (IRQ_INTCMD(0), timer_action); } -static struct nb85e_intc_irq_init irq_inits[] = { +static struct v850e_intc_irq_init irq_inits[] = { { "IRQ", 0, NUM_MACH_IRQS, 1, 7 }, { "CCC", IRQ_INTCCC(0), IRQ_INTCCC_NUM, 1, 5 }, { "CMD", IRQ_INTCMD(0), IRQ_INTCMD_NUM, 1, 5 }, @@ -166,7 +160,7 @@ void __init mach_init_irqs (void) { - nb85e_intc_init_irq_types (irq_inits, hw_itypes); + v850e_intc_init_irq_types (irq_inits, hw_itypes); } void machine_restart (char *__unused) diff -Nru a/arch/v850/kernel/fpga85e2c.c b/arch/v850/kernel/fpga85e2c.c --- a/arch/v850/kernel/fpga85e2c.c Sun Jul 27 10:13:51 2003 +++ b/arch/v850/kernel/fpga85e2c.c Sun Jul 27 10:13:51 2003 @@ -2,8 +2,8 @@ * arch/v850/kernel/fpga85e2c.h -- Machine-dependent defs for * FPGA implementation of V850E2/NA85E2C * - * Copyright (C) 2002 NEC Corporation - * Copyright (C) 2002 Miles Bader + * Copyright (C) 2002,03 NEC Electronics Corporation + * Copyright (C) 2002,03 Miles Bader * * This file is subject to the terms and conditions of the GNU General * Public License. See the file COPYING in the main directory of this @@ -46,7 +46,7 @@ /* Set bus sizes: CS0 32-bit, CS1 16-bit, CS7 8-bit, everything else 32-bit. */ - BSC = 0x2AA6; + V850E2_BSC = 0x2AA6; for (i = 2; i <= 6; i++) CSDEV(i) = 0; /* 32 bit */ @@ -134,7 +134,7 @@ /* Interrupts */ -struct nb85e_intc_irq_init irq_inits[] = { +struct v850e_intc_irq_init irq_inits[] = { { "IRQ", 0, NUM_MACH_IRQS, 1, 7 }, { "RPU", IRQ_RPU(0), IRQ_RPU_NUM, 1, 6 }, { 0 } @@ -146,7 +146,7 @@ /* Initialize interrupts. */ void __init mach_init_irqs (void) { - nb85e_intc_init_irq_types (irq_inits, hw_itypes); + v850e_intc_init_irq_types (irq_inits, hw_itypes); } diff -Nru a/arch/v850/kernel/gbus_int.c b/arch/v850/kernel/gbus_int.c --- a/arch/v850/kernel/gbus_int.c Sun Jul 27 10:13:52 2003 +++ b/arch/v850/kernel/gbus_int.c Sun Jul 27 10:13:52 2003 @@ -113,9 +113,7 @@ /* Only pay attention to enabled interrupts. */ status &= enable; if (status) { - unsigned base_irq - = IRQ_GBUS_INT (w * GBUS_INT_BITS_PER_WORD); - irq = base_irq; + irq = IRQ_GBUS_INT (w * GBUS_INT_BITS_PER_WORD); do { /* There's an active interrupt in word W, find out which one, and call its @@ -247,7 +245,7 @@ /* First initialize the shared gint interrupts. */ for (i = 0; i < NUM_USED_GINTS; i++) { unsigned gint = used_gint[i].gint; - struct nb85e_intc_irq_init gint_irq_init[2]; + struct v850e_intc_irq_init gint_irq_init[2]; /* We initialize one GINT interrupt at a time. */ gint_irq_init[0].name = "GINT"; @@ -258,7 +256,7 @@ gint_irq_init[1].name = 0; /* Terminate the vector. */ - nb85e_intc_init_irq_types (gint_irq_init, gint_hw_itypes); + v850e_intc_init_irq_types (gint_irq_init, gint_hw_itypes); } /* Then the GBUS interrupts. */ diff -Nru a/arch/v850/kernel/head.S b/arch/v850/kernel/head.S --- a/arch/v850/kernel/head.S Sun Jul 27 10:13:41 2003 +++ b/arch/v850/kernel/head.S Sun Jul 27 10:13:41 2003 @@ -1,8 +1,8 @@ /* * arch/v850/kernel/head.S -- Lowest-level startup code * - * Copyright (C) 2001,02 NEC Corporation - * Copyright (C) 2001,02 Miles Bader + * Copyright (C) 2001,02,03 NEC Electronics Corporation + * Copyright (C) 2001,02,03 Miles Bader * * This file is subject to the terms and conditions of the GNU General * Public License. See the file COPYING in the main directory of this @@ -115,7 +115,14 @@ jarl CSYM(memset), lp #endif - // Start Linux kernel. + // What happens if the main kernel function returns (it shouldn't) mov hilo(CSYM(machine_halt)), lp - jr CSYM(start_kernel) + + // Start the linux kernel. We use an indirect jump to get extra + // range, because on some platforms this initial startup code + // (and the associated platform-specific code in mach_early_init) + // are located far away from the main kernel, e.g. so that they + // can initialize RAM first and copy the kernel or something. + mov hilo(CSYM(start_kernel)), r12 + jmp [r12] C_END(start) diff -Nru a/arch/v850/kernel/highres_timer.c b/arch/v850/kernel/highres_timer.c --- a/arch/v850/kernel/highres_timer.c Sun Jul 27 10:13:52 2003 +++ b/arch/v850/kernel/highres_timer.c Sun Jul 27 10:13:52 2003 @@ -1,8 +1,8 @@ /* * arch/v850/kernel/highres_timer.c -- High resolution timing routines * - * Copyright (C) 2001,02 NEC Corporation - * Copyright (C) 2001,02 Miles Bader + * Copyright (C) 2001,02,03 NEC Electronics Corporation + * Copyright (C) 2001,02,03 Miles Bader * * This file is subject to the terms and conditions of the GNU General * Public License. See the file COPYING in the main directory of this @@ -12,7 +12,7 @@ */ #include -#include +#include #include #define HIGHRES_TIMER_USEC_SHIFT 12 @@ -42,7 +42,7 @@ void highres_timer_reset (void) { - NB85E_TIMER_D_TMD (HIGHRES_TIMER_TIMER_D_UNIT) = 0; + V850E_TIMER_D_TMD (HIGHRES_TIMER_TIMER_D_UNIT) = 0; HIGHRES_TIMER_SLOW_TICKS = 0; } @@ -51,12 +51,12 @@ u32 fast_tick_rate; /* Start hardware timer. */ - nb85e_timer_d_configure (HIGHRES_TIMER_TIMER_D_UNIT, + v850e_timer_d_configure (HIGHRES_TIMER_TIMER_D_UNIT, HIGHRES_TIMER_SLOW_TICK_RATE); fast_tick_rate = - (NB85E_TIMER_D_BASE_FREQ - >> NB85E_TIMER_D_DIVLOG2 (HIGHRES_TIMER_TIMER_D_UNIT)); + (V850E_TIMER_D_BASE_FREQ + >> V850E_TIMER_D_DIVLOG2 (HIGHRES_TIMER_TIMER_D_UNIT)); /* The obvious way of calculating microseconds from fast ticks is to do: @@ -77,16 +77,16 @@ /* Enable the interrupt (which is hardwired to this use), and give it the highest priority. */ - NB85E_INTC_IC (IRQ_INTCMD (HIGHRES_TIMER_TIMER_D_UNIT)) = 0; + V850E_INTC_IC (IRQ_INTCMD (HIGHRES_TIMER_TIMER_D_UNIT)) = 0; } void highres_timer_stop (void) { /* Stop the timer. */ - NB85E_TIMER_D_TMCD (HIGHRES_TIMER_TIMER_D_UNIT) = - NB85E_TIMER_D_TMCD_CAE; + V850E_TIMER_D_TMCD (HIGHRES_TIMER_TIMER_D_UNIT) = + V850E_TIMER_D_TMCD_CAE; /* Disable its interrupt, just in case. */ - nb85e_intc_disable_irq (IRQ_INTCMD (HIGHRES_TIMER_TIMER_D_UNIT)); + v850e_intc_disable_irq (IRQ_INTCMD (HIGHRES_TIMER_TIMER_D_UNIT)); } inline void highres_timer_read_ticks (u32 *slow_ticks, u32 *fast_ticks) @@ -95,9 +95,9 @@ u32 fast_ticks_1, fast_ticks_2, _slow_ticks; local_irq_save (flags); - fast_ticks_1 = NB85E_TIMER_D_TMD (HIGHRES_TIMER_TIMER_D_UNIT); + fast_ticks_1 = V850E_TIMER_D_TMD (HIGHRES_TIMER_TIMER_D_UNIT); _slow_ticks = HIGHRES_TIMER_SLOW_TICKS; - fast_ticks_2 = NB85E_TIMER_D_TMD (HIGHRES_TIMER_TIMER_D_UNIT); + fast_ticks_2 = V850E_TIMER_D_TMD (HIGHRES_TIMER_TIMER_D_UNIT); local_irq_restore (flags); if (fast_ticks_2 < fast_ticks_1) diff -Nru a/arch/v850/kernel/intv.S b/arch/v850/kernel/intv.S --- a/arch/v850/kernel/intv.S Sun Jul 27 10:13:46 2003 +++ b/arch/v850/kernel/intv.S Sun Jul 27 10:13:46 2003 @@ -16,7 +16,7 @@ #include #include -#ifdef CONFIG_V850E_MA1_HIGHRES_TIMER +#ifdef CONFIG_V850E_HIGHRES_TIMER #include #endif @@ -59,7 +59,7 @@ .section .intv.mach, "ax" .org 0x0 -#if defined (CONFIG_V850E_MA1_HIGHRES_TIMER) && defined (IRQ_INTCMD) +#if defined (CONFIG_V850E_HIGHRES_TIMER) && defined (IRQ_INTCMD) /* Interrupts before the highres timer interrupt. */ .rept IRQ_INTCMD (HIGHRES_TIMER_TIMER_D_UNIT) diff -Nru a/arch/v850/kernel/ma.c b/arch/v850/kernel/ma.c --- a/arch/v850/kernel/ma.c Sun Jul 27 10:13:41 2003 +++ b/arch/v850/kernel/ma.c Sun Jul 27 10:13:41 2003 @@ -22,19 +22,19 @@ #include #include #include -#include +#include #include "mach.h" void __init mach_sched_init (struct irqaction *timer_action) { /* Start hardware timer. */ - nb85e_timer_d_configure (0, HZ); + v850e_timer_d_configure (0, HZ); /* Install timer interrupt handler. */ setup_irq (IRQ_INTCMD(0), timer_action); } -static struct nb85e_intc_irq_init irq_inits[] = { +static struct v850e_intc_irq_init irq_inits[] = { { "IRQ", 0, NUM_MACH_IRQS, 1, 7 }, { "CMD", IRQ_INTCMD(0), IRQ_INTCMD_NUM, 1, 5 }, { "DMA", IRQ_INTDMA(0), IRQ_INTDMA_NUM, 1, 2 }, @@ -51,7 +51,7 @@ /* Initialize MA chip interrupts. */ void __init ma_init_irqs (void) { - nb85e_intc_init_irq_types (irq_inits, hw_itypes); + v850e_intc_init_irq_types (irq_inits, hw_itypes); } /* Called before configuring an on-chip UART. */ diff -Nru a/arch/v850/kernel/me2.c b/arch/v850/kernel/me2.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/kernel/me2.c Sun Jul 27 10:13:53 2003 @@ -0,0 +1,74 @@ +/* + * arch/v850/kernel/me2.c -- V850E/ME2 chip-specific support + * + * Copyright (C) 2003 NEC Corporation + * Copyright (C) 2003 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "mach.h" + +void __init mach_sched_init (struct irqaction *timer_action) +{ + /* Start hardware timer. */ + v850e_timer_d_configure (0, HZ); + /* Install timer interrupt handler. */ + setup_irq (IRQ_INTCMD(0), timer_action); +} + +static struct v850e_intc_irq_init irq_inits[] = { + { "IRQ", 0, NUM_CPU_IRQS, 1, 7 }, + { "INTP", IRQ_INTP(0), IRQ_INTP_NUM, 1, 5 }, + { "CMD", IRQ_INTCMD(0), IRQ_INTCMD_NUM, 1, 3 }, + { "UBTIRE", IRQ_INTUBTIRE(0), IRQ_INTUBTIRE_NUM, 5, 4 }, + { "UBTIR", IRQ_INTUBTIR(0), IRQ_INTUBTIR_NUM, 5, 4 }, + { "UBTIT", IRQ_INTUBTIT(0), IRQ_INTUBTIT_NUM, 5, 4 }, + { "UBTIF", IRQ_INTUBTIF(0), IRQ_INTUBTIF_NUM, 5, 4 }, + { "UBTITO", IRQ_INTUBTITO(0), IRQ_INTUBTITO_NUM, 5, 4 }, + { 0 } +}; +#define NUM_IRQ_INITS ((sizeof irq_inits / sizeof irq_inits[0]) - 1) + +static struct hw_interrupt_type hw_itypes[NUM_IRQ_INITS]; + +/* Initialize V850E/ME2 chip interrupts. */ +void __init me2_init_irqs (void) +{ + v850e_intc_init_irq_types (irq_inits, hw_itypes); +} + +/* Called before configuring an on-chip UART. */ +void me2_uart_pre_configure (unsigned chan, unsigned cflags, unsigned baud) +{ + if (chan == 0) { + /* Specify that the relevent pins on the chip should do + serial I/O, not direct I/O. */ + ME2_PORT1_PMC |= 0xC; + /* Specify that we're using the UART, not the CSI device. */ + ME2_PORT1_PFC |= 0xC; + } else if (chan == 1) { + /* Specify that the relevent pins on the chip should do + serial I/O, not direct I/O. */ + ME2_PORT2_PMC |= 0x6; + /* Specify that we're using the UART, not the CSI device. */ + ME2_PORT2_PFC |= 0x6; + } +} diff -Nru a/arch/v850/kernel/nb85e_cache.c b/arch/v850/kernel/nb85e_cache.c --- a/arch/v850/kernel/nb85e_cache.c Sun Jul 27 10:13:49 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,178 +0,0 @@ -/* - * arch/v850/kernel/nb85e_cache.c -- Cache control for NB85E_CACHE212 and - * NB85E_CACHE213 cache memories - * - * Copyright (C) 2003 NEC Electronics Corporation - * Copyright (C) 2003 Miles Bader - * - * This file is subject to the terms and conditions of the GNU General - * Public License. See the file COPYING in the main directory of this - * archive for more details. - * - * Written by Miles Bader - */ - -#include -#include - -#define WAIT_UNTIL_CLEAR(value) while (value) {} - -/* Set caching params via the BHC and DCC registers. */ -void nb85e_cache_enable (u16 bhc, u16 dcc) -{ - unsigned long *r0_ram = (unsigned long *)R0_RAM_ADDR; - register u16 bhc_val asm ("r6") = bhc; - - /* Configure data-cache. */ - NB85E_CACHE_DCC = dcc; - - /* Configure caching for various memory regions by writing the BHC - register. The documentation says that an instruction _cannot_ - enable/disable caching for the memory region in which the - instruction itself exists; to work around this, we store - appropriate instructions into the on-chip RAM area (which is never - cached), and briefly jump there to do the work. */ - r0_ram[0] = 0xf0720760; /* st.h r0, 0xfffff072[r0] */ - r0_ram[1] = 0xf06a3760; /* st.h r6, 0xfffff06a[r0] */ - r0_ram[2] = 0x5640006b; /* jmp [r11] */ - asm ("mov hilo(1f), r11; jmp [%1]; 1:;" - :: "r" (bhc_val), "r" (R0_RAM_ADDR) : "r11"); -} - -static void clear_icache (void) -{ - /* 1. Read the instruction cache control register (ICC) and confirm - that bits 0 and 1 (TCLR0, TCLR1) are all cleared. */ - WAIT_UNTIL_CLEAR (NB85E_CACHE_ICC & 0x3); - - /* 2. Read the ICC register and confirm that bit 12 (LOCK0) is - cleared. Bit 13 of the ICC register is always cleared. */ - WAIT_UNTIL_CLEAR (NB85E_CACHE_ICC & 0x1000); - - /* 3. Set the TCLR0 and TCLR1 bits of the ICC register as follows, - when clearing way 0 and way 1 at the same time: - (a) Set the TCLR0 and TCLR1 bits. - (b) Read the TCLR0 and TCLR1 bits to confirm that these bits - are cleared. - (c) Perform (a) and (b) above again. */ - NB85E_CACHE_ICC |= 0x3; - WAIT_UNTIL_CLEAR (NB85E_CACHE_ICC & 0x3); - /* Do it again. */ - NB85E_CACHE_ICC |= 0x3; - WAIT_UNTIL_CLEAR (NB85E_CACHE_ICC & 0x3); -} - -/* Flush or clear (or both) the data cache, depending on the value of FLAGS; - the procedure is the same for both, just the control bits used differ (and - both may be performed simultaneously). */ -static void dcache_op (unsigned short flags) -{ - /* 1. Read the data cache control register (DCC) and confirm that bits - 0, 1, 4, and 5 (DC00, DC01, DC04, DC05) are all cleared. */ - WAIT_UNTIL_CLEAR (NB85E_CACHE_DCC & 0x33); - - /* 2. Clear DCC register bit 12 (DC12), bit 13 (DC13), or both - depending on the way for which tags are to be cleared. */ - NB85E_CACHE_DCC &= ~0xC000; - - /* 3. Set DCC register bit 0 (DC00), bit 1 (DC01) or both depending on - the way for which tags are to be cleared. - ... - Set DCC register bit 4 (DC04), bit 5 (DC05), or both depending - on the way to be data flushed. */ - NB85E_CACHE_DCC |= flags; - - /* 4. Read DCC register bit DC00, DC01 [DC04, DC05], or both depending - on the way for which tags were cleared [flushed] and confirm - that that bit is cleared. */ - WAIT_UNTIL_CLEAR (NB85E_CACHE_DCC & flags); -} - -/* Flushes the contents of the dcache to memory. */ -static inline void flush_dcache (void) -{ - /* We only need to do something if in write-back mode. */ - if (NB85E_CACHE_DCC & 0x0400) - dcache_op (0x30); -} - -/* Flushes the contents of the dcache to memory, and then clears it. */ -static inline void clear_dcache (void) -{ - /* We only need to do something if the dcache is enabled. */ - if (NB85E_CACHE_DCC & 0x0C00) - dcache_op (0x33); -} - -/* Clears the dcache without flushing to memory first. */ -static inline void clear_dcache_no_flush (void) -{ - /* We only need to do something if the dcache is enabled. */ - if (NB85E_CACHE_DCC & 0x0C00) - dcache_op (0x3); -} - -static inline void cache_exec_after_store (void) -{ - flush_dcache (); - clear_icache (); -} - - -/* Exported functions. */ - -void inline nb85e_cache_flush_all (void) -{ - clear_icache (); - clear_dcache (); -} - -void nb85e_cache_flush_mm (struct mm_struct *mm) -{ - /* nothing */ -} - -void nb85e_cache_flush_range (struct mm_struct *mm, - unsigned long start, unsigned long end) -{ - /* nothing */ -} - -void nb85e_cache_flush_page (struct vm_area_struct *vma, - unsigned long page_addr) -{ - /* nothing */ -} - -void nb85e_cache_flush_dcache_page (struct page *page) -{ - /* nothing */ -} - -void nb85e_cache_flush_icache (void) -{ - cache_exec_after_store (); -} - -void nb85e_cache_flush_icache_range (unsigned long start, unsigned long end) -{ - cache_exec_after_store (); -} - -void nb85e_cache_flush_icache_page (struct vm_area_struct *vma, - struct page *page) -{ - cache_exec_after_store (); -} - -void nb85e_cache_flush_icache_user_range (struct vm_area_struct *vma, - struct page *page, - unsigned long adr, int len) -{ - cache_exec_after_store (); -} - -void nb85e_cache_flush_sigtramp (unsigned long addr) -{ - cache_exec_after_store (); -} diff -Nru a/arch/v850/kernel/nb85e_intc.c b/arch/v850/kernel/nb85e_intc.c --- a/arch/v850/kernel/nb85e_intc.c Sun Jul 27 10:13:43 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,104 +0,0 @@ -/* - * arch/v850/kernel/nb85e_intc.c -- NB85E cpu core interrupt controller (INTC) - * - * Copyright (C) 2001,02,03 NEC Electronics Corporation - * Copyright (C) 2001,02,03 Miles Bader - * - * This file is subject to the terms and conditions of the GNU General - * Public License. See the file COPYING in the main directory of this - * archive for more details. - * - * Written by Miles Bader - */ - -#include -#include -#include - -#include - -static void irq_nop (unsigned irq) { } - -static unsigned nb85e_intc_irq_startup (unsigned irq) -{ - nb85e_intc_clear_pending_irq (irq); - nb85e_intc_enable_irq (irq); - return 0; -} - -static void nb85e_intc_end_irq (unsigned irq) -{ - unsigned long psw, temp; - - /* Clear the highest-level bit in the In-service priority register - (ISPR), to allow this interrupt (or another of the same or - lesser priority) to happen again. - - The `reti' instruction normally does this automatically when the - PSW bits EP and NP are zero, but we can't always rely on reti - being used consistently to return after an interrupt (another - process can be scheduled, for instance, which can delay the - associated reti for a long time, or this process may be being - single-stepped, which uses the `dbret' instruction to return - from the kernel). - - We also set the PSW EP bit, which prevents reti from also - trying to modify the ISPR itself. */ - - /* Get PSW and disable interrupts. */ - asm volatile ("stsr psw, %0; di" : "=r" (psw)); - /* We don't want to do anything for NMIs (they don't use the ISPR). */ - if (! (psw & 0xC0)) { - /* Transition to `trap' state, so that an eventual real - reti instruction won't modify the ISPR. */ - psw |= 0x40; - /* Fake an interrupt return, which automatically clears the - appropriate bit in the ISPR. */ - asm volatile ("mov hilo(1f), %0;" - "ldsr %0, eipc; ldsr %1, eipsw;" - "reti;" - "1:" - : "=&r" (temp) : "r" (psw)); - } -} - -/* Initialize HW_IRQ_TYPES for INTC-controlled irqs described in array - INITS (which is terminated by an entry with the name field == 0). */ -void __init nb85e_intc_init_irq_types (struct nb85e_intc_irq_init *inits, - struct hw_interrupt_type *hw_irq_types) -{ - struct nb85e_intc_irq_init *init; - for (init = inits; init->name; init++) { - unsigned i; - struct hw_interrupt_type *hwit = hw_irq_types++; - - hwit->typename = init->name; - - hwit->startup = nb85e_intc_irq_startup; - hwit->shutdown = nb85e_intc_disable_irq; - hwit->enable = nb85e_intc_enable_irq; - hwit->disable = nb85e_intc_disable_irq; - hwit->ack = irq_nop; - hwit->end = nb85e_intc_end_irq; - - /* Initialize kernel IRQ infrastructure for this interrupt. */ - init_irq_handlers(init->base, init->num, init->interval, hwit); - - /* Set the interrupt priorities. */ - for (i = 0; i < init->num; i++) { - unsigned irq = init->base + i * init->interval; - - /* If the interrupt is currently enabled (all - interrupts are initially disabled), then - assume whoever enabled it has set things up - properly, and avoid messing with it. */ - if (! nb85e_intc_irq_enabled (irq)) - /* This write also (1) disables the - interrupt, and (2) clears any pending - interrupts. */ - NB85E_INTC_IC (irq) - = (NB85E_INTC_IC_PR (init->priority) - | NB85E_INTC_IC_MK); - } - } -} diff -Nru a/arch/v850/kernel/nb85e_timer_d.c b/arch/v850/kernel/nb85e_timer_d.c --- a/arch/v850/kernel/nb85e_timer_d.c Sun Jul 27 10:13:45 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,54 +0,0 @@ -/* - * include/asm-v850/nb85e_timer_d.c -- `Timer D' component often used - * with the NB85E cpu core - * - * Copyright (C) 2001,02 NEC Corporation - * Copyright (C) 2001,02 Miles Bader - * - * This file is subject to the terms and conditions of the GNU General - * Public License. See the file COPYING in the main directory of this - * archive for more details. - * - * Written by Miles Bader - */ - -#include - -#include -#include - -/* Start interval timer TIMER (0-3). The timer will issue the - corresponding INTCMD interrupt RATE times per second. - This function does not enable the interrupt. */ -void nb85e_timer_d_configure (unsigned timer, unsigned rate) -{ - unsigned divlog2, count; - - /* Calculate params for timer. */ - if (! calc_counter_params ( - NB85E_TIMER_D_BASE_FREQ, rate, - NB85E_TIMER_D_TMCD_CS_MIN, NB85E_TIMER_D_TMCD_CS_MAX, 16, - &divlog2, &count)) - printk (KERN_WARNING - "Cannot find interval timer %d setting suitable" - " for rate of %dHz.\n" - "Using rate of %dHz instead.\n", - timer, rate, - (NB85E_TIMER_D_BASE_FREQ >> divlog2) >> 16); - - /* Do the actual hardware timer initialization: */ - - /* Enable timer. */ - NB85E_TIMER_D_TMCD(timer) = NB85E_TIMER_D_TMCD_CAE; - /* Set clock divider. */ - NB85E_TIMER_D_TMCD(timer) - = NB85E_TIMER_D_TMCD_CAE - | NB85E_TIMER_D_TMCD_CS(divlog2); - /* Set timer compare register. */ - NB85E_TIMER_D_CMD(timer) = count; - /* Start counting. */ - NB85E_TIMER_D_TMCD(timer) - = NB85E_TIMER_D_TMCD_CAE - | NB85E_TIMER_D_TMCD_CS(divlog2) - | NB85E_TIMER_D_TMCD_CE; -} diff -Nru a/arch/v850/kernel/nb85e_utils.c b/arch/v850/kernel/nb85e_utils.c --- a/arch/v850/kernel/nb85e_utils.c Sun Jul 27 10:13:42 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,65 +0,0 @@ -/* - * include/asm-v850/nb85e_utils.h -- Utility functions associated with - * the NB85E cpu core - * - * Copyright (C) 2001,02 NEC Corporation - * Copyright (C) 2001,02 Miles Bader - * - * This file is subject to the terms and conditions of the GNU General - * Public License. See the file COPYING in the main directory of this - * archive for more details. - * - * Written by Miles Bader - */ - -/* Note: these functions are often associated with the N85E cpu core, - but not always, which is why they're not in `nb85e.c'. */ - -#include - -/* Calculate counter clock-divider and count values to attain the - desired frequency RATE from the base frequency BASE_FREQ. The - counter is expected to have a clock-divider, which can divide the - system cpu clock by a power of two value from MIN_DIVLOG2 to - MAX_DIV_LOG2, and a word-size of COUNTER_SIZE bits (the counter - counts up and resets whenever it's equal to the compare register, - generating an interrupt or whatever when it does so). The returned - values are: *DIVLOG2 -- log2 of the desired clock divider and *COUNT - -- the counter compare value to use. Returns true if it was possible - to find a reasonable value, otherwise false (and the other return - values will be set to be as good as possible). */ -int calc_counter_params (unsigned long base_freq, - unsigned long rate, - unsigned min_divlog2, unsigned max_divlog2, - unsigned counter_size, - unsigned *divlog2, unsigned *count) -{ - unsigned _divlog2; - int ok = 0; - - /* Find the lowest clock divider setting that can represent RATE. */ - for (_divlog2 = min_divlog2; _divlog2 <= max_divlog2; _divlog2++) { - /* Minimum interrupt rate possible using this divider. */ - unsigned min_int_rate - = (base_freq >> _divlog2) >> counter_size; - - if (min_int_rate <= rate) { - /* This setting is the highest resolution - setting that's slow enough enough to attain - RATE interrupts per second, so use it. */ - ok = 1; - break; - } - } - - if (_divlog2 > max_divlog2) - /* Can't find correct setting. */ - _divlog2 = max_divlog2; - - if (divlog2) - *divlog2 = _divlog2; - if (count) - *count = ((base_freq >> _divlog2) + rate/2) / rate; - - return ok; -} diff -Nru a/arch/v850/kernel/process.c b/arch/v850/kernel/process.c --- a/arch/v850/kernel/process.c Sun Jul 27 10:13:42 2003 +++ b/arch/v850/kernel/process.c Sun Jul 27 10:13:42 2003 @@ -28,7 +28,6 @@ #include #include -#include #include extern void ret_from_fork (void); diff -Nru a/arch/v850/kernel/rte_cb.c b/arch/v850/kernel/rte_cb.c --- a/arch/v850/kernel/rte_cb.c Sun Jul 27 10:13:41 2003 +++ b/arch/v850/kernel/rte_cb.c Sun Jul 27 10:13:41 2003 @@ -17,7 +17,7 @@ #include #include -#include +#include #include "mach.h" @@ -34,7 +34,7 @@ void __init rte_cb_early_init (void) { - nb85e_intc_disable_irqs (); + v850e_intc_disable_irqs (); #ifdef CONFIG_RTE_CB_MULTI multi_init (); @@ -43,6 +43,7 @@ void __init mach_setup (char **cmdline) { +#ifdef CONFIG_RTE_MB_A_PCI /* Probe for Mother-A, and print a message if we find it. */ *(volatile unsigned long *)MB_A_SRAM_ADDR = 0xDEADBEEF; if (*(volatile unsigned long *)MB_A_SRAM_ADDR == 0xDEADBEEF) { @@ -52,23 +53,11 @@ " NEC SolutionGear/Midas lab" " RTE-MOTHER-A motherboard\n"); } - -#if defined (CONFIG_V850E_NB85E_UART_CONSOLE) && !defined (CONFIG_TIME_BOOTUP) - nb85e_uart_cons_init (0); -#endif +#endif /* CONFIG_RTE_MB_A_PCI */ mach_tick = led_tick; } -#ifdef CONFIG_TIME_BOOTUP -void initial_boot_done (void) -{ -#ifdef CONFIG_V850E_NB85E_UART_CONSOLE - nb85e_uart_cons_init (0); -#endif -} -#endif - void machine_restart (char *__unused) { #ifdef CONFIG_RESET_GUARD @@ -193,6 +182,7 @@ static struct hw_interrupt_type gbus_hw_itypes[NUM_GBUS_IRQ_INITS]; #endif /* CONFIG_RTE_GBUS_INT */ + void __init rte_cb_init_irqs (void) { diff -Nru a/arch/v850/kernel/rte_ma1_cb.c b/arch/v850/kernel/rte_ma1_cb.c --- a/arch/v850/kernel/rte_ma1_cb.c Sun Jul 27 10:13:50 2003 +++ b/arch/v850/kernel/rte_ma1_cb.c Sun Jul 27 10:13:50 2003 @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include "mach.h" @@ -89,14 +89,14 @@ rte_cb_init_irqs (); /* Use falling-edge-sensitivity for interrupts . */ - NB85E_TIMER_C_SESC (0) &= ~0xC; - NB85E_TIMER_C_SESC (1) &= ~0xF; + V850E_TIMER_C_SESC (0) &= ~0xC; + V850E_TIMER_C_SESC (1) &= ~0xF; /* INTP000-INTP011 are shared with `Timer C', so we have to set up Timer C to pass them through as raw interrupts. */ for (tc = 0; tc < 2; tc++) /* Turn on the timer. */ - NB85E_TIMER_C_TMCC0 (tc) |= NB85E_TIMER_C_TMCC0_CAE; + V850E_TIMER_C_TMCC0 (tc) |= V850E_TIMER_C_TMCC0_CAE; /* Make sure the relevant port0/port1 pins are assigned interrupt duty. We used INTP001-INTP011 (don't screw with diff -Nru a/arch/v850/kernel/rte_me2_cb.c b/arch/v850/kernel/rte_me2_cb.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/kernel/rte_me2_cb.c Sun Jul 27 10:13:53 2003 @@ -0,0 +1,308 @@ +/* + * arch/v850/kernel/rte_me2_cb.c -- Midas labs RTE-V850E/ME2-CB board + * + * Copyright (C) 2001,02,03 NEC Electronics Corporation + * Copyright (C) 2001,02,03 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mach.h" + +extern unsigned long *_intv_start; +extern unsigned long *_intv_end; + +/* LED access routines. */ +extern unsigned read_leds (int pos, char *buf, int len); +extern unsigned write_leds (int pos, const char *buf, int len); + + +/* SDRAM are almost contiguous (with a small hole in between; + see mach_reserve_bootmem for details), so just use both as one big area. */ +#define RAM_START SDRAM_ADDR +#define RAM_END (SDRAM_ADDR + SDRAM_SIZE) + + +void __init mach_get_physical_ram (unsigned long *ram_start, + unsigned long *ram_len) +{ + *ram_start = RAM_START; + *ram_len = RAM_END - RAM_START; +} + +void __init mach_reserve_bootmem () +{ + extern char _root_fs_image_start, _root_fs_image_end; + u32 root_fs_image_start = (u32)&_root_fs_image_start; + u32 root_fs_image_end = (u32)&_root_fs_image_end; + + /* Reserve the memory used by the root filesystem image if it's + in RAM. */ + if (root_fs_image_start >= RAM_START && root_fs_image_start < RAM_END) + reserve_bootmem (root_fs_image_start, + root_fs_image_end - root_fs_image_start); +} + +void mach_gettimeofday (struct timespec *tv) +{ + tv->tv_sec = 0; + tv->tv_nsec = 0; +} + +/* Called before configuring an on-chip UART. */ +void rte_me2_cb_uart_pre_configure (unsigned chan, + unsigned cflags, unsigned baud) +{ + /* The RTE-V850E/ME2-CB connects some general-purpose I/O + pins on the CPU to the RTS/CTS lines of UARTB channel 0's + serial connection. + I/O pins P21 and P22 are RTS and CTS respectively. */ + if (chan == 0) { + /* Put P21 & P22 in I/O port mode. */ + ME2_PORT2_PMC &= ~0x6; + /* Make P21 and output, and P22 an input. */ + ME2_PORT2_PM = (ME2_PORT2_PM & ~0xC) | 0x4; + } + + me2_uart_pre_configure (chan, cflags, baud); +} + +void __init mach_init_irqs (void) +{ + /* Initialize interrupts. */ + me2_init_irqs (); + rte_me2_cb_init_irqs (); +} + +#ifdef CONFIG_ROM_KERNEL +/* Initialization for kernel in ROM. */ +static inline rom_kernel_init (void) +{ + /* If the kernel is in ROM, we have to copy any initialized data + from ROM into RAM. */ + extern unsigned long _data_load_start, _sdata, _edata; + register unsigned long *src = &_data_load_start; + register unsigned long *dst = &_sdata, *end = &_edata; + + while (dst != end) + *dst++ = *src++; +} +#endif /* CONFIG_ROM_KERNEL */ + +static void install_interrupt_vectors (void) +{ + unsigned long *p1, *p2; + + ME2_IRAMM = 0x03; /* V850E/ME2 iRAM write mode */ + + /* vector copy to iRAM */ + p1 = (unsigned long *)0; /* v85x vector start */ + p2 = (unsigned long *)&_intv_start; + while (p2 < (unsigned long *)&_intv_end) + *p1++ = *p2++; + + ME2_IRAMM = 0x00; /* V850E/ME2 iRAM read mode */ +} + +/* CompactFlash */ + +static void cf_power_on (void) +{ + /* CF card detected? */ + if (CB_CF_STS0 & 0x0030) + return; + + CB_CF_REG0 = 0x0002; /* reest on */ + mdelay (10); + CB_CF_REG0 = 0x0003; /* power on */ + mdelay (10); + CB_CF_REG0 = 0x0001; /* reset off */ + mdelay (10); +} + +static void cf_power_off (void) +{ + CB_CF_REG0 = 0x0003; /* power on */ + mdelay (10); + CB_CF_REG0 = 0x0002; /* reest on */ + mdelay (10); +} + +void __init mach_early_init (void) +{ + install_interrupt_vectors (); + + /* CS1 SDRAM instruction cache enable */ + v850e_cache_enable (0x04, 0x03, 0); + + rte_cb_early_init (); + + /* CompactFlash power on */ + cf_power_on (); + +#if defined (CONFIG_ROM_KERNEL) + rom_kernel_init (); +#endif +} + + +/* RTE-V850E/ME2-CB Programmable Interrupt Controller. */ + +static struct cb_pic_irq_init cb_pic_irq_inits[] = { + { "CB_EXTTM0", IRQ_CB_EXTTM0, 1, 1, 6 }, + { "CB_EXTSIO", IRQ_CB_EXTSIO, 1, 1, 6 }, + { "CB_TOVER", IRQ_CB_TOVER, 1, 1, 6 }, + { "CB_GINT0", IRQ_CB_GINT0, 1, 1, 6 }, + { "CB_USB", IRQ_CB_USB, 1, 1, 6 }, + { "CB_LANC", IRQ_CB_LANC, 1, 1, 6 }, + { "CB_USB_VBUS_ON", IRQ_CB_USB_VBUS_ON, 1, 1, 6 }, + { "CB_USB_VBUS_OFF", IRQ_CB_USB_VBUS_OFF, 1, 1, 6 }, + { "CB_EXTTM1", IRQ_CB_EXTTM1, 1, 1, 6 }, + { "CB_EXTTM2", IRQ_CB_EXTTM2, 1, 1, 6 }, + { 0 } +}; +#define NUM_CB_PIC_IRQ_INITS \ + ((sizeof cb_pic_irq_inits / sizeof cb_pic_irq_inits[0]) - 1) + +static struct hw_interrupt_type cb_pic_hw_itypes[NUM_CB_PIC_IRQ_INITS]; +static unsigned char cb_pic_active_irqs = 0; + +void __init rte_me2_cb_init_irqs (void) +{ + cb_pic_init_irq_types (cb_pic_irq_inits, cb_pic_hw_itypes); + + /* Initalize on board PIC1 (not PIC0) enable */ + CB_PIC_INT0M = 0x0000; + CB_PIC_INT1M = 0x0000; + CB_PIC_INTR = 0x0000; + CB_PIC_INTEN |= CB_PIC_INT1EN; + + ME2_PORT2_PMC |= 0x08; /* INTP23/SCK1 mode */ + ME2_PORT2_PFC &= ~0x08; /* INTP23 mode */ + ME2_INTR(2) &= ~0x08; /* INTP23 falling-edge detect */ + ME2_INTF(2) &= ~0x08; /* " */ + + rte_cb_init_irqs (); /* gbus &c */ +} + + +/* Enable interrupt handling for interrupt IRQ. */ +void cb_pic_enable_irq (unsigned irq) +{ + CB_PIC_INT1M |= 1 << (irq - CB_PIC_BASE_IRQ); +} + +void cb_pic_disable_irq (unsigned irq) +{ + CB_PIC_INT1M &= ~(1 << (irq - CB_PIC_BASE_IRQ)); +} + +void cb_pic_shutdown_irq (unsigned irq) +{ + cb_pic_disable_irq (irq); + + if (--cb_pic_active_irqs == 0) + free_irq (IRQ_CB_PIC, 0); + + CB_PIC_INT1M &= ~(1 << (irq - CB_PIC_BASE_IRQ)); +} + +static void cb_pic_handle_irq (int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned status = CB_PIC_INTR; + unsigned enable = CB_PIC_INT1M; + + /* Only pay attention to enabled interrupts. */ + status &= enable; + + CB_PIC_INTEN &= ~CB_PIC_INT1EN; + + if (status) { + unsigned mask = 1; + + irq = CB_PIC_BASE_IRQ; + do { + /* There's an active interrupt, find out which one, + and call its handler. */ + while (! (status & mask)) { + irq++; + mask <<= 1; + } + status &= ~mask; + + CB_PIC_INTR = mask; + + /* Recursively call handle_irq to handle it. */ + handle_irq (irq, regs); + } while (status); + } + + CB_PIC_INTEN |= CB_PIC_INT1EN; +} + + +static void irq_nop (unsigned irq) { } + +static unsigned cb_pic_startup_irq (unsigned irq) +{ + int rval; + + if (cb_pic_active_irqs == 0) { + rval = request_irq (IRQ_CB_PIC, cb_pic_handle_irq, + SA_INTERRUPT, "cb_pic_handler", 0); + if (rval != 0) + return rval; + } + + cb_pic_active_irqs++; + + cb_pic_enable_irq (irq); + + return 0; +} + +/* Initialize HW_IRQ_TYPES for INTC-controlled irqs described in array + INITS (which is terminated by an entry with the name field == 0). */ +void __init cb_pic_init_irq_types (struct cb_pic_irq_init *inits, + struct hw_interrupt_type *hw_irq_types) +{ + struct cb_pic_irq_init *init; + for (init = inits; init->name; init++) { + struct hw_interrupt_type *hwit = hw_irq_types++; + + hwit->typename = init->name; + + hwit->startup = cb_pic_startup_irq; + hwit->shutdown = cb_pic_shutdown_irq; + hwit->enable = cb_pic_enable_irq; + hwit->disable = cb_pic_disable_irq; + hwit->ack = irq_nop; + hwit->end = irq_nop; + + /* Initialize kernel IRQ infrastructure for this interrupt. */ + init_irq_handlers(init->base, init->num, init->interval, hwit); + } +} diff -Nru a/arch/v850/kernel/rte_nb85e_cb.c b/arch/v850/kernel/rte_nb85e_cb.c --- a/arch/v850/kernel/rte_nb85e_cb.c Sun Jul 27 10:13:52 2003 +++ b/arch/v850/kernel/rte_nb85e_cb.c Sun Jul 27 10:13:52 2003 @@ -21,7 +21,7 @@ #include #include -#include +#include #include #include "mach.h" @@ -41,7 +41,7 @@ Unfortunately, the dcache seems to be buggy, so we only use the icache for now. */ - nb85e_cache_enable (0x0040 /* BHC */, 0x0000 /* DCC */); + v850e_cache_enable (0x0040 /*BHC*/, 0x0003 /*ICC*/, 0x0000 /*DCC*/); rte_cb_early_init (); } diff -Nru a/arch/v850/kernel/sim85e2.c b/arch/v850/kernel/sim85e2.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/kernel/sim85e2.c Sun Jul 27 10:13:46 2003 @@ -0,0 +1,211 @@ +/* + * arch/v850/kernel/sim85e2.c -- Machine-specific stuff for + * V850E2 RTL simulator + * + * Copyright (C) 2002,03 NEC Electronics Corporation + * Copyright (C) 2002,03 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "mach.h" + + +/* There are 4 possible areas we can use: + + IRAM (1MB) is fast for instruction fetches, but slow for data + DRAM (1020KB) is fast for data, but slow for instructions + ERAM is cached, so should be fast for both insns and data + SDRAM is external DRAM, similar to ERAM +*/ + +#define INIT_MEMC_FOR_SDRAM +#define USE_SDRAM_AREA +#define KERNEL_IN_SDRAM_AREA + +#define DCACHE_MODE V850E2_CACHE_BTSC_DCM_WT +/*#define DCACHE_MODE V850E2_CACHE_BTSC_DCM_WB_ALLOC*/ + +#ifdef USE_SDRAM_AREA +#define RAM_START SDRAM_ADDR +#define RAM_END (SDRAM_ADDR + SDRAM_SIZE) +#else +/* When we use DRAM, we need to account for the fact that the end of it is + used for R0_RAM. */ +#define RAM_START DRAM_ADDR +#define RAM_END R0_RAM_ADDR +#endif + + +extern void memcons_setup (void); + + +#ifdef KERNEL_IN_SDRAM_AREA +#define EARLY_INIT_SECTION_ATTR __attribute__ ((section (".early.text"))) +#else +#define EARLY_INIT_SECTION_ATTR __init +#endif + +void EARLY_INIT_SECTION_ATTR mach_early_init (void) +{ + extern int panic_timeout; + + /* The sim85e2 simulator tracks `undefined' values, so to make + debugging easier, we begin by zeroing out all otherwise + undefined registers. This is not strictly necessary. + + The registers we zero are: + Every GPR except: + stack-pointer (r3) + task-pointer (r16) + our return addr (r31) + Every system register (SPR) that we know about except for + the PSW (SPR 5), which we zero except for the + disable-interrupts bit. + */ + + /* GPRs */ + asm volatile (" mov r0, r1 ; mov r0, r2 "); + asm volatile ("mov r0, r4 ; mov r0, r5 ; mov r0, r6 ; mov r0, r7 "); + asm volatile ("mov r0, r8 ; mov r0, r9 ; mov r0, r10; mov r0, r11"); + asm volatile ("mov r0, r12; mov r0, r13; mov r0, r14; mov r0, r15"); + asm volatile (" mov r0, r17; mov r0, r18; mov r0, r19"); + asm volatile ("mov r0, r20; mov r0, r21; mov r0, r22; mov r0, r23"); + asm volatile ("mov r0, r24; mov r0, r25; mov r0, r26; mov r0, r27"); + asm volatile ("mov r0, r28; mov r0, r29; mov r0, r30"); + + /* SPRs */ + asm volatile ("ldsr r0, 0; ldsr r0, 1; ldsr r0, 2; ldsr r0, 3"); + asm volatile ("ldsr r0, 4"); + asm volatile ("addi 0x20, r0, r1; ldsr r1, 5"); /* PSW */ + asm volatile ("ldsr r0, 16; ldsr r0, 17; ldsr r0, 18; ldsr r0, 19"); + asm volatile ("ldsr r0, 20"); + + +#ifdef INIT_MEMC_FOR_SDRAM + /* Settings for SDRAM controller. */ + V850E2_VSWC = 0x0042; + V850E2_BSC = 0x9286; + V850E2_BCT(0) = 0xb000; /* was: 0 */ + V850E2_BCT(1) = 0x000b; + V850E2_ASC = 0; + V850E2_LBS = 0xa9aa; /* was: 0xaaaa */ + V850E2_LBC(0) = 0; + V850E2_LBC(1) = 0; /* was: 0x3 */ + V850E2_BCC = 0; + V850E2_RFS(4) = 0x800a; /* was: 0xf109 */ + V850E2_SCR(4) = 0x2091; /* was: 0x20a1 */ + V850E2_RFS(3) = 0x800c; + V850E2_SCR(3) = 0x20a1; + V850E2_DWC(0) = 0; + V850E2_DWC(1) = 0; +#endif + +#if 0 +#ifdef CONFIG_V850E2_SIM85E2S + /* Turn on the caches. */ + V850E2_CACHE_BTSC = V850E2_CACHE_BTSC_ICM | DCACHE_MODE; + V850E2_BHC = 0x1010; +#elif CONFIG_V850E2_SIM85E2C + V850E2_CACHE_BTSC |= (V850E2_CACHE_BTSC_ICM | V850E2_CACHE_BTSC_DCM0); + V850E2_BUSM_BHC = 0xFFFF; +#endif +#else + V850E2_BHC = 0; +#endif + + /* Don't stop the simulator at `halt' instructions. */ + SIM85E2_NOTHAL = 1; + + /* Ensure that the simulator halts on a panic, instead of going + into an infinite loop inside the panic function. */ + panic_timeout = -1; +} + +void __init mach_setup (char **cmdline) +{ + memcons_setup (); +} + +void mach_get_physical_ram (unsigned long *ram_start, unsigned long *ram_len) +{ + *ram_start = RAM_START; + *ram_len = RAM_END - RAM_START; +} + +void __init mach_reserve_bootmem () +{ + extern char _root_fs_image_start, _root_fs_image_end; + u32 root_fs_image_start = (u32)&_root_fs_image_start; + u32 root_fs_image_end = (u32)&_root_fs_image_end; + + /* Reserve the memory used by the root filesystem image if it's + in RAM. */ + if (root_fs_image_end > root_fs_image_start + && root_fs_image_start >= RAM_START + && root_fs_image_start < RAM_END) + reserve_bootmem (root_fs_image_start, + root_fs_image_end - root_fs_image_start); +} + +void __init mach_sched_init (struct irqaction *timer_action) +{ + /* The simulator actually cycles through all interrupts + periodically. We just pay attention to IRQ0, which gives us + 1/64 the rate of the periodic interrupts. */ + setup_irq (0, timer_action); +} + +void mach_gettimeofday (struct timespec *tv) +{ + tv->tv_sec = 0; + tv->tv_nsec = 0; +} + +/* Interrupts */ + +struct v850e_intc_irq_init irq_inits[] = { + { "IRQ", 0, NUM_MACH_IRQS, 1, 7 }, + { 0 } +}; +struct hw_interrupt_type hw_itypes[1]; + +/* Initialize interrupts. */ +void __init mach_init_irqs (void) +{ + v850e_intc_init_irq_types (irq_inits, hw_itypes); +} + + +void machine_halt (void) __attribute__ ((noreturn)); +void machine_halt (void) +{ + SIM85E2_SIMFIN = 0; /* Halt immediately. */ + for (;;) {} +} + +void machine_restart (char *__unused) +{ + machine_halt (); +} + +void machine_power_off (void) +{ + machine_halt (); +} diff -Nru a/arch/v850/kernel/sim85e2c.c b/arch/v850/kernel/sim85e2c.c --- a/arch/v850/kernel/sim85e2c.c Sun Jul 27 10:13:46 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,145 +0,0 @@ -/* - * arch/v850/kernel/sim85e2c.c -- Machine-specific stuff for - * V850E2 RTL simulator - * - * Copyright (C) 2002 NEC Corporation - * Copyright (C) 2002 Miles Bader - * - * This file is subject to the terms and conditions of the GNU General - * Public License. See the file COPYING in the main directory of this - * archive for more details. - * - * Written by Miles Bader - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "mach.h" - -extern void memcons_setup (void); - - -void __init mach_early_init (void) -{ - extern int panic_timeout; - - /* Don't stop the simulator at `halt' instructions. */ - NOTHAL = 1; - - /* The sim85e2c simulator tracks `undefined' values, so to make - debugging easier, we begin by zeroing out all otherwise - undefined registers. This is not strictly necessary. - - The registers we zero are: - Every GPR except: - stack-pointer (r3) - task-pointer (r16) - our return addr (r31) - Every system register (SPR) that we know about except for - the PSW (SPR 5), which we zero except for the - disable-interrupts bit. - */ - - /* GPRs */ - asm volatile (" mov r0, r1 ; mov r0, r2 "); - asm volatile ("mov r0, r4 ; mov r0, r5 ; mov r0, r6 ; mov r0, r7 "); - asm volatile ("mov r0, r8 ; mov r0, r9 ; mov r0, r10; mov r0, r11"); - asm volatile ("mov r0, r12; mov r0, r13; mov r0, r14; mov r0, r15"); - asm volatile (" mov r0, r17; mov r0, r18; mov r0, r19"); - asm volatile ("mov r0, r20; mov r0, r21; mov r0, r22; mov r0, r23"); - asm volatile ("mov r0, r24; mov r0, r25; mov r0, r26; mov r0, r27"); - asm volatile ("mov r0, r28; mov r0, r29; mov r0, r30"); - - /* SPRs */ - asm volatile ("ldsr r0, 0; ldsr r0, 1; ldsr r0, 2; ldsr r0, 3"); - asm volatile ("ldsr r0, 4"); - asm volatile ("addi 0x20, r0, r1; ldsr r1, 5"); /* PSW */ - asm volatile ("ldsr r0, 16; ldsr r0, 17; ldsr r0, 18; ldsr r0, 19"); - asm volatile ("ldsr r0, 20"); - - /* Turn on the caches. */ - NA85E2C_CACHE_BTSC - |= (NA85E2C_CACHE_BTSC_ICM | NA85E2C_CACHE_BTSC_DCM0); - NA85E2C_BUSM_BHC = 0xFFFF; - - /* Ensure that the simulator halts on a panic, instead of going - into an infinite loop inside the panic function. */ - panic_timeout = -1; -} - -void __init mach_setup (char **cmdline) -{ - memcons_setup (); -} - -void mach_get_physical_ram (unsigned long *ram_start, unsigned long *ram_len) -{ - /* There are 3 possible areas we can use: - IRAM (1MB) is fast for instruction fetches, but slow for data - DRAM (1020KB) is fast for data, but slow for instructions - ERAM is cached, so should be fast for both insns and data, - _but_ currently only supports write-through caching, so - writes are slow. - Since there's really no area that's good for general kernel - use, we use DRAM -- it won't be good for user programs - (which will be loaded into kernel allocated memory), but - currently we're more concerned with testing the kernel. */ - *ram_start = DRAM_ADDR; - *ram_len = R0_RAM_ADDR - DRAM_ADDR; -} - -void __init mach_sched_init (struct irqaction *timer_action) -{ - /* The simulator actually cycles through all interrupts - periodically. We just pay attention to IRQ0, which gives us - 1/64 the rate of the periodic interrupts. */ - setup_irq (0, timer_action); -} - -void mach_gettimeofday (struct timespec *tv) -{ - tv->tv_sec = 0; - tv->tv_nsec = 0; -} - -/* Interrupts */ - -struct nb85e_intc_irq_init irq_inits[] = { - { "IRQ", 0, NUM_MACH_IRQS, 1, 7 }, - { 0 } -}; -struct hw_interrupt_type hw_itypes[1]; - -/* Initialize interrupts. */ -void __init mach_init_irqs (void) -{ - nb85e_intc_init_irq_types (irq_inits, hw_itypes); -} - - -void machine_halt (void) __attribute__ ((noreturn)); -void machine_halt (void) -{ - SIMFIN = 0; /* Halt immediately. */ - for (;;) {} -} - -void machine_restart (char *__unused) -{ - machine_halt (); -} - -void machine_power_off (void) -{ - machine_halt (); -} diff -Nru a/arch/v850/kernel/teg.c b/arch/v850/kernel/teg.c --- a/arch/v850/kernel/teg.c Sun Jul 27 10:13:48 2003 +++ b/arch/v850/kernel/teg.c Sun Jul 27 10:13:48 2003 @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include "mach.h" @@ -31,12 +31,12 @@ /* Select timer interrupt instead of external pin. */ TEG_ISS |= 0x1; /* Start hardware timer. */ - nb85e_timer_d_configure (0, HZ); + v850e_timer_d_configure (0, HZ); /* Install timer interrupt handler. */ setup_irq (IRQ_INTCMD(0), timer_action); } -static struct nb85e_intc_irq_init irq_inits[] = { +static struct v850e_intc_irq_init irq_inits[] = { { "IRQ", 0, NUM_CPU_IRQS, 1, 7 }, { "CMD", IRQ_INTCMD(0), IRQ_INTCMD_NUM, 1, 5 }, { "SER", IRQ_INTSER(0), IRQ_INTSER_NUM, 1, 3 }, @@ -51,7 +51,7 @@ /* Initialize MA chip interrupts. */ void __init teg_init_irqs (void) { - nb85e_intc_init_irq_types (irq_inits, hw_itypes); + v850e_intc_init_irq_types (irq_inits, hw_itypes); } /* Called before configuring an on-chip UART. */ diff -Nru a/arch/v850/kernel/v850_ksyms.c b/arch/v850/kernel/v850_ksyms.c --- a/arch/v850/kernel/v850_ksyms.c Sun Jul 27 10:13:46 2003 +++ b/arch/v850/kernel/v850_ksyms.c Sun Jul 27 10:13:46 2003 @@ -9,7 +9,6 @@ #include #include -#include #include #include #include diff -Nru a/arch/v850/kernel/v850e2_cache.c b/arch/v850/kernel/v850e2_cache.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/kernel/v850e2_cache.c Sun Jul 27 10:13:53 2003 @@ -0,0 +1,127 @@ +/* + * arch/v850/kernel/v850e2_cache.c -- Cache control for V850E2 cache + * memories + * + * Copyright (C) 2003 NEC Electronics Corporation + * Copyright (C) 2003 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#include + +#include + +/* Cache operations we can do. The encoding corresponds directly to the + value we need to write into the COPR register. */ +enum cache_op { + OP_SYNC_IF_DIRTY = V850E2_CACHE_COPR_CFC(0), /* 000 */ + OP_SYNC_IF_VALID = V850E2_CACHE_COPR_CFC(1), /* 001 */ + OP_SYNC_IF_VALID_AND_CLEAR = V850E2_CACHE_COPR_CFC(3), /* 011 */ + OP_WAY_CLEAR = V850E2_CACHE_COPR_CFC(4), /* 100 */ + OP_FILL = V850E2_CACHE_COPR_CFC(5), /* 101 */ + OP_CLEAR = V850E2_CACHE_COPR_CFC(6), /* 110 */ + OP_CREATE_DIRTY = V850E2_CACHE_COPR_CFC(7) /* 111 */ +}; + +/* Which cache to use. This encoding also corresponds directly to the + value we need to write into the COPR register. */ +enum cache { + ICACHE = 0, + DCACHE = V850E2_CACHE_COPR_LBSL +}; + +/* Returns ADDR rounded down to the beginning of its cache-line. */ +#define CACHE_LINE_ADDR(addr) \ + ((addr) & ~(V850E2_CACHE_LINE_SIZE - 1)) +/* Returns END_ADDR rounded up to the `limit' of its cache-line. */ +#define CACHE_LINE_END_ADDR(end_addr) \ + CACHE_LINE_ADDR(end_addr + (V850E2_CACHE_LINE_SIZE - 1)) + + +/* Low-level cache ops. */ + +/* Apply cache-op OP to all entries in CACHE. */ +static inline void cache_op_all (enum cache_op op, enum cache cache) +{ + int cmd = op | cache | V850E2_CACHE_COPR_WSLE | V850E2_CACHE_COPR_STRT; + + if (op != OP_WAY_CLEAR) { + /* The WAY_CLEAR operation does the whole way, but other + ops take begin-index and count params; we just indicate + the entire cache. */ + V850E2_CACHE_CADL = 0; + V850E2_CACHE_CADH = 0; + V850E2_CACHE_CCNT = V850E2_CACHE_WAY_SIZE - 1; + } + + V850E2_CACHE_COPR = cmd | V850E2_CACHE_COPR_WSL(0); /* way 0 */ + V850E2_CACHE_COPR = cmd | V850E2_CACHE_COPR_WSL(1); /* way 1 */ + V850E2_CACHE_COPR = cmd | V850E2_CACHE_COPR_WSL(2); /* way 2 */ + V850E2_CACHE_COPR = cmd | V850E2_CACHE_COPR_WSL(3); /* way 3 */ +} + +/* Apply cache-op OP to all entries in CACHE covering addresses ADDR + through ADDR+LEN. */ +static inline void cache_op_range (enum cache_op op, u32 addr, u32 len, + enum cache cache) +{ + u32 start = CACHE_LINE_ADDR (addr); + u32 end = CACHE_LINE_END_ADDR (addr + len); + u32 num_lines = (end - start) >> V850E2_CACHE_LINE_SIZE_BITS; + + V850E2_CACHE_CADL = start & 0xFFFF; + V850E2_CACHE_CADH = start >> 16; + V850E2_CACHE_CCNT = num_lines - 1; + + V850E2_CACHE_COPR = op | cache | V850E2_CACHE_COPR_STRT; +} + + +/* High-level ops. */ + +static void cache_exec_after_store_all (void) +{ + cache_op_all (OP_SYNC_IF_DIRTY, DCACHE); + cache_op_all (OP_WAY_CLEAR, ICACHE); +} + +static void cache_exec_after_store_range (u32 start, u32 len) +{ + cache_op_range (OP_SYNC_IF_DIRTY, start, len, DCACHE); + cache_op_range (OP_CLEAR, start, len, ICACHE); +} + + +/* Exported functions. */ + +void flush_icache (void) +{ + cache_exec_after_store_all (); +} + +void flush_icache_range (unsigned long start, unsigned long end) +{ + cache_exec_after_store_range (start, end - start); +} + +void flush_icache_page (struct vm_area_struct *vma, struct page *page) +{ + cache_exec_after_store_range (page_to_virt (page), PAGE_SIZE); +} + +void flush_icache_user_range (struct vm_area_struct *vma, struct page *page, + unsigned long addr, int len) +{ + cache_exec_after_store_range (addr, len); +} + +void flush_cache_sigtramp (unsigned long addr) +{ + /* For the exact size, see signal.c, but 16 bytes should be enough. */ + cache_exec_after_store_range (addr, 16); +} diff -Nru a/arch/v850/kernel/v850e_cache.c b/arch/v850/kernel/v850e_cache.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/kernel/v850e_cache.c Sun Jul 27 10:13:49 2003 @@ -0,0 +1,173 @@ +/* + * arch/v850/kernel/v850e_cache.c -- Cache control for V850E cache memories + * + * Copyright (C) 2003 NEC Electronics Corporation + * Copyright (C) 2003 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +/* This file implements cache control for the rather simple cache used on + some V850E CPUs, specifically the NB85E/TEG CPU-core and the V850E/ME2 + CPU. V850E2 processors have their own (better) cache + implementation. */ + +#include +#include + +#define WAIT_UNTIL_CLEAR(value) while (value) {} + +/* Set caching params via the BHC and DCC registers. */ +void v850e_cache_enable (u16 bhc, u16 icc, u16 dcc) +{ + unsigned long *r0_ram = (unsigned long *)R0_RAM_ADDR; + register u16 bhc_val asm ("r6") = bhc; + + /* Read the instruction cache control register (ICC) and confirm + that bits 0 and 1 (TCLR0, TCLR1) are all cleared. */ + WAIT_UNTIL_CLEAR (V850E_CACHE_ICC & 0x3); + V850E_CACHE_ICC = icc; + +#ifdef V850E_CACHE_DCC + /* Configure data-cache. */ + V850E_CACHE_DCC = dcc; +#endif /* V850E_CACHE_DCC */ + + /* Configure caching for various memory regions by writing the BHC + register. The documentation says that an instruction _cannot_ + enable/disable caching for the memory region in which the + instruction itself exists; to work around this, we store + appropriate instructions into the on-chip RAM area (which is never + cached), and briefly jump there to do the work. */ +#ifdef V850E_CACHE_WRITE_IBS + *r0_ram++ = 0xf0720760; /* st.h r0, 0xfffff072[r0] */ +#endif + *r0_ram++ = 0xf06a3760; /* st.h r6, 0xfffff06a[r0] */ + *r0_ram = 0x5640006b; /* jmp [r11] */ + + asm ("mov hilo(1f), r11; jmp [%1]; 1:;" + :: "r" (bhc_val), "r" (R0_RAM_ADDR) : "r11"); +} + +static void clear_icache (void) +{ + /* 1. Read the instruction cache control register (ICC) and confirm + that bits 0 and 1 (TCLR0, TCLR1) are all cleared. */ + WAIT_UNTIL_CLEAR (V850E_CACHE_ICC & 0x3); + + /* 2. Read the ICC register and confirm that bit 12 (LOCK0) is + cleared. Bit 13 of the ICC register is always cleared. */ + WAIT_UNTIL_CLEAR (V850E_CACHE_ICC & 0x1000); + + /* 3. Set the TCLR0 and TCLR1 bits of the ICC register as follows, + when clearing way 0 and way 1 at the same time: + (a) Set the TCLR0 and TCLR1 bits. + (b) Read the TCLR0 and TCLR1 bits to confirm that these bits + are cleared. + (c) Perform (a) and (b) above again. */ + V850E_CACHE_ICC |= 0x3; + WAIT_UNTIL_CLEAR (V850E_CACHE_ICC & 0x3); + +#ifdef V850E_CACHE_REPEAT_ICC_WRITE + /* Do it again. */ + V850E_CACHE_ICC |= 0x3; + WAIT_UNTIL_CLEAR (V850E_CACHE_ICC & 0x3); +#endif +} + +#ifdef V850E_CACHE_DCC +/* Flush or clear (or both) the data cache, depending on the value of FLAGS; + the procedure is the same for both, just the control bits used differ (and + both may be performed simultaneously). */ +static void dcache_op (unsigned short flags) +{ + /* 1. Read the data cache control register (DCC) and confirm that bits + 0, 1, 4, and 5 (DC00, DC01, DC04, DC05) are all cleared. */ + WAIT_UNTIL_CLEAR (V850E_CACHE_DCC & 0x33); + + /* 2. Clear DCC register bit 12 (DC12), bit 13 (DC13), or both + depending on the way for which tags are to be cleared. */ + V850E_CACHE_DCC &= ~0xC000; + + /* 3. Set DCC register bit 0 (DC00), bit 1 (DC01) or both depending on + the way for which tags are to be cleared. + ... + Set DCC register bit 4 (DC04), bit 5 (DC05), or both depending + on the way to be data flushed. */ + V850E_CACHE_DCC |= flags; + + /* 4. Read DCC register bit DC00, DC01 [DC04, DC05], or both depending + on the way for which tags were cleared [flushed] and confirm + that that bit is cleared. */ + WAIT_UNTIL_CLEAR (V850E_CACHE_DCC & flags); +} +#endif /* V850E_CACHE_DCC */ + +/* Flushes the contents of the dcache to memory. */ +static inline void flush_dcache (void) +{ +#ifdef V850E_CACHE_DCC + /* We only need to do something if in write-back mode. */ + if (V850E_CACHE_DCC & 0x0400) + dcache_op (0x30); +#endif /* V850E_CACHE_DCC */ +} + +/* Flushes the contents of the dcache to memory, and then clears it. */ +static inline void clear_dcache (void) +{ +#ifdef V850E_CACHE_DCC + /* We only need to do something if the dcache is enabled. */ + if (V850E_CACHE_DCC & 0x0C00) + dcache_op (0x33); +#endif /* V850E_CACHE_DCC */ +} + +/* Clears the dcache without flushing to memory first. */ +static inline void clear_dcache_no_flush (void) +{ +#ifdef V850E_CACHE_DCC + /* We only need to do something if the dcache is enabled. */ + if (V850E_CACHE_DCC & 0x0C00) + dcache_op (0x3); +#endif /* V850E_CACHE_DCC */ +} + +static inline void cache_exec_after_store (void) +{ + flush_dcache (); + clear_icache (); +} + + +/* Exported functions. */ + +void flush_icache (void) +{ + cache_exec_after_store (); +} + +void flush_icache_range (unsigned long start, unsigned long end) +{ + cache_exec_after_store (); +} + +void flush_icache_page (struct vm_area_struct *vma, struct page *page) +{ + cache_exec_after_store (); +} + +void flush_icache_user_range (struct vm_area_struct *vma, struct page *page, + unsigned long adr, int len) +{ + cache_exec_after_store (); +} + +void flush_cache_sigtramp (unsigned long addr) +{ + cache_exec_after_store (); +} diff -Nru a/arch/v850/kernel/v850e_intc.c b/arch/v850/kernel/v850e_intc.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/kernel/v850e_intc.c Sun Jul 27 10:13:43 2003 @@ -0,0 +1,104 @@ +/* + * arch/v850/kernel/v850e_intc.c -- V850E interrupt controller (INTC) + * + * Copyright (C) 2001,02,03 NEC Electronics Corporation + * Copyright (C) 2001,02,03 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#include +#include +#include + +#include + +static void irq_nop (unsigned irq) { } + +static unsigned v850e_intc_irq_startup (unsigned irq) +{ + v850e_intc_clear_pending_irq (irq); + v850e_intc_enable_irq (irq); + return 0; +} + +static void v850e_intc_end_irq (unsigned irq) +{ + unsigned long psw, temp; + + /* Clear the highest-level bit in the In-service priority register + (ISPR), to allow this interrupt (or another of the same or + lesser priority) to happen again. + + The `reti' instruction normally does this automatically when the + PSW bits EP and NP are zero, but we can't always rely on reti + being used consistently to return after an interrupt (another + process can be scheduled, for instance, which can delay the + associated reti for a long time, or this process may be being + single-stepped, which uses the `dbret' instruction to return + from the kernel). + + We also set the PSW EP bit, which prevents reti from also + trying to modify the ISPR itself. */ + + /* Get PSW and disable interrupts. */ + asm volatile ("stsr psw, %0; di" : "=r" (psw)); + /* We don't want to do anything for NMIs (they don't use the ISPR). */ + if (! (psw & 0xC0)) { + /* Transition to `trap' state, so that an eventual real + reti instruction won't modify the ISPR. */ + psw |= 0x40; + /* Fake an interrupt return, which automatically clears the + appropriate bit in the ISPR. */ + asm volatile ("mov hilo(1f), %0;" + "ldsr %0, eipc; ldsr %1, eipsw;" + "reti;" + "1:" + : "=&r" (temp) : "r" (psw)); + } +} + +/* Initialize HW_IRQ_TYPES for INTC-controlled irqs described in array + INITS (which is terminated by an entry with the name field == 0). */ +void __init v850e_intc_init_irq_types (struct v850e_intc_irq_init *inits, + struct hw_interrupt_type *hw_irq_types) +{ + struct v850e_intc_irq_init *init; + for (init = inits; init->name; init++) { + unsigned i; + struct hw_interrupt_type *hwit = hw_irq_types++; + + hwit->typename = init->name; + + hwit->startup = v850e_intc_irq_startup; + hwit->shutdown = v850e_intc_disable_irq; + hwit->enable = v850e_intc_enable_irq; + hwit->disable = v850e_intc_disable_irq; + hwit->ack = irq_nop; + hwit->end = v850e_intc_end_irq; + + /* Initialize kernel IRQ infrastructure for this interrupt. */ + init_irq_handlers(init->base, init->num, init->interval, hwit); + + /* Set the interrupt priorities. */ + for (i = 0; i < init->num; i++) { + unsigned irq = init->base + i * init->interval; + + /* If the interrupt is currently enabled (all + interrupts are initially disabled), then + assume whoever enabled it has set things up + properly, and avoid messing with it. */ + if (! v850e_intc_irq_enabled (irq)) + /* This write also (1) disables the + interrupt, and (2) clears any pending + interrupts. */ + V850E_INTC_IC (irq) + = (V850E_INTC_IC_PR (init->priority) + | V850E_INTC_IC_MK); + } + } +} diff -Nru a/arch/v850/kernel/v850e_timer_d.c b/arch/v850/kernel/v850e_timer_d.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/kernel/v850e_timer_d.c Sun Jul 27 10:13:45 2003 @@ -0,0 +1,54 @@ +/* + * include/asm-v850/v850e_timer_d.c -- `Timer D' component often used + * with V850E CPUs + * + * Copyright (C) 2001,02,03 NEC Electronics Corporation + * Copyright (C) 2001,02,03 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#include + +#include +#include + +/* Start interval timer TIMER (0-3). The timer will issue the + corresponding INTCMD interrupt RATE times per second. + This function does not enable the interrupt. */ +void v850e_timer_d_configure (unsigned timer, unsigned rate) +{ + unsigned divlog2, count; + + /* Calculate params for timer. */ + if (! calc_counter_params ( + V850E_TIMER_D_BASE_FREQ, rate, + V850E_TIMER_D_TMCD_CS_MIN, V850E_TIMER_D_TMCD_CS_MAX, 16, + &divlog2, &count)) + printk (KERN_WARNING + "Cannot find interval timer %d setting suitable" + " for rate of %dHz.\n" + "Using rate of %dHz instead.\n", + timer, rate, + (V850E_TIMER_D_BASE_FREQ >> divlog2) >> 16); + + /* Do the actual hardware timer initialization: */ + + /* Enable timer. */ + V850E_TIMER_D_TMCD(timer) = V850E_TIMER_D_TMCD_CAE; + /* Set clock divider. */ + V850E_TIMER_D_TMCD(timer) + = V850E_TIMER_D_TMCD_CAE + | V850E_TIMER_D_TMCD_CS(divlog2); + /* Set timer compare register. */ + V850E_TIMER_D_CMD(timer) = count; + /* Start counting. */ + V850E_TIMER_D_TMCD(timer) + = V850E_TIMER_D_TMCD_CAE + | V850E_TIMER_D_TMCD_CS(divlog2) + | V850E_TIMER_D_TMCD_CE; +} diff -Nru a/arch/v850/kernel/v850e_utils.c b/arch/v850/kernel/v850e_utils.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/kernel/v850e_utils.c Sun Jul 27 10:13:42 2003 @@ -0,0 +1,62 @@ +/* + * include/asm-v850/v850e_utils.h -- Utility functions associated with + * V850E CPUs + * + * Copyright (C) 2001,02,03 NEC Electronics Corporation + * Copyright (C) 2001,02,03 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#include + +/* Calculate counter clock-divider and count values to attain the + desired frequency RATE from the base frequency BASE_FREQ. The + counter is expected to have a clock-divider, which can divide the + system cpu clock by a power of two value from MIN_DIVLOG2 to + MAX_DIV_LOG2, and a word-size of COUNTER_SIZE bits (the counter + counts up and resets whenever it's equal to the compare register, + generating an interrupt or whatever when it does so). The returned + values are: *DIVLOG2 -- log2 of the desired clock divider and *COUNT + -- the counter compare value to use. Returns true if it was possible + to find a reasonable value, otherwise false (and the other return + values will be set to be as good as possible). */ +int calc_counter_params (unsigned long base_freq, + unsigned long rate, + unsigned min_divlog2, unsigned max_divlog2, + unsigned counter_size, + unsigned *divlog2, unsigned *count) +{ + unsigned _divlog2; + int ok = 0; + + /* Find the lowest clock divider setting that can represent RATE. */ + for (_divlog2 = min_divlog2; _divlog2 <= max_divlog2; _divlog2++) { + /* Minimum interrupt rate possible using this divider. */ + unsigned min_int_rate + = (base_freq >> _divlog2) >> counter_size; + + if (min_int_rate <= rate) { + /* This setting is the highest resolution + setting that's slow enough enough to attain + RATE interrupts per second, so use it. */ + ok = 1; + break; + } + } + + if (_divlog2 > max_divlog2) + /* Can't find correct setting. */ + _divlog2 = max_divlog2; + + if (divlog2) + *divlog2 = _divlog2; + if (count) + *count = ((base_freq >> _divlog2) + rate/2) / rate; + + return ok; +} diff -Nru a/arch/v850/rte_me2_cb.ld b/arch/v850/rte_me2_cb.ld --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/rte_me2_cb.ld Sun Jul 27 10:13:53 2003 @@ -0,0 +1,30 @@ +/* Linker script for the Midas labs RTE-V850E/ME2-CB evaluation board + (CONFIG_RTE_CB_ME2), with kernel in SDRAM. */ + +MEMORY { + /* 128Kbyte of IRAM */ + IRAM : ORIGIN = 0x00000000, LENGTH = 0x00020000 + + /* 32MB of SDRAM. */ + SDRAM : ORIGIN = 0x00800000, LENGTH = 0x02000000 +} + +#define KRAM SDRAM + +SECTIONS { + .text : { + __kram_start = . ; + TEXT_CONTENTS + INTV_CONTENTS /* copy to iRAM (0x0-0x620) */ + } > KRAM + + .data : { + DATA_CONTENTS + BSS_CONTENTS + RAMK_INIT_CONTENTS + __kram_end = . ; + BOOTMAP_CONTENTS + } > KRAM + + .root ALIGN (4096) : { ROOT_FS_CONTENTS } > SDRAM +} diff -Nru a/arch/v850/sim85e2.ld b/arch/v850/sim85e2.ld --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/sim85e2.ld Sun Jul 27 10:13:52 2003 @@ -0,0 +1,44 @@ +/* Linker script for the sim85e2c simulator, which is a verilog simulation of + the V850E2 NA85E2C cpu core (CONFIG_V850E2_SIM85E2C). */ + +MEMORY { + /* 1MB of `instruction RAM', starting at 0. + Instruction fetches are much faster from IRAM than from DRAM. + This should match IRAM_ADDR in "include/asm-v580/sim85e2c.h". */ + IRAM : ORIGIN = 0x00000000, LENGTH = 0x00100000 + + /* 1MB of `data RAM', below and contiguous with the I/O space. + Data fetches are much faster from DRAM than from IRAM. + This should match DRAM_ADDR in "include/asm-v580/sim85e2c.h". */ + DRAM : ORIGIN = 0xfff00000, LENGTH = 0x000ff000 + /* We have to load DRAM at a mirror-address of 0x1ff00000, + because the simulator's preprocessing script isn't smart + enough to deal with the above LMA. */ + DRAM_LOAD : ORIGIN = 0x1ff00000, LENGTH = 0x000ff000 + + /* `external ram' (CS1 area), comes after IRAM. + This should match ERAM_ADDR in "include/asm-v580/sim85e2c.h". */ + ERAM : ORIGIN = 0x00100000, LENGTH = 0x07f00000 + + /* Dynamic RAM; uses memory controller. */ + /* SDRAM : ORIGIN = 0x10000000, LENGTH = 0x01000000 */ + SDRAM : ORIGIN = 0x10000000, LENGTH = 0x00200000/*use 2MB*/ +} + +SECTIONS { + .iram : { + INTV_CONTENTS + *arch/v850/kernel/head.o + *(.early.text) + } > IRAM + .dram : { + _memcons_output = . ; + . = . + 0x8000 ; + _memcons_output_end = . ; + } > DRAM + .sdram : { + /* We stick console output into a buffer here. */ + RAMK_KRAM_CONTENTS + ROOT_FS_CONTENTS + } > SDRAM +} diff -Nru a/arch/v850/sim85e2c.ld b/arch/v850/sim85e2c.ld --- a/arch/v850/sim85e2c.ld Sun Jul 27 10:13:52 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,44 +0,0 @@ -/* Linker script for the sim85e2c simulator, which is a verilog simulation of - the V850E2 NA85E2C cpu core (CONFIG_V850E2_SIM85E2C). */ - -MEMORY { - /* 1MB of `instruction RAM', starting at 0. - Instruction fetches are much faster from IRAM than from DRAM. - This should match IRAM_ADDR in "include/asm-v580/sim85e2c.h". */ - IRAM : ORIGIN = 0x00000000, LENGTH = 0x00100000 - - /* 1MB of `data RAM', below and contiguous with the I/O space. - Data fetches are much faster from DRAM than from IRAM. - This should match DRAM_ADDR in "include/asm-v580/sim85e2c.h". */ - DRAM : ORIGIN = 0xfff00000, LENGTH = 0x000ff000 - /* We have to load DRAM at a mirror-address of 0x1ff00000, - because the simulator's preprocessing script isn't smart - enough to deal with the above LMA. */ - DRAM_LOAD : ORIGIN = 0x1ff00000, LENGTH = 0x000ff000 - - /* `external ram' (CS1 area), comes after IRAM. - This should match ERAM_ADDR in "include/asm-v580/sim85e2c.h". */ - ERAM : ORIGIN = 0x00100000, LENGTH = 0x07f00000 -} - -SECTIONS { - .iram : { - INTV_CONTENTS - TEXT_CONTENTS - RAMK_INIT_CONTENTS - } > IRAM - .data : { - __kram_start = . ; - DATA_CONTENTS - BSS_CONTENTS - ROOT_FS_CONTENTS - - /* We stick console output into a buffer here. */ - _memcons_output = . ; - . = . + 0x8000 ; - _memcons_output_end = . ; - - __kram_end = . ; - BOOTMAP_CONTENTS - } > DRAM AT> DRAM_LOAD -} diff -Nru a/arch/v850/vmlinux.lds.S b/arch/v850/vmlinux.lds.S --- a/arch/v850/vmlinux.lds.S Sun Jul 27 10:13:48 2003 +++ b/arch/v850/vmlinux.lds.S Sun Jul 27 10:13:48 2003 @@ -206,8 +206,8 @@ # include "sim.ld" #endif -#ifdef CONFIG_V850E2_SIM85E2C -# include "sim85e2c.ld" +#ifdef CONFIG_V850E2_SIM85E2 +# include "sim85e2.ld" #endif #ifdef CONFIG_V850E2_FPGA85E2C @@ -247,3 +247,8 @@ # include "rte_nb85e_cb.ld" # endif #endif + +#ifdef CONFIG_RTE_CB_ME2 +# include "rte_me2_cb.ld" +#endif + diff -Nru a/arch/x86_64/Makefile b/arch/x86_64/Makefile --- a/arch/x86_64/Makefile Sun Jul 27 10:13:51 2003 +++ b/arch/x86_64/Makefile Sun Jul 27 10:13:51 2003 @@ -36,7 +36,6 @@ LDFLAGS := -m elf_x86_64 OBJCOPYFLAGS := -O binary -R .note -R .comment -S LDFLAGS_vmlinux := -e stext -LDFLAGS_BLOB := --format binary --oformat elf64-x86-64 CFLAGS += -mno-red-zone CFLAGS += -mcmodel=kernel diff -Nru a/arch/x86_64/mm/init.c b/arch/x86_64/mm/init.c --- a/arch/x86_64/mm/init.c Sun Jul 27 10:13:42 2003 +++ b/arch/x86_64/mm/init.c Sun Jul 27 10:13:42 2003 @@ -19,9 +19,6 @@ #include #include #include -#ifdef CONFIG_BLK_DEV_INITRD -#include -#endif #include #include #include diff -Nru a/arch/x86_64/mm/numa.c b/arch/x86_64/mm/numa.c --- a/arch/x86_64/mm/numa.c Sun Jul 27 10:13:50 2003 +++ b/arch/x86_64/mm/numa.c Sun Jul 27 10:13:50 2003 @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff -Nru a/drivers/acorn/block/fd1772.c b/drivers/acorn/block/fd1772.c --- a/drivers/acorn/block/fd1772.c Sun Jul 27 10:13:43 2003 +++ b/drivers/acorn/block/fd1772.c Sun Jul 27 10:13:43 2003 @@ -152,8 +152,6 @@ #include -#include - /* Note: FD_MAX_UNITS could be redefined to 2 for the Atari (with * little additional rework in this file). But I'm not yet sure if * some other code depends on the number of floppies... (It is defined diff -Nru a/drivers/acorn/block/mfmhd.c b/drivers/acorn/block/mfmhd.c --- a/drivers/acorn/block/mfmhd.c Sun Jul 27 10:13:42 2003 +++ b/drivers/acorn/block/mfmhd.c Sun Jul 27 10:13:42 2003 @@ -111,7 +111,6 @@ #include #include #include -#include #include #include diff -Nru a/drivers/acpi/executer/exutils.c b/drivers/acpi/executer/exutils.c --- a/drivers/acpi/executer/exutils.c Sun Jul 27 10:13:42 2003 +++ b/drivers/acpi/executer/exutils.c Sun Jul 27 10:13:42 2003 @@ -290,7 +290,7 @@ * acpi_integer is unsigned, so we don't worry about a '-' */ if ((current_value = value) == 0) { - return_VALUE (1); + return_VALUE (1); } num_digits = 0; diff -Nru a/drivers/acpi/hardware/hwregs.c b/drivers/acpi/hardware/hwregs.c --- a/drivers/acpi/hardware/hwregs.c Sun Jul 27 10:13:50 2003 +++ b/drivers/acpi/hardware/hwregs.c Sun Jul 27 10:13:50 2003 @@ -357,9 +357,9 @@ /* * Decode the Register ID - * Register id = Register block id | bit id + * Register ID = [Register block ID] | [bit ID] * - * Check bit id to fine locate Register offset. + * Check bit ID to fine locate Register offset. * Check Mask to determine Register offset, and then read-write. */ switch (bit_reg_info->parent_register) { @@ -367,9 +367,9 @@ /* * Status Registers are different from the rest. Clear by - * writing 1, writing 0 has no effect. So, the only relevant + * writing 1, and writing 0 has no effect. So, the only relevant * information is the single bit we're interested in, all others should - * be written as 0 so they will be left unchanged + * be written as 0 so they will be left unchanged. */ value = ACPI_REGISTER_PREPARE_BITS (value, bit_reg_info->bit_position, bit_reg_info->access_bit_mask); @@ -394,17 +394,17 @@ case ACPI_REGISTER_PM1_CONTROL: /* - * Read the PM1 Control register. + * Write the PM1 Control register. * Note that at this level, the fact that there are actually TWO - * registers (A and B - and that B may not exist) is abstracted. + * registers (A and B - and B may not exist) is abstracted. */ ACPI_DEBUG_PRINT ((ACPI_DB_IO, "PM1 control: Read %X\n", register_value)); ACPI_REGISTER_INSERT_VALUE (register_value, bit_reg_info->bit_position, bit_reg_info->access_bit_mask, value); - status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, register_id, - (u16) register_value); + status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, + ACPI_REGISTER_PM1_CONTROL, (u16) register_value); break; @@ -724,7 +724,7 @@ /* * Three address spaces supported: - * Memory, Io, or PCI config. + * Memory, IO, or PCI_Config. */ switch (reg->address_space_id) { case ACPI_ADR_SPACE_SYSTEM_MEMORY: @@ -808,9 +808,10 @@ (!reg->address)) { return (AE_OK); } + /* * Three address spaces supported: - * Memory, Io, or PCI config. + * Memory, IO, or PCI_Config. */ switch (reg->address_space_id) { case ACPI_ADR_SPACE_SYSTEM_MEMORY: diff -Nru a/drivers/acpi/osl.c b/drivers/acpi/osl.c --- a/drivers/acpi/osl.c Sun Jul 27 10:13:50 2003 +++ b/drivers/acpi/osl.c Sun Jul 27 10:13:50 2003 @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -291,11 +292,14 @@ void acpi_os_stall(u32 us) { - if (us > 10000) { - mdelay(us / 1000); - } - else { - udelay(us); + while (us) { + u32 delay = 1000; + + if (delay > us) + delay = us; + udelay(delay); + touch_nmi_watchdog(); + us -= delay; } } diff -Nru a/drivers/acpi/processor.c b/drivers/acpi/processor.c --- a/drivers/acpi/processor.c Sun Jul 27 10:13:48 2003 +++ b/drivers/acpi/processor.c Sun Jul 27 10:13:48 2003 @@ -1351,7 +1351,7 @@ PDE(inode)->data); } -static int +static ssize_t acpi_processor_write_throttling ( struct file *file, const char *buffer, @@ -1414,7 +1414,7 @@ PDE(inode)->data); } -static int +static ssize_t acpi_processor_write_limit ( struct file *file, const char *buffer, diff -Nru a/drivers/acpi/tables/tbconvrt.c b/drivers/acpi/tables/tbconvrt.c --- a/drivers/acpi/tables/tbconvrt.c Sun Jul 27 10:13:44 2003 +++ b/drivers/acpi/tables/tbconvrt.c Sun Jul 27 10:13:44 2003 @@ -75,14 +75,10 @@ ACPI_FUNCTION_ENTRY (); -#if ACPI_MACHINE_WIDTH != 64 - if (RSDP->revision < 2) { pointer_size = sizeof (u32); } - else -#endif - { + else { pointer_size = sizeof (u64); } diff -Nru a/drivers/acpi/tables/tbget.c b/drivers/acpi/tables/tbget.c --- a/drivers/acpi/tables/tbget.c Sun Jul 27 10:13:48 2003 +++ b/drivers/acpi/tables/tbget.c Sun Jul 27 10:13:48 2003 @@ -145,7 +145,7 @@ /* Create a logical address for the physical pointer*/ status = acpi_os_map_memory (address->pointer.physical, sizeof (struct acpi_table_header), - (void **) &header); + (void *) &header); if (ACPI_FAILURE (status)) { ACPI_REPORT_ERROR (("Could not map memory at %8.8X%8.8X for length %X\n", ACPI_HIDWORD (address->pointer.physical), @@ -361,7 +361,7 @@ * into our address space. */ status = acpi_os_map_memory (address->pointer.physical, (acpi_size) header->length, - (void **) &full_table); + (void *) &full_table); if (ACPI_FAILURE (status)) { ACPI_REPORT_ERROR (("Could not map memory for table [%4.4s] at %8.8X%8.8X for length %X\n", header->signature, diff -Nru a/drivers/acpi/tables/tbinstal.c b/drivers/acpi/tables/tbinstal.c --- a/drivers/acpi/tables/tbinstal.c Sun Jul 27 10:13:42 2003 +++ b/drivers/acpi/tables/tbinstal.c Sun Jul 27 10:13:42 2003 @@ -271,22 +271,40 @@ if (list_head->next) { return_ACPI_STATUS (AE_ALREADY_EXISTS); } - } - /* - * Link the new table in to the list of tables of this type. - * Just insert at the start of the list, order unimportant. - * - * table_desc->Prev is already NULL from calloc() - */ - table_desc->next = list_head->next; - list_head->next = table_desc; + table_desc->next = list_head->next; + list_head->next = table_desc; + + if (table_desc->next) { + table_desc->next->prev = table_desc; + } - if (table_desc->next) { - table_desc->next->prev = table_desc; + list_head->count++; } + else { + /* + * Link the new table in to the list of tables of this type. + * Insert at the end of the list, order IS IMPORTANT. + * + * table_desc->Prev & Next are already NULL from calloc() + */ + list_head->count++; + + if (!list_head->next) { + list_head->next = table_desc; + } + else { + table_desc->next = list_head->next; - list_head->count++; + while (table_desc->next->next) { + table_desc->next = table_desc->next->next; + } + + table_desc->next->next = table_desc; + table_desc->prev = table_desc->next; + table_desc->next = NULL; + } + } /* Finish initialization of the table descriptor */ diff -Nru a/drivers/acpi/tables/tbrsdt.c b/drivers/acpi/tables/tbrsdt.c --- a/drivers/acpi/tables/tbrsdt.c Sun Jul 27 10:13:47 2003 +++ b/drivers/acpi/tables/tbrsdt.c Sun Jul 27 10:13:47 2003 @@ -85,7 +85,7 @@ * Obtain access to the RSDP structure */ status = acpi_os_map_memory (address->pointer.physical, sizeof (struct rsdp_descriptor), - (void **) &rsdp); + (void *) &rsdp); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } diff -Nru a/drivers/acpi/tables/tbxfroot.c b/drivers/acpi/tables/tbxfroot.c --- a/drivers/acpi/tables/tbxfroot.c Sun Jul 27 10:13:49 2003 +++ b/drivers/acpi/tables/tbxfroot.c Sun Jul 27 10:13:49 2003 @@ -179,7 +179,7 @@ if ((flags & ACPI_MEMORY_MODE) == ACPI_LOGICAL_ADDRESSING) { status = acpi_os_map_memory (rsdp_address.pointer.physical, sizeof (struct rsdp_descriptor), - (void **) &acpi_gbl_RSDP); + (void *) &acpi_gbl_RSDP); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -423,7 +423,7 @@ * 1) Search EBDA (low memory) paragraphs */ status = acpi_os_map_memory ((u64) ACPI_LO_RSDP_WINDOW_BASE, ACPI_LO_RSDP_WINDOW_SIZE, - (void **) &table_ptr); + (void *) &table_ptr); if (ACPI_FAILURE (status)) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not map memory at %X for length %X\n", ACPI_LO_RSDP_WINDOW_BASE, ACPI_LO_RSDP_WINDOW_SIZE)); @@ -447,7 +447,7 @@ * 2) Search upper memory: 16-byte boundaries in E0000h-F0000h */ status = acpi_os_map_memory ((u64) ACPI_HI_RSDP_WINDOW_BASE, ACPI_HI_RSDP_WINDOW_SIZE, - (void **) &table_ptr); + (void *) &table_ptr); if (ACPI_FAILURE (status)) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not map memory at %X for length %X\n", ACPI_HI_RSDP_WINDOW_BASE, ACPI_HI_RSDP_WINDOW_SIZE)); diff -Nru a/drivers/acpi/tables.c b/drivers/acpi/tables.c --- a/drivers/acpi/tables.c Sun Jul 27 10:13:44 2003 +++ b/drivers/acpi/tables.c Sun Jul 27 10:13:44 2003 @@ -33,6 +33,7 @@ #include #include #include +#include #define PREFIX "ACPI: " @@ -61,16 +62,14 @@ /* System Description Table (RSDT/XSDT) */ struct acpi_table_sdt { - unsigned long pa; /* Physical Address */ - unsigned long count; /* Table count */ - struct { - unsigned long pa; - enum acpi_table_id id; - unsigned long size; - } entry[ACPI_MAX_TABLES]; + unsigned long pa; + enum acpi_table_id id; + unsigned long size; } __attribute__ ((packed)); -static struct acpi_table_sdt sdt; +static unsigned long sdt_pa; /* Physical Address */ +static unsigned long sdt_count; /* Table count */ +static struct acpi_table_sdt *sdt_entry; void acpi_table_print ( @@ -236,11 +235,11 @@ /* Locate the table. */ - for (i = 0; i < sdt.count; i++) { - if (sdt.entry[i].id != temp_id) + for (i = 0; i < sdt_count; i++) { + if (sdt_entry[i].id != temp_id) continue; *header = (void *) - __acpi_map_table(sdt.entry[i].pa, sdt.entry[i].size); + __acpi_map_table(sdt_entry[i].pa, sdt_entry[i].size); if (!*header) { printk(KERN_WARNING PREFIX "Unable to map %s\n", acpi_table_signatures[temp_id]); @@ -289,11 +288,11 @@ /* Locate the MADT (if exists). There should only be one. */ - for (i = 0; i < sdt.count; i++) { - if (sdt.entry[i].id != id) + for (i = 0; i < sdt_count; i++) { + if (sdt_entry[i].id != id) continue; madt = (void *) - __acpi_map_table(sdt.entry[i].pa, sdt.entry[i].size); + __acpi_map_table(sdt_entry[i].pa, sdt_entry[i].size); if (!madt) { printk(KERN_WARNING PREFIX "Unable to map %s\n", acpi_table_signatures[id]); @@ -308,7 +307,7 @@ return -ENODEV; } - madt_end = (unsigned long) madt + sdt.entry[i].size; + madt_end = (unsigned long) madt + sdt_entry[i].size; /* Parse all entries looking for a match. */ @@ -349,10 +348,10 @@ if (!handler) return -EINVAL; - for (i = 0; i < sdt.count; i++) { - if (sdt.entry[i].id != id) + for (i = 0; i < sdt_count; i++) { + if (sdt_entry[i].id != id) continue; - handler(sdt.entry[i].pa, sdt.entry[i].size); + handler(sdt_entry[i].pa, sdt_entry[i].size); count++; } @@ -377,11 +376,11 @@ struct acpi_table_xsdt *mapped_xsdt = NULL; - sdt.pa = ((struct acpi20_table_rsdp*)rsdp)->xsdt_address; + sdt_pa = ((struct acpi20_table_rsdp*)rsdp)->xsdt_address; /* map in just the header */ header = (struct acpi_table_header *) - __acpi_map_table(sdt.pa, sizeof(struct acpi_table_header)); + __acpi_map_table(sdt_pa, sizeof(struct acpi_table_header)); if (!header) { printk(KERN_WARNING PREFIX "Unable to map XSDT header\n"); @@ -390,7 +389,7 @@ /* remap in the entire table before processing */ mapped_xsdt = (struct acpi_table_xsdt *) - __acpi_map_table(sdt.pa, header->length); + __acpi_map_table(sdt_pa, header->length); if (!mapped_xsdt) { printk(KERN_WARNING PREFIX "Unable to map XSDT\n"); return -ENODEV; @@ -407,15 +406,21 @@ return -ENODEV; } - sdt.count = (header->length - sizeof(struct acpi_table_header)) >> 3; - if (sdt.count > ACPI_MAX_TABLES) { + sdt_count = (header->length - sizeof(struct acpi_table_header)) >> 3; + if (sdt_count > ACPI_MAX_TABLES) { printk(KERN_WARNING PREFIX "Truncated %lu XSDT entries\n", - (sdt.count - ACPI_MAX_TABLES)); - sdt.count = ACPI_MAX_TABLES; + (sdt_count - ACPI_MAX_TABLES)); + sdt_count = ACPI_MAX_TABLES; } - for (i = 0; i < sdt.count; i++) - sdt.entry[i].pa = (unsigned long) mapped_xsdt->entry[i]; + sdt_entry = alloc_bootmem(sdt_count * sizeof(struct acpi_table_sdt)); + if (!sdt_entry) { + printk(KERN_ERR "ACPI: Could not allocate mem for SDT entries!\n"); + return -ENOMEM; + } + + for (i = 0; i < sdt_count; i++) + sdt_entry[i].pa = (unsigned long) mapped_xsdt->entry[i]; } /* Then check RSDT */ @@ -424,11 +429,11 @@ struct acpi_table_rsdt *mapped_rsdt = NULL; - sdt.pa = rsdp->rsdt_address; + sdt_pa = rsdp->rsdt_address; /* map in just the header */ header = (struct acpi_table_header *) - __acpi_map_table(sdt.pa, sizeof(struct acpi_table_header)); + __acpi_map_table(sdt_pa, sizeof(struct acpi_table_header)); if (!header) { printk(KERN_WARNING PREFIX "Unable to map RSDT header\n"); return -ENODEV; @@ -436,7 +441,7 @@ /* remap in the entire table before processing */ mapped_rsdt = (struct acpi_table_rsdt *) - __acpi_map_table(sdt.pa, header->length); + __acpi_map_table(sdt_pa, header->length); if (!mapped_rsdt) { printk(KERN_WARNING PREFIX "Unable to map RSDT\n"); return -ENODEV; @@ -453,15 +458,21 @@ return -ENODEV; } - sdt.count = (header->length - sizeof(struct acpi_table_header)) >> 2; - if (sdt.count > ACPI_MAX_TABLES) { + sdt_count = (header->length - sizeof(struct acpi_table_header)) >> 2; + if (sdt_count > ACPI_MAX_TABLES) { printk(KERN_WARNING PREFIX "Truncated %lu RSDT entries\n", - (sdt.count - ACPI_TABLE_COUNT)); - sdt.count = ACPI_MAX_TABLES; + (sdt_count - ACPI_MAX_TABLES)); + sdt_count = ACPI_MAX_TABLES; } - for (i = 0; i < sdt.count; i++) - sdt.entry[i].pa = (unsigned long) mapped_rsdt->entry[i]; + sdt_entry = alloc_bootmem(sdt_count * sizeof(struct acpi_table_sdt)); + if (!sdt_entry) { + printk(KERN_ERR "ACPI: Could not allocate mem for SDT entries!\n"); + return -ENOMEM; + } + + for (i = 0; i < sdt_count; i++) + sdt_entry[i].pa = (unsigned long) mapped_rsdt->entry[i]; } else { @@ -469,38 +480,38 @@ return -ENODEV; } - acpi_table_print(header, sdt.pa); + acpi_table_print(header, sdt_pa); - for (i = 0; i < sdt.count; i++) { + for (i = 0; i < sdt_count; i++) { /* map in just the header */ header = (struct acpi_table_header *) - __acpi_map_table(sdt.entry[i].pa, + __acpi_map_table(sdt_entry[i].pa, sizeof(struct acpi_table_header)); if (!header) continue; /* remap in the entire table before processing */ header = (struct acpi_table_header *) - __acpi_map_table(sdt.entry[i].pa, + __acpi_map_table(sdt_entry[i].pa, header->length); if (!header) continue; - acpi_table_print(header, sdt.entry[i].pa); + acpi_table_print(header, sdt_entry[i].pa); if (acpi_table_compute_checksum(header, header->length)) { printk(KERN_WARNING " >>> ERROR: Invalid checksum\n"); continue; } - sdt.entry[i].size = header->length; + sdt_entry[i].size = header->length; for (id = 0; id < ACPI_TABLE_COUNT; id++) { if (!strncmp((char *) &header->signature, acpi_table_signatures[id], sizeof(header->signature))) { - sdt.entry[i].id = id; + sdt_entry[i].id = id; } } } @@ -524,8 +535,6 @@ struct acpi_table_rsdp *rsdp = NULL; unsigned long rsdp_phys = 0; int result = 0; - - memset(&sdt, 0, sizeof(struct acpi_table_sdt)); /* Locate and map the Root System Description Table (RSDP) */ diff -Nru a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c --- a/drivers/acpi/thermal.c Sun Jul 27 10:13:51 2003 +++ b/drivers/acpi/thermal.c Sun Jul 27 10:13:51 2003 @@ -84,11 +84,11 @@ static int acpi_thermal_state_open_fs(struct inode *inode, struct file *file); static int acpi_thermal_temp_open_fs(struct inode *inode, struct file *file); static int acpi_thermal_trip_open_fs(struct inode *inode, struct file *file); -static int acpi_thermal_write_trip_points (struct file*,const char *,size_t,loff_t *); +static ssize_t acpi_thermal_write_trip_points (struct file*,const char *,size_t,loff_t *); static int acpi_thermal_cooling_open_fs(struct inode *inode, struct file *file); -static int acpi_thermal_write_cooling_mode (struct file*,const char *,size_t,loff_t *); +static ssize_t acpi_thermal_write_cooling_mode (struct file*,const char *,size_t,loff_t *); static int acpi_thermal_polling_open_fs(struct inode *inode, struct file *file); -static int acpi_thermal_write_polling(struct file*,const char *,size_t,loff_t *); +static ssize_t acpi_thermal_write_polling(struct file*,const char *,size_t,loff_t *); static struct acpi_driver acpi_thermal_driver = { .name = ACPI_THERMAL_DRIVER_NAME, @@ -881,7 +881,7 @@ return single_open(file, acpi_thermal_trip_seq_show, PDE(inode)->data); } -static int +static ssize_t acpi_thermal_write_trip_points ( struct file *file, const char *buffer, @@ -950,7 +950,7 @@ PDE(inode)->data); } -static int +static ssize_t acpi_thermal_write_cooling_mode ( struct file *file, const char *buffer, @@ -1011,7 +1011,7 @@ PDE(inode)->data); } -static int +static ssize_t acpi_thermal_write_polling ( struct file *file, const char *buffer, diff -Nru a/drivers/acpi/toshiba_acpi.c b/drivers/acpi/toshiba_acpi.c --- a/drivers/acpi/toshiba_acpi.c Sun Jul 27 10:13:40 2003 +++ b/drivers/acpi/toshiba_acpi.c Sun Jul 27 10:13:40 2003 @@ -108,7 +108,8 @@ int result; char* str2 = kmalloc(n + 1, GFP_KERNEL); if (str2 == 0) return 0; - strlcpy(str2, str, n); + strncpy(str2, str, n); + str2[n] = 0; va_start(args, format); result = vsscanf(str2, format, args); va_end(args); diff -Nru a/drivers/acpi/utilities/utglobal.c b/drivers/acpi/utilities/utglobal.c --- a/drivers/acpi/utilities/utglobal.c Sun Jul 27 10:13:41 2003 +++ b/drivers/acpi/utilities/utglobal.c Sun Jul 27 10:13:41 2003 @@ -307,9 +307,9 @@ /*********** Name, Signature, Global typed pointer Signature size, Type How many allowed?, Contains valid AML? */ /* RSDP 0 */ {RSDP_NAME, RSDP_SIG, NULL, sizeof (RSDP_SIG)-1, ACPI_TABLE_ROOT | ACPI_TABLE_SINGLE}, - /* DSDT 1 */ {DSDT_SIG, DSDT_SIG, (void **) &acpi_gbl_DSDT, sizeof (DSDT_SIG)-1, ACPI_TABLE_SECONDARY| ACPI_TABLE_SINGLE | ACPI_TABLE_EXECUTABLE}, - /* FADT 2 */ {FADT_SIG, FADT_SIG, (void **) &acpi_gbl_FADT, sizeof (FADT_SIG)-1, ACPI_TABLE_PRIMARY | ACPI_TABLE_SINGLE}, - /* FACS 3 */ {FACS_SIG, FACS_SIG, (void **) &acpi_gbl_FACS, sizeof (FACS_SIG)-1, ACPI_TABLE_SECONDARY| ACPI_TABLE_SINGLE}, + /* DSDT 1 */ {DSDT_SIG, DSDT_SIG, (void *) &acpi_gbl_DSDT, sizeof (DSDT_SIG)-1, ACPI_TABLE_SECONDARY| ACPI_TABLE_SINGLE | ACPI_TABLE_EXECUTABLE}, + /* FADT 2 */ {FADT_SIG, FADT_SIG, (void *) &acpi_gbl_FADT, sizeof (FADT_SIG)-1, ACPI_TABLE_PRIMARY | ACPI_TABLE_SINGLE}, + /* FACS 3 */ {FACS_SIG, FACS_SIG, (void *) &acpi_gbl_FACS, sizeof (FACS_SIG)-1, ACPI_TABLE_SECONDARY| ACPI_TABLE_SINGLE}, /* PSDT 4 */ {PSDT_SIG, PSDT_SIG, NULL, sizeof (PSDT_SIG)-1, ACPI_TABLE_PRIMARY | ACPI_TABLE_MULTIPLE | ACPI_TABLE_EXECUTABLE}, /* SSDT 5 */ {SSDT_SIG, SSDT_SIG, NULL, sizeof (SSDT_SIG)-1, ACPI_TABLE_PRIMARY | ACPI_TABLE_MULTIPLE | ACPI_TABLE_EXECUTABLE}, /* XSDT 6 */ {XSDT_SIG, XSDT_SIG, NULL, sizeof (RSDT_SIG)-1, ACPI_TABLE_ROOT | ACPI_TABLE_SINGLE}, diff -Nru a/drivers/atm/atmtcp.c b/drivers/atm/atmtcp.c --- a/drivers/atm/atmtcp.c Sun Jul 27 10:13:48 2003 +++ b/drivers/atm/atmtcp.c Sun Jul 27 10:13:48 2003 @@ -66,7 +66,7 @@ *(struct atm_vcc **) &new_msg->vcc = vcc; old_test = test_bit(flag,&vcc->flags); out_vcc->push(out_vcc,skb); - add_wait_queue(&vcc->sleep,&wait); + add_wait_queue(vcc->sk->sk_sleep, &wait); while (test_bit(flag,&vcc->flags) == old_test) { mb(); out_vcc = PRIV(vcc->dev) ? PRIV(vcc->dev)->vcc : NULL; @@ -78,7 +78,7 @@ schedule(); } current->state = TASK_RUNNING; - remove_wait_queue(&vcc->sleep,&wait); + remove_wait_queue(vcc->sk->sk_sleep, &wait); return error; } @@ -90,7 +90,7 @@ vcc->vpi = msg->addr.sap_addr.vpi; vcc->vci = msg->addr.sap_addr.vci; vcc->qos = msg->qos; - vcc->reply = msg->result; + vcc->sk->sk_err = -msg->result; switch (msg->type) { case ATMTCP_CTRL_OPEN: change_bit(ATM_VF_READY,&vcc->flags); @@ -103,7 +103,7 @@ msg->type); return -EINVAL; } - wake_up(&vcc->sleep); + wake_up(vcc->sk->sk_sleep); return 0; } @@ -134,7 +134,7 @@ clear_bit(ATM_VF_READY,&vcc->flags); /* just in case ... */ error = atmtcp_send_control(vcc,ATMTCP_CTRL_OPEN,&msg,ATM_VF_READY); if (error) return error; - return vcc->reply; + return -vcc->sk->sk_err; } @@ -257,7 +257,7 @@ walk = atm_sk(s); if (walk->dev != atmtcp_dev) continue; - wake_up(&walk->sleep); + wake_up(walk->sk->sk_sleep); } read_unlock(&vcc_sklist_lock); } diff -Nru a/drivers/block/DAC960.c b/drivers/block/DAC960.c --- a/drivers/block/DAC960.c Sun Jul 27 10:13:49 2003 +++ b/drivers/block/DAC960.c Sun Jul 27 10:13:50 2003 @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include diff -Nru a/drivers/block/Kconfig b/drivers/block/Kconfig --- a/drivers/block/Kconfig Sun Jul 27 10:13:42 2003 +++ b/drivers/block/Kconfig Sun Jul 27 10:13:42 2003 @@ -264,6 +264,7 @@ config BLK_DEV_CRYPTOLOOP tristate "Cryptoloop Support" + select CRYPTO depends on BLK_DEV_LOOP ---help--- Say Y here if you want to be able to use the ciphers that are @@ -339,7 +340,7 @@ config LBD bool "Support for Large Block Devices" - depends on X86 + depends on X86 || MIPS32 || PPC32 || ARCH_S390_31 || SUPERH help Say Y here if you want to attach large (bigger than 2TB) discs to your machine, or if you want to have a raid or loopback device diff -Nru a/drivers/block/Kconfig.iosched b/drivers/block/Kconfig.iosched --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/block/Kconfig.iosched Sun Jul 27 10:13:53 2003 @@ -0,0 +1,8 @@ +config IOSCHED_AS + bool "Anticipatory I/O scheduler" if EMBEDDED + default y + +config IOSCHED_DEADLINE + bool "Deadline I/O scheduler" if EMBEDDED + default y + diff -Nru a/drivers/block/Makefile b/drivers/block/Makefile --- a/drivers/block/Makefile Sun Jul 27 10:13:50 2003 +++ b/drivers/block/Makefile Sun Jul 27 10:13:50 2003 @@ -13,9 +13,10 @@ # kblockd threads # -obj-y := elevator.o ll_rw_blk.o ioctl.o genhd.o scsi_ioctl.o \ - deadline-iosched.o as-iosched.o +obj-y := elevator.o ll_rw_blk.o ioctl.o genhd.o scsi_ioctl.o +obj-$(CONFIG_IOSCHED_AS) += as-iosched.o +obj-$(CONFIG_IOSCHED_DEADLINE) += deadline-iosched.o obj-$(CONFIG_MAC_FLOPPY) += swim3.o obj-$(CONFIG_BLK_DEV_FD) += floppy.o obj-$(CONFIG_BLK_DEV_FD98) += floppy98.o diff -Nru a/drivers/block/acsi.c b/drivers/block/acsi.c --- a/drivers/block/acsi.c Sun Jul 27 10:13:52 2003 +++ b/drivers/block/acsi.c Sun Jul 27 10:13:52 2003 @@ -55,7 +55,6 @@ #include #include #include -#include #include #include #include /* for SCSI_IOCTL_GET_IDLUN */ diff -Nru a/drivers/block/acsi_slm.c b/drivers/block/acsi_slm.c --- a/drivers/block/acsi_slm.c Sun Jul 27 10:13:39 2003 +++ b/drivers/block/acsi_slm.c Sun Jul 27 10:13:39 2003 @@ -999,7 +999,7 @@ return -EBUSY; } - if (!(SLMBuffer = atari_stram_alloc( SLM_BUFFER_SIZE, NULL, "SLM" ))) { + if (!(SLMBuffer = atari_stram_alloc( SLM_BUFFER_SIZE, "SLM" ))) { printk( KERN_ERR "Unable to get SLM ST-Ram buffer.\n" ); unregister_chrdev( ACSI_MAJOR, "slm" ); return -ENOMEM; diff -Nru a/drivers/block/amiflop.c b/drivers/block/amiflop.c --- a/drivers/block/amiflop.c Sun Jul 27 10:13:45 2003 +++ b/drivers/block/amiflop.c Sun Jul 27 10:13:45 2003 @@ -79,7 +79,6 @@ #include #include #include -#include #undef DEBUG /* print _LOTS_ of infos */ diff -Nru a/drivers/block/as-iosched.c b/drivers/block/as-iosched.c --- a/drivers/block/as-iosched.c Sun Jul 27 10:13:39 2003 +++ b/drivers/block/as-iosched.c Sun Jul 27 10:13:39 2003 @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -834,10 +833,11 @@ + 2*1024*64); aic->seek_samples += 256; - aic->seek_total += 256*seek_dist; + aic->seek_total += (u64)256*seek_dist; if (aic->seek_samples) { - aic->seek_mean = aic->seek_total + 128; - sector_div(aic->seek_mean, aic->seek_samples); + u64 total = aic->seek_total + (aic->seek_samples>>1); + do_div(total, aic->seek_samples); + aic->seek_mean = (sector_t)total; } aic->seek_samples = (aic->seek_samples>>1) + (aic->seek_samples>>2); @@ -1306,6 +1306,15 @@ as_update_arq(ad, arq); /* keep state machine up to date */ } +/* + * FIXME: HACK for AS requeue problems + */ +static void as_requeue_request(request_queue_t *q, struct request *rq) +{ + elv_completed_request(q, rq); + __elv_add_request(q, rq, 0, 0); +} + static void as_insert_request(request_queue_t *q, struct request *rq, struct list_head *insert_here) @@ -1821,6 +1830,7 @@ .elevator_next_req_fn = as_next_request, .elevator_add_req_fn = as_insert_request, .elevator_remove_req_fn = as_remove_request, + .elevator_requeue_req_fn = as_requeue_request, .elevator_queue_empty_fn = as_queue_empty, .elevator_completed_req_fn = as_completed_request, .elevator_former_req_fn = as_former_request, @@ -1832,6 +1842,7 @@ .elevator_exit_fn = as_exit, .elevator_ktype = &as_ktype, + .elevator_name = "anticipatory scheduling", }; EXPORT_SYMBOL(iosched_as); diff -Nru a/drivers/block/ataflop.c b/drivers/block/ataflop.c --- a/drivers/block/ataflop.c Sun Jul 27 10:13:41 2003 +++ b/drivers/block/ataflop.c Sun Jul 27 10:13:41 2003 @@ -91,7 +91,6 @@ #include #include #include -#include #include #define FD_MAX_UNITS 2 diff -Nru a/drivers/block/cciss.c b/drivers/block/cciss.c --- a/drivers/block/cciss.c Sun Jul 27 10:13:52 2003 +++ b/drivers/block/cciss.c Sun Jul 27 10:13:52 2003 @@ -41,7 +41,6 @@ #include #include -#include #include #include #include diff -Nru a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c --- a/drivers/block/cciss_scsi.c Sun Jul 27 10:13:42 2003 +++ b/drivers/block/cciss_scsi.c Sun Jul 27 10:13:42 2003 @@ -712,7 +712,8 @@ sh->hostdata[0] = (unsigned long) hba[ctlr]; sh->irq = hba[ctlr]->intr; sh->unique_id = sh->irq; - scsi_add_host(sh, &hba[ctlr]->pdev->dev); + scsi_add_host(sh, &hba[ctlr]->pdev->dev); /* XXX handle failure */ + scsi_scan_host(sh); return 1; } diff -Nru a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c --- a/drivers/block/cpqarray.c Sun Jul 27 10:13:41 2003 +++ b/drivers/block/cpqarray.c Sun Jul 27 10:13:41 2003 @@ -38,7 +38,6 @@ #include #include #include -#include #include #include #include diff -Nru a/drivers/block/cryptoloop.c b/drivers/block/cryptoloop.c --- a/drivers/block/cryptoloop.c Sun Jul 27 10:13:47 2003 +++ b/drivers/block/cryptoloop.c Sun Jul 27 10:13:47 2003 @@ -26,7 +26,6 @@ #include #include #include -#include #include #include diff -Nru a/drivers/block/deadline-iosched.c b/drivers/block/deadline-iosched.c --- a/drivers/block/deadline-iosched.c Sun Jul 27 10:13:50 2003 +++ b/drivers/block/deadline-iosched.c Sun Jul 27 10:13:50 2003 @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include @@ -941,6 +940,7 @@ .elevator_exit_fn = deadline_exit, .elevator_ktype = &deadline_ktype, + .elevator_name = "deadline", }; EXPORT_SYMBOL(iosched_deadline); diff -Nru a/drivers/block/elevator.c b/drivers/block/elevator.c --- a/drivers/block/elevator.c Sun Jul 27 10:13:50 2003 +++ b/drivers/block/elevator.c Sun Jul 27 10:13:50 2003 @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include @@ -214,6 +213,18 @@ e->elevator_merge_req_fn(q, rq, next); } +void elv_requeue_request(request_queue_t *q, struct request *rq) +{ + /* + * if iosched has an explicit requeue hook, then use that. otherwise + * just put the request at the front of the queue + */ + if (q->elevator.elevator_requeue_req_fn) + q->elevator.elevator_requeue_req_fn(q, rq); + else + __elv_add_request(q, rq, 0, 0); +} + void __elv_add_request(request_queue_t *q, struct request *rq, int at_end, int plug) { @@ -409,6 +420,7 @@ .elevator_merge_req_fn = elevator_noop_merge_requests, .elevator_next_req_fn = elevator_noop_next_request, .elevator_add_req_fn = elevator_noop_add_request, + .elevator_name = "noop", }; module_init(elevator_global_init); @@ -417,6 +429,7 @@ EXPORT_SYMBOL(elv_add_request); EXPORT_SYMBOL(__elv_add_request); +EXPORT_SYMBOL(elv_requeue_request); EXPORT_SYMBOL(elv_next_request); EXPORT_SYMBOL(elv_remove_request); EXPORT_SYMBOL(elv_queue_empty); diff -Nru a/drivers/block/floppy.c b/drivers/block/floppy.c --- a/drivers/block/floppy.c Sun Jul 27 10:13:41 2003 +++ b/drivers/block/floppy.c Sun Jul 27 10:13:41 2003 @@ -242,7 +242,7 @@ #define LOCAL_END_REQUEST #define DEVICE_NAME "floppy" -#include +#include #include #include /* for the compatibility eject ioctl */ #include diff -Nru a/drivers/block/floppy98.c b/drivers/block/floppy98.c --- a/drivers/block/floppy98.c Sun Jul 27 10:13:44 2003 +++ b/drivers/block/floppy98.c Sun Jul 27 10:13:44 2003 @@ -277,7 +277,6 @@ #define LOCAL_END_REQUEST #define DEVICE_NAME "floppy" -#include #include #include /* for the compatibility eject ioctl */ #include diff -Nru a/drivers/block/genhd.c b/drivers/block/genhd.c --- a/drivers/block/genhd.c Sun Jul 27 10:13:45 2003 +++ b/drivers/block/genhd.c Sun Jul 27 10:13:45 2003 @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include #include diff -Nru a/drivers/block/ioctl.c b/drivers/block/ioctl.c --- a/drivers/block/ioctl.c Sun Jul 27 10:13:40 2003 +++ b/drivers/block/ioctl.c Sun Jul 27 10:13:40 2003 @@ -1,5 +1,5 @@ #include /* for capable() */ -#include /* for set_device_ro() */ +#include #include #include #include @@ -166,13 +166,11 @@ return -EINVAL; if (get_user(n, (int *) arg)) return -EFAULT; - if (n > PAGE_SIZE || n < 512 || (n & (n - 1))) - return -EINVAL; if (bd_claim(bdev, &holder) < 0) return -EBUSY; - set_blocksize(bdev, n); + ret = set_blocksize(bdev, n); bd_release(bdev); - return 0; + return ret; case BLKPG: return blkpg_ioctl(bdev, (struct blkpg_ioctl_arg *) arg); case BLKRRPART: diff -Nru a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c --- a/drivers/block/ll_rw_blk.c Sun Jul 27 10:13:41 2003 +++ b/drivers/block/ll_rw_blk.c Sun Jul 27 10:13:41 2003 @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include @@ -689,7 +689,7 @@ static char *rq_flags[] = { "REQ_RW", - "REQ_RW_AHEAD", + "REQ_FAILFAST", "REQ_SOFTBARRIER", "REQ_HARDBARRIER", "REQ_CMD", @@ -706,6 +706,10 @@ "REQ_DRIVE_CMD", "REQ_DRIVE_TASK", "REQ_DRIVE_TASKFILE", + "REQ_PREEMPT", + "REQ_PM_SUSPEND", + "REQ_PM_RESUME", + "REQ_PM_SHUTDOWN", }; void blk_dump_rq_flags(struct request *rq, char *msg) @@ -1205,17 +1209,31 @@ static int __make_request(request_queue_t *, struct bio *); -static elevator_t *chosen_elevator = &iosched_as; +static elevator_t *chosen_elevator = +#if defined(CONFIG_IOSCHED_AS) + &iosched_as; +#elif defined(CONFIG_IOSCHED_DEADLINE) + &iosched_deadline; +#else + &elevator_noop; +#endif +#if defined(CONFIG_IOSCHED_AS) || defined(CONFIG_IOSCHED_DEADLINE) static int __init elevator_setup(char *str) { +#ifdef CONFIG_IOSCHED_DEADLINE if (!strcmp(str, "deadline")) chosen_elevator = &iosched_deadline; +#endif +#ifdef CONFIG_IOSCHED_AS if (!strcmp(str, "as")) chosen_elevator = &iosched_as; +#endif return 1; } + __setup("elevator=", elevator_setup); +#endif /* CONFIG_IOSCHED_AS || CONFIG_IOSCHED_DEADLINE */ /** * blk_init_queue - prepare a request queue for use with a block device @@ -1255,10 +1273,7 @@ if (!printed) { printed = 1; - if (chosen_elevator == &iosched_deadline) - printk("deadline elevator\n"); - else if (chosen_elevator == &iosched_as) - printk("anticipatory scheduling elevator\n"); + printk("Using %s elevator\n", chosen_elevator->elevator_name); } if ((ret = elevator_init(q, chosen_elevator))) { @@ -1494,6 +1509,23 @@ return rq; } +/** + * blk_requeue_request - put a request back on queue + * @q: request queue where request should be inserted + * @rq: request to be inserted + * + * Description: + * Drivers often keep queueing requests until the hardware cannot accept + * more, when that condition happens we need to put the request back + * on the queue. Must be called with queue lock held. + */ +void blk_requeue_request(request_queue_t *q, struct request *rq) +{ + if (blk_rq_tagged(rq)) + blk_queue_end_tag(q, rq); + + elv_requeue_request(q, rq); +} /** * blk_insert_request - insert a special request in to a request queue @@ -1501,6 +1533,7 @@ * @rq: request to be inserted * @at_head: insert request at head or tail of queue * @data: private data + * @reinsert: true if request it a reinsertion of previously processed one * * Description: * Many block devices need to execute commands asynchronously, so they don't @@ -1515,7 +1548,7 @@ * host that is unable to accept a particular command. */ void blk_insert_request(request_queue_t *q, struct request *rq, - int at_head, void *data) + int at_head, void *data, int reinsert) { unsigned long flags; @@ -1533,11 +1566,15 @@ /* * If command is tagged, release the tag */ - if (blk_rq_tagged(rq)) - blk_queue_end_tag(q, rq); + if(reinsert) { + blk_requeue_request(q, rq); + } else { + if (blk_rq_tagged(rq)) + blk_queue_end_tag(q, rq); - drive_stat_acct(rq, rq->nr_sectors, 1); - __elv_add_request(q, rq, !at_head, 0); + drive_stat_acct(rq, rq->nr_sectors, 1); + __elv_add_request(q, rq, !at_head, 0); + } q->request_fn(q); spin_unlock_irqrestore(q->queue_lock, flags); } @@ -1776,7 +1813,7 @@ static int __make_request(request_queue_t *q, struct bio *bio) { struct request *req, *freereq = NULL; - int el_ret, rw, nr_sectors, cur_nr_sectors, barrier; + int el_ret, rw, nr_sectors, cur_nr_sectors, barrier, ra; struct list_head *insert_here; sector_t sector; @@ -1797,6 +1834,8 @@ barrier = test_bit(BIO_RW_BARRIER, &bio->bi_rw); + ra = bio_flagged(bio, BIO_RW_AHEAD) || current->flags & PF_READAHEAD; + again: insert_here = NULL; spin_lock_irq(q->queue_lock); @@ -1884,7 +1923,7 @@ /* * READA bit set */ - if (bio_flagged(bio, BIO_RW_AHEAD)) + if (ra) goto end_io; freereq = get_request_wait(q, rw); @@ -1904,6 +1943,12 @@ if (barrier) req->flags |= (REQ_HARDBARRIER | REQ_NOMERGE); + /* + * don't stack up retries for read ahead + */ + if (ra) + req->flags |= REQ_FAILFAST; + req->errors = 0; req->hard_sector = req->sector = sector; req->hard_nr_sectors = req->nr_sectors = nr_sectors; @@ -2262,8 +2307,8 @@ * not a complete bvec done */ if (unlikely(nbytes > nr_bytes)) { - bio_iovec(bio)->bv_offset += nr_bytes; - bio_iovec(bio)->bv_len -= nr_bytes; + bio_iovec_idx(bio, idx)->bv_offset += nr_bytes; + bio_iovec_idx(bio, idx)->bv_len -= nr_bytes; bio_nbytes += nr_bytes; total_bytes += nr_bytes; break; @@ -2730,6 +2775,7 @@ EXPORT_SYMBOL(blk_get_request); EXPORT_SYMBOL(blk_put_request); EXPORT_SYMBOL(blk_insert_request); +EXPORT_SYMBOL(blk_requeue_request); EXPORT_SYMBOL(blk_queue_prep_rq); EXPORT_SYMBOL(blk_queue_merge_bvec); diff -Nru a/drivers/block/nbd.c b/drivers/block/nbd.c --- a/drivers/block/nbd.c Sun Jul 27 10:13:42 2003 +++ b/drivers/block/nbd.c Sun Jul 27 10:13:42 2003 @@ -44,7 +44,6 @@ #include -#include #include #include #include @@ -55,8 +54,6 @@ #include #include #include -#include -#include #include #include @@ -261,7 +258,8 @@ dprintk(DBG_TX, "%s: request %p: sending control (%s@%llu,%luB)\n", lo->disk->disk_name, req, nbdcmd_to_ascii(nbd_cmd(req)), - req->sector << 9, req->nr_sectors << 9); + (unsigned long long)req->sector << 9, + req->nr_sectors << 9); result = sock_xmit(sock, 1, &request, sizeof(request), (nbd_cmd(req) == NBD_CMD_WRITE)? MSG_MORE: 0); if (result <= 0) { diff -Nru a/drivers/block/paride/pcd.c b/drivers/block/paride/pcd.c --- a/drivers/block/paride/pcd.c Sun Jul 27 10:13:52 2003 +++ b/drivers/block/paride/pcd.c Sun Jul 27 10:13:52 2003 @@ -137,7 +137,7 @@ #include #include #include -#include +#include #include static spinlock_t pcd_lock; diff -Nru a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c --- a/drivers/block/paride/pd.c Sun Jul 27 10:13:50 2003 +++ b/drivers/block/paride/pd.c Sun Jul 27 10:13:50 2003 @@ -150,7 +150,7 @@ #include #include #include /* for the eject ioctl */ -#include +#include #include #include diff -Nru a/drivers/block/paride/pf.c b/drivers/block/paride/pf.c --- a/drivers/block/paride/pf.c Sun Jul 27 10:13:48 2003 +++ b/drivers/block/paride/pf.c Sun Jul 27 10:13:48 2003 @@ -150,7 +150,7 @@ #include #include #include -#include +#include #include #include @@ -222,9 +222,6 @@ #define ATAPI_READ_10 0x28 #define ATAPI_WRITE_10 0x2a -#ifdef MODULE -void cleanup_module(void); -#endif static int pf_open(struct inode *inode, struct file *file); static void do_pf_request(request_queue_t * q); static int pf_ioctl(struct inode *inode, struct file *file, diff -Nru a/drivers/block/ps2esdi.c b/drivers/block/ps2esdi.c --- a/drivers/block/ps2esdi.c Sun Jul 27 10:13:39 2003 +++ b/drivers/block/ps2esdi.c Sun Jul 27 10:13:39 2003 @@ -38,7 +38,7 @@ #include #include #include -#include +#include #include #include #include diff -Nru a/drivers/block/swim3.c b/drivers/block/swim3.c --- a/drivers/block/swim3.c Sun Jul 27 10:13:44 2003 +++ b/drivers/block/swim3.c Sun Jul 27 10:13:44 2003 @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include diff -Nru a/drivers/block/swim_iop.c b/drivers/block/swim_iop.c --- a/drivers/block/swim_iop.c Sun Jul 27 10:13:39 2003 +++ b/drivers/block/swim_iop.c Sun Jul 27 10:13:39 2003 @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include diff -Nru a/drivers/block/umem.c b/drivers/block/umem.c --- a/drivers/block/umem.c Sun Jul 27 10:13:52 2003 +++ b/drivers/block/umem.c Sun Jul 27 10:13:52 2003 @@ -99,7 +99,7 @@ static int major_nr; -#include +#include #include struct cardinfo { diff -Nru a/drivers/block/xd.c b/drivers/block/xd.c --- a/drivers/block/xd.c Sun Jul 27 10:13:50 2003 +++ b/drivers/block/xd.c Sun Jul 27 10:13:50 2003 @@ -46,7 +46,7 @@ #include #include #include -#include +#include #include #include diff -Nru a/drivers/block/z2ram.c b/drivers/block/z2ram.c --- a/drivers/block/z2ram.c Sun Jul 27 10:13:48 2003 +++ b/drivers/block/z2ram.c Sun Jul 27 10:13:48 2003 @@ -30,7 +30,6 @@ #include #include #include -#include #include #include diff -Nru a/drivers/cdrom/aztcd.c b/drivers/cdrom/aztcd.c --- a/drivers/cdrom/aztcd.c Sun Jul 27 10:13:51 2003 +++ b/drivers/cdrom/aztcd.c Sun Jul 27 10:13:51 2003 @@ -166,7 +166,7 @@ */ #include -#include +#include #include "aztcd.h" #include diff -Nru a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c --- a/drivers/cdrom/cdrom.c Sun Jul 27 10:13:41 2003 +++ b/drivers/cdrom/cdrom.c Sun Jul 27 10:13:41 2003 @@ -268,6 +268,7 @@ #include #include #include +#include #include @@ -2171,6 +2172,7 @@ return -ENOSYS; cdinfo(CD_DO_IOCTL, "entering CDROM_SEND_PACKET\n"); IOCTL_IN(arg, struct cdrom_generic_command, cgc); + cgc.timeout = clock_t_to_jiffies(cgc.timeout); return cdrom_do_cmd(cdi, &cgc); } case CDROM_NEXT_WRITABLE: { diff -Nru a/drivers/cdrom/cdu31a.c b/drivers/cdrom/cdu31a.c --- a/drivers/cdrom/cdu31a.c Sun Jul 27 10:13:49 2003 +++ b/drivers/cdrom/cdu31a.c Sun Jul 27 10:13:49 2003 @@ -177,7 +177,7 @@ #include "cdu31a.h" #define MAJOR_NR CDU31A_CDROM_MAJOR -#include +#include #define CDU31A_READAHEAD 4 /* 128 sector, 64kB, 32 reads read-ahead */ #define CDU31A_MAX_CONSECUTIVE_ATTENTIONS 10 diff -Nru a/drivers/cdrom/cm206.c b/drivers/cdrom/cm206.c --- a/drivers/cdrom/cm206.c Sun Jul 27 10:13:51 2003 +++ b/drivers/cdrom/cm206.c Sun Jul 27 10:13:51 2003 @@ -199,7 +199,7 @@ #define MAJOR_NR CM206_CDROM_MAJOR -#include +#include #undef DEBUG #define STATISTICS /* record times and frequencies of events */ diff -Nru a/drivers/cdrom/gscd.c b/drivers/cdrom/gscd.c --- a/drivers/cdrom/gscd.c Sun Jul 27 10:13:40 2003 +++ b/drivers/cdrom/gscd.c Sun Jul 27 10:13:40 2003 @@ -69,7 +69,7 @@ #include #define MAJOR_NR GOLDSTAR_CDROM_MAJOR -#include +#include #define gscd_port gscd /* for compatible parameter passing with "insmod" */ #include "gscd.h" diff -Nru a/drivers/cdrom/mcd.c b/drivers/cdrom/mcd.c --- a/drivers/cdrom/mcd.c Sun Jul 27 10:13:47 2003 +++ b/drivers/cdrom/mcd.c Sun Jul 27 10:13:47 2003 @@ -101,7 +101,7 @@ #include #include #include -#include +#include #define mcd_port mcd /* for compatible parameter passing with "insmod" */ #include "mcd.h" diff -Nru a/drivers/cdrom/mcdx.c b/drivers/cdrom/mcdx.c --- a/drivers/cdrom/mcdx.c Sun Jul 27 10:13:45 2003 +++ b/drivers/cdrom/mcdx.c Sun Jul 27 10:13:45 2003 @@ -74,7 +74,7 @@ #include #define MAJOR_NR MITSUMI_X_CDROM_MAJOR -#include +#include #include /* for compatible parameter passing with "insmod" */ diff -Nru a/drivers/cdrom/optcd.c b/drivers/cdrom/optcd.c --- a/drivers/cdrom/optcd.c Sun Jul 27 10:13:42 2003 +++ b/drivers/cdrom/optcd.c Sun Jul 27 10:13:42 2003 @@ -73,7 +73,7 @@ #include #include -#include +#include #include #include "optcd.h" diff -Nru a/drivers/cdrom/sbpcd.c b/drivers/cdrom/sbpcd.c --- a/drivers/cdrom/sbpcd.c Sun Jul 27 10:13:42 2003 +++ b/drivers/cdrom/sbpcd.c Sun Jul 27 10:13:42 2003 @@ -387,7 +387,7 @@ #include "sbpcd.h" #define MAJOR_NR MATSUSHITA_CDROM_MAJOR -#include +#include /*==========================================================================*/ #if SBPCD_DIS_IRQ diff -Nru a/drivers/cdrom/sjcd.c b/drivers/cdrom/sjcd.c --- a/drivers/cdrom/sjcd.c Sun Jul 27 10:13:48 2003 +++ b/drivers/cdrom/sjcd.c Sun Jul 27 10:13:48 2003 @@ -74,7 +74,7 @@ #include #include #include -#include +#include #include "sjcd.h" static int sjcd_present = 0; diff -Nru a/drivers/cdrom/sonycd535.c b/drivers/cdrom/sonycd535.c --- a/drivers/cdrom/sonycd535.c Sun Jul 27 10:13:43 2003 +++ b/drivers/cdrom/sonycd535.c Sun Jul 27 10:13:43 2003 @@ -134,7 +134,7 @@ #include #define MAJOR_NR CDU535_CDROM_MAJOR -#include +#include #define sony535_cd_base_io sonycd535 /* for compatible parameter passing with "insmod" */ #include "sonycd535.h" diff -Nru a/drivers/char/agp/i460-agp.c b/drivers/char/agp/i460-agp.c --- a/drivers/char/agp/i460-agp.c Sun Jul 27 10:13:47 2003 +++ b/drivers/char/agp/i460-agp.c Sun Jul 27 10:13:47 2003 @@ -608,7 +608,7 @@ .name = "agpgart-intel-i460", .id_table = agp_intel_i460_pci_table, .probe = agp_intel_i460_probe, - .remove = agp_intel_i460_remove, + .remove = __devexit_p(agp_intel_i460_remove), }; static int __init agp_intel_i460_init(void) diff -Nru a/drivers/char/amiserial.c b/drivers/char/amiserial.c --- a/drivers/char/amiserial.c Sun Jul 27 10:13:52 2003 +++ b/drivers/char/amiserial.c Sun Jul 27 10:13:52 2003 @@ -2145,14 +2145,14 @@ static __exit void rs_exit(void) { - int e1, e2; + int error; struct async_struct *info = rs_table[0].info; /* printk("Unloading %s: version %s\n", serial_name, serial_version); */ tasklet_kill(&info->tlet); - if ((e1 = tty_unregister_driver(serial_driver))) + if ((error = tty_unregister_driver(serial_driver))) printk("SERIAL: failed to unregister serial driver (%d)\n", - e1); + error); put_tty_driver(serial_driver); if (info) { diff -Nru a/drivers/char/busmouse.c b/drivers/char/busmouse.c --- a/drivers/char/busmouse.c Sun Jul 27 10:13:50 2003 +++ b/drivers/char/busmouse.c Sun Jul 27 10:13:50 2003 @@ -357,25 +357,23 @@ { unsigned int msedev = MINOR_TO_MOUSE(ops->minor); struct busmouse_data *mse; - int ret; + int ret = -EINVAL; if (msedev >= NR_MICE) { printk(KERN_ERR "busmouse: trying to allocate mouse on minor %d\n", ops->minor); - return -EINVAL; + goto out; } + ret = -ENOMEM; mse = kmalloc(sizeof(*mse), GFP_KERNEL); if (!mse) - return -ENOMEM; + goto out; down(&mouse_sem); + ret = -EBUSY; if (busmouse_data[msedev]) - { - up(&mouse_sem); - kfree(mse); - return -EBUSY; - } + goto freemem; memset(mse, 0, sizeof(*mse)); @@ -386,14 +384,22 @@ mse->lock = (spinlock_t)SPIN_LOCK_UNLOCKED; init_waitqueue_head(&mse->wait); - busmouse_data[msedev] = mse; ret = misc_register(&mse->miscdev); - if (!ret) - ret = msedev; + + if (ret < 0) + goto freemem; + + busmouse_data[msedev] = mse; + ret = msedev; +out: up(&mouse_sem); - return ret; + + +freemem: + kfree(mse); + goto out; } /** diff -Nru a/drivers/char/ftape/lowlevel/fdc-io.c b/drivers/char/ftape/lowlevel/fdc-io.c --- a/drivers/char/ftape/lowlevel/fdc-io.c Sun Jul 27 10:13:42 2003 +++ b/drivers/char/ftape/lowlevel/fdc-io.c Sun Jul 27 10:13:42 2003 @@ -66,6 +66,7 @@ /* Local vars. */ +static spinlock_t fdc_io_lock; static unsigned int fdc_calibr_count; static unsigned int fdc_calibr_time; static int fdc_status; @@ -89,14 +90,13 @@ { unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&fdc_io_lock, flags); if (count == 0) { ft_expected_stray_interrupts = 0; } else { ft_expected_stray_interrupts += count; } - restore_flags(flags); + spin_unlock_irqrestore(&fdc_io_lock, flags); } /* Wait during a timeout period for a given FDC status. @@ -194,8 +194,7 @@ TRACE_FUN(ft_t_any); fdc_usec_wait(FT_RQM_DELAY); /* wait for valid RQM status */ - save_flags(flags); - cli(); + spin_lock_irqsave(&fdc_io_lock, flags); if (!in_interrupt()) /* Yes, I know, too much comments inside this function * ... @@ -242,12 +241,11 @@ } fdc_usec_wait(FT_RQM_DELAY); /* wait for valid RQM status */ - save_flags(flags); - cli(); + spin_lock_irqsave(&fdc_io_lock, flags); } fdc_status = inb(fdc.msr); if ((fdc_status & FDC_DATA_READY_MASK) != FDC_DATA_IN_READY) { - restore_flags(flags); + spin_unlock_irqrestore(&fdc_io_lock, flags); TRACE_ABORT(-EBUSY, ft_t_err, "fdc not ready"); } fdc_mode = *cmd_data; /* used by isr */ @@ -289,7 +287,7 @@ last_time = ftape_timestamp(); } #endif - restore_flags(flags); + spin_unlock_irqrestore(&fdc_io_lock, flags); TRACE_EXIT result; } @@ -305,15 +303,14 @@ int retry = 0; TRACE_FUN(ft_t_any); - save_flags(flags); - cli(); + spin_lock_irqsave(&fdc_io_lock, flags); fdc_status = inb(fdc.msr); if ((fdc_status & FDC_DATA_READY_MASK) != FDC_DATA_OUT_READY) { TRACE(ft_t_err, "fdc not ready"); result = -EBUSY; } else while (count) { if (!(fdc_status & FDC_BUSY)) { - restore_flags(flags); + spin_unlock_irqrestore(&fdc_io_lock, flags); TRACE_ABORT(-EIO, ft_t_err, "premature end of result phase"); } result = fdc_read(res_data); @@ -336,7 +333,7 @@ ++res_data; } } - restore_flags(flags); + spin_unlock_irqrestore(&fdc_io_lock, flags); fdc_usec_wait(FT_RQM_DELAY); /* allow FDC to negate BSY */ TRACE_EXIT result; } @@ -609,8 +606,7 @@ unsigned long flags; TRACE_FUN(ft_t_any); - save_flags(flags); - cli(); + spin_lock_irqsave(&fdc_io_lock, flags); fdc_dor_reset(1); /* keep unit selected */ @@ -629,7 +625,7 @@ */ fdc_update_dsr(); /* restore data rate and precomp */ - restore_flags(flags); + spin_unlock_irqrestore(&fdc_io_lock, flags); /* * Wait for first polling cycle to complete @@ -928,8 +924,7 @@ */ TRACE(ft_t_fdc_dma, "phys. addr. = %lx", virt_to_bus((void*) buff->ptr)); - save_flags(flags); - cli(); /* could be called from ISR ! */ + spin_lock_irqsave(&fdc_io_lock, flags); fdc_setup_dma(DMA_MODE_WRITE, buff->ptr, FT_SECTORS_PER_SEGMENT * 4); /* Issue FDC command to start reading/writing. */ @@ -937,7 +932,7 @@ out[4] = buff->gap3; TRACE_CATCH(fdc_setup_error = fdc_command(out, sizeof(out)), restore_flags(flags); fdc_mode = fdc_idle); - restore_flags(flags); + spin_unlock_irqrestore(&fdc_io_lock, flags); TRACE_EXIT 0; } @@ -977,11 +972,10 @@ break; default: TRACE_ABORT(-EIO, - ft_t_bug, "bug: illegal operation parameter"); + ft_t_bug, "bug: invalid operation parameter"); } TRACE(ft_t_fdc_dma, "phys. addr. = %lx",virt_to_bus((void*)buff->ptr)); - save_flags(flags); - cli(); /* could be called from ISR ! */ + spin_lock_irqsave(&fdc_io_lock, flags); if (operation != FDC_VERIFY) { fdc_setup_dma(dma_mode, buff->ptr, FT_SECTOR_SIZE * buff->sector_count); @@ -999,7 +993,7 @@ out[8] = 0xff; /* No limit to transfer size. */ TRACE(ft_t_fdc_dma, "C: 0x%02x, H: 0x%02x, R: 0x%02x, cnt: 0x%02x", out[2], out[3], out[4], out[6] - out[4] + 1); - restore_flags(flags); + spin_unlock_irqrestore(&fdc_io_lock, flags); TRACE_CATCH(fdc_setup_error = fdc_command(out, 9),fdc_mode = fdc_idle); TRACE_EXIT 0; } diff -Nru a/drivers/char/ftape/lowlevel/ftape-calibr.c b/drivers/char/ftape/lowlevel/ftape-calibr.c --- a/drivers/char/ftape/lowlevel/ftape-calibr.c Sun Jul 27 10:13:43 2003 +++ b/drivers/char/ftape/lowlevel/ftape-calibr.c Sun Jul 27 10:13:43 2003 @@ -49,6 +49,8 @@ static unsigned long ps_per_cycle = 0; #endif +static spinlock_t calibr_lock; + /* * Note: On Intel PCs, the clock ticks at 100 Hz (HZ==100) which is * too slow for certain timeouts (and that clock doesn't even tick @@ -75,13 +77,12 @@ __u16 lo; __u16 hi; - save_flags(flags); - cli(); + spin_lock_irqsave(&calibr_lock, flags); outb_p(0x00, 0x43); /* latch the count ASAP */ lo = inb_p(0x40); /* read the latched count */ lo |= inb(0x40) << 8; hi = jiffies; - restore_flags(flags); + spin_unlock_irqrestore(&calibr_lock, flags); return ((hi + 1) * (unsigned int) LATCH) - lo; /* downcounter ! */ #endif } @@ -94,12 +95,11 @@ unsigned int count; unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&calibr_lock, flags); outb_p(0x00, 0x43); /* latch the count ASAP */ count = inb_p(0x40); /* read the latched count */ count |= inb(0x40) << 8; - restore_flags(flags); + spin_unlock_irqrestore(&calibr_lock, flags); return (LATCH - count); /* normal: downcounter */ #endif } @@ -150,14 +150,13 @@ int status; TRACE_FUN(ft_t_any); - save_flags(flags); - cli(); + spin_lock_irqsave(&calibr_lock, flags); t0 = short_ftape_timestamp(); for (i = 0; i < 1000; ++i) { status = inb(fdc.msr); } t1 = short_ftape_timestamp(); - restore_flags(flags); + spin_unlock_irqrestore(&calibr_lock, flags); TRACE(ft_t_info, "inb() duration: %d nsec", ftape_timediff(t0, t1)); TRACE_EXIT; } @@ -241,8 +240,7 @@ *calibr_count = *calibr_time = count; /* set TC to 1 */ - save_flags(flags); - cli(); + spin_lock_irqsave(&calibr_lock, flags); fun(0); /* dummy, get code into cache */ t0 = short_ftape_timestamp(); fun(0); /* overhead + one test */ @@ -252,7 +250,7 @@ fun(count); /* overhead + count tests */ t1 = short_ftape_timestamp(); multiple = diff(t0, t1); - restore_flags(flags); + spin_unlock_irqrestore(&calibr_lock, flags); time = ftape_timediff(0, multiple - once); tc = (1000 * time) / (count - 1); TRACE(ft_t_any, "once:%3d us,%6d times:%6d us, TC:%5d ns", diff -Nru a/drivers/char/ftape/lowlevel/ftape-format.c b/drivers/char/ftape/lowlevel/ftape-format.c --- a/drivers/char/ftape/lowlevel/ftape-format.c Sun Jul 27 10:13:45 2003 +++ b/drivers/char/ftape/lowlevel/ftape-format.c Sun Jul 27 10:13:45 2003 @@ -44,6 +44,8 @@ #define FT_FMT_SEGS_PER_BUF (FT_BUFF_SIZE/(4*FT_SECTORS_PER_SEGMENT)) #endif +static spinlock_t ftape_format_lock; + /* * first segment of the new buffer */ @@ -129,9 +131,9 @@ head->status = formatting; TRACE_CATCH(ftape_seek_head_to_track(track),); TRACE_CATCH(ftape_command(QIC_LOGICAL_FORWARD),); - save_flags(flags); cli(); + spin_lock_irqsave(&ftape_format_lock, flags); TRACE_CATCH(fdc_setup_formatting(head), restore_flags(flags)); - restore_flags(flags); + spin_unlock_irqrestore(&ftape_format_lock, flags); TRACE_EXIT 0; } diff -Nru a/drivers/char/ftape/zftape/zftape-init.c b/drivers/char/ftape/zftape/zftape-init.c --- a/drivers/char/ftape/zftape/zftape-init.c Sun Jul 27 10:13:44 2003 +++ b/drivers/char/ftape/zftape/zftape-init.c Sun Jul 27 10:13:44 2003 @@ -118,7 +118,7 @@ > FTAPE_SEL_D) { clear_bit(0,&busy_flag); - TRACE_ABORT(-ENXIO, ft_t_err, "failed: illegal unit nr"); + TRACE_ABORT(-ENXIO, ft_t_err, "failed: invalid unit nr"); } orig_sigmask = current->blocked; sigfillset(¤t->blocked); diff -Nru a/drivers/char/ip2/i2lib.c b/drivers/char/ip2/i2lib.c --- a/drivers/char/ip2/i2lib.c Sun Jul 27 10:13:52 2003 +++ b/drivers/char/ip2/i2lib.c Sun Jul 27 10:13:52 2003 @@ -1089,7 +1089,7 @@ // Move the data if ( user ) { - COPY_FROM_USER(rc, (char*)(DATA_OF(pInsert)), pSource, + rc = copy_from_user((char*)(DATA_OF(pInsert)), pSource, amountToMove ); } else { memcpy( (char*)(DATA_OF(pInsert)), pSource, amountToMove ); diff -Nru a/drivers/char/ip2/i2os.h b/drivers/char/ip2/i2os.h --- a/drivers/char/ip2/i2os.h Sun Jul 27 10:13:45 2003 +++ b/drivers/char/ip2/i2os.h Sun Jul 27 10:13:45 2003 @@ -19,8 +19,6 @@ #ifndef I2OS_H /* To prevent multiple includes */ #define I2OS_H 1 -#define VERSION(ver,rel,seq) (((ver)<<16) | ((rel)<<8) | (seq)) - //------------------------------------------------- // Required Includes //------------------------------------------------- @@ -45,22 +43,6 @@ //-------------------------------------------- // Interrupt control //-------------------------------------------- - -#if LINUX_VERSION_CODE < 0x00020100 -typedef int spinlock_t; -#define spin_lock_init() -#define spin_lock(a) -#define spin_unlock(a) -#define spin_lock_irqsave(a,b) {save_flags((b));cli();} -#define spin_unlock_irqrestore(a,b) {restore_flags((b));} -#define write_lock_irqsave(a,b) spin_lock_irqsave(a,b) -#define write_unlock_irqrestore(a,b) spin_unlock_irqrestore(a,b) -#define read_lock_irqsave(a,b) spin_lock_irqsave(a,b) -#define read_unlock_irqrestore(a,b) spin_unlock_irqrestore(a,b) -#endif - -//#define SAVE_AND_DISABLE_INTS(a,b) spin_lock_irqsave(a,b) -//#define RESTORE_INTS(a,b) spin_unlock_irqrestore(a,b) #define LOCK_INIT(a) rwlock_init(a) diff -Nru a/drivers/char/ip2.c b/drivers/char/ip2.c --- a/drivers/char/ip2.c Sun Jul 27 10:13:45 2003 +++ b/drivers/char/ip2.c Sun Jul 27 10:13:45 2003 @@ -38,16 +38,14 @@ static int poll_only = 0; -# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) - MODULE_AUTHOR("Doug McNash"); - MODULE_DESCRIPTION("Computone IntelliPort Plus Driver"); - MODULE_PARM(irq,"1-"__MODULE_STRING(IP2_MAX_BOARDS) "i"); - MODULE_PARM_DESC(irq,"Interrupts for IntelliPort Cards"); - MODULE_PARM(io,"1-"__MODULE_STRING(IP2_MAX_BOARDS) "i"); - MODULE_PARM_DESC(io,"I/O ports for IntelliPort Cards"); - MODULE_PARM(poll_only,"1i"); - MODULE_PARM_DESC(poll_only,"Do not use card interrupts"); -# endif /* LINUX_VERSION */ +MODULE_AUTHOR("Doug McNash"); +MODULE_DESCRIPTION("Computone IntelliPort Plus Driver"); +MODULE_PARM(irq,"1-"__MODULE_STRING(IP2_MAX_BOARDS) "i"); +MODULE_PARM_DESC(irq,"Interrupts for IntelliPort Cards"); +MODULE_PARM(io,"1-"__MODULE_STRING(IP2_MAX_BOARDS) "i"); +MODULE_PARM_DESC(io,"I/O ports for IntelliPort Cards"); +MODULE_PARM(poll_only,"1i"); +MODULE_PARM_DESC(poll_only,"Do not use card interrupts"); //====================================================================== diff -Nru a/drivers/char/ip2main.c b/drivers/char/ip2main.c --- a/drivers/char/ip2main.c Sun Jul 27 10:13:52 2003 +++ b/drivers/char/ip2main.c Sun Jul 27 10:13:52 2003 @@ -83,7 +83,6 @@ /* Includes */ /************/ #include -// Uncomment the following if you want it compiled with modversions #include @@ -120,82 +119,11 @@ #include #include -#ifndef KERNEL_VERSION -#define KERNEL_VERSION(ver,rel,seq) (((ver)<<16) | ((rel)<<8) | (seq)) -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) -# include -# include -# include -#else -# include -#endif +#include +#include +#include -// These VERSION switches maybe inexact because I simply don't know -// when the various features appeared in the 2.1.XX kernels. -// They are good enough for 2.0 vs 2.2 and if you are fooling with -// the 2.1.XX stuff then it would be trivial for you to fix. -// Most of these macros were stolen from some other drivers -// so blame them. - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,4) -# define GET_USER(error,value,addr) error = get_user(value,addr) -# define COPY_FROM_USER(error,dest,src,size) error = copy_from_user(dest,src,size) ? -EFAULT : 0 -# define PUT_USER(error,value,addr) error = put_user(value,addr) -# define COPY_TO_USER(error,dest,src,size) error = copy_to_user(dest,src,size) ? -EFAULT : 0 - -# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,5) -# include -# define pcibios_strerror(status) \ - printk( KERN_ERR "IP2: PCI error 0x%x \n", status ); -# endif - -#else /* 2.0.x and 2.1.x before 2.1.4 */ - -# define proc_register_dynamic(a,b) proc_register(a,b) - -# define GET_USER(error,value,addr) \ - do { \ - error = verify_area (VERIFY_READ, (void *) addr, sizeof (value)); \ - if (error == 0) \ - value = get_user(addr); \ - } while (0) - -# define COPY_FROM_USER(error,dest,src,size) \ - do { \ - error = verify_area (VERIFY_READ, (void *) src, size); \ - if (error == 0) \ - memcpy_fromfs (dest, src, size); \ - } while (0) - -# define PUT_USER(error,value,addr) \ - do { \ - error = verify_area (VERIFY_WRITE, (void *) addr, sizeof (value)); \ - if (error == 0) \ - put_user (value, addr); \ - } while (0) - -# define COPY_TO_USER(error,dest,src,size) \ - do { \ - error = verify_area (VERIFY_WRITE, (void *) dest, size); \ - if (error == 0) \ - memcpy_tofs (dest, src, size); \ - } while (0) - -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) -#define __init -#define __initfunc(a) a -#define __initdata -#define ioremap(a,b) vremap((a),(b)) -#define iounmap(a) vfree((a)) -#define SERIAL_TYPE_NORMAL 1 -#define schedule_timeout(a){current->timeout = jiffies + (a); schedule();} -#define signal_pending(a) ((a)->signal & ~(a)->blocked) -#define in_interrupt() intr_count -#endif +#include #include "./ip2/ip2types.h" #include "./ip2/ip2trace.h" @@ -276,11 +204,7 @@ static int get_serial_info(i2ChanStrPtr, struct serial_struct *); static int set_serial_info(i2ChanStrPtr, struct serial_struct *); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) -static int ip2_ipl_read(struct inode *, char *, size_t , loff_t *); -#else -static ssize_t ip2_ipl_read(struct file *, char *, size_t, loff_t *) ; -#endif +static ssize_t ip2_ipl_read(struct file *, char *, size_t, loff_t *); static ssize_t ip2_ipl_write(struct file *, const char *, size_t, loff_t *); static int ip2_ipl_ioctl(struct inode *, struct file *, UINT, ULONG); static int ip2_ipl_open(struct inode *, struct file *); @@ -354,9 +278,6 @@ #define DBG_CNT(s) #endif -#define MIN(a,b) ( ( (a) < (b) ) ? (a) : (b) ) -#define MAX(a,b) ( ( (a) > (b) ) ? (a) : (b) ) - /********/ /* Code */ /********/ @@ -366,12 +287,9 @@ #include "./ip2/i2lib.c" /* High level interface services */ /* Configuration area for modprobe */ -#ifdef MODULE -# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) - MODULE_AUTHOR("Doug McNash"); - MODULE_DESCRIPTION("Computone IntelliPort Plus Driver"); -# endif /* LINUX_VERSION */ -#endif /* MODULE */ + +MODULE_AUTHOR("Doug McNash"); +MODULE_DESCRIPTION("Computone IntelliPort Plus Driver"); static int poll_only = 0; @@ -660,53 +578,6 @@ break; case PCI: #ifdef CONFIG_PCI -#if (LINUX_VERSION_CODE < 0x020163) /* 2.1.99 */ - if (pcibios_present()) { - unsigned char pci_bus, pci_devfn; - int Pci_index = 0; - status = pcibios_find_device(PCI_VENDOR_ID_COMPUTONE, - PCI_DEVICE_ID_COMPUTONE_IP2EX, Pci_index, - &pci_bus, &pci_devfn); - if (status == 0) { - unsigned int addr; - unsigned char pci_irq; - - ip2config.type[i] = PCI; - /* - * Update Pci_index, so that the next time we go - * searching for a PCI board we find a different - * one. - */ - ++Pci_index; - - pcibios_read_config_dword(pci_bus, pci_devfn, - PCI_BASE_ADDRESS_1, &addr); - if ( addr & 1 ) { - ip2config.addr[i]=(USHORT)(addr&0xfffe); - } else { - printk( KERN_ERR "IP2: PCI I/O address error\n"); - } - pcibios_read_config_byte(pci_bus, pci_devfn, - PCI_INTERRUPT_LINE, &pci_irq); - -// If the PCI BIOS assigned it, lets try and use it. If we -// can't acquire it or it screws up, deal with it then. - -// if (!is_valid_irq(pci_irq)) { -// printk( KERN_ERR "IP2: Bad PCI BIOS IRQ(%d)\n",pci_irq); -// pci_irq = 0; -// } - ip2config.irq[i] = pci_irq; - } else { // ann error - ip2config.addr[i] = 0; - if (status == PCIBIOS_DEVICE_NOT_FOUND) { - printk( KERN_ERR "IP2: PCI board %d not found\n", i ); - } else { - pcibios_strerror(status); - } - } - } -#else /* LINUX_VERSION_CODE > 2.1.99 */ { struct pci_dev *pci_dev_i = NULL; pci_dev_i = pci_find_device(PCI_VENDOR_ID_COMPUTONE, @@ -739,11 +610,10 @@ if (status == PCIBIOS_DEVICE_NOT_FOUND) { printk( KERN_ERR "IP2: PCI board %d not found\n", i ); } else { - pcibios_strerror(status); + printk( KERN_ERR "IP2: PCI error 0x%x \n", status ); } } } -#endif /* ! 2_0_X */ #else printk( KERN_ERR "IP2: PCI card specified but PCI support not\n"); printk( KERN_ERR "IP2: configured in this kernel.\n"); @@ -2193,7 +2063,7 @@ ip2trace (CHANN, ITRC_IOCTL, 6, 1, rc ); - PUT_USER(rc,C_CLOCAL(tty) ? 1 : 0, (unsigned long *) arg); + rc = put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *) arg); if (rc) return rc; break; @@ -2202,7 +2072,7 @@ ip2trace (CHANN, ITRC_IOCTL, 7, 1, rc ); - GET_USER(rc,arg,(unsigned long *) arg); + rc = get_user(arg,(unsigned long *) arg); if (rc) return rc; tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) @@ -2243,7 +2113,7 @@ return -EINTR; } #endif - PUT_USER(rc, + rc = put_user( ((pCh->dataSetOut & I2_RTS) ? TIOCM_RTS : 0) | ((pCh->dataSetOut & I2_DTR) ? TIOCM_DTR : 0) | ((pCh->dataSetIn & I2_DCD) ? TIOCM_CAR : 0) @@ -2333,17 +2203,17 @@ cnow = pCh->icount; restore_flags(flags); p_cuser = (struct serial_icounter_struct *) arg; - PUT_USER(rc,cnow.cts, &p_cuser->cts); - PUT_USER(rc,cnow.dsr, &p_cuser->dsr); - PUT_USER(rc,cnow.rng, &p_cuser->rng); - PUT_USER(rc,cnow.dcd, &p_cuser->dcd); - PUT_USER(rc,cnow.rx, &p_cuser->rx); - PUT_USER(rc,cnow.tx, &p_cuser->tx); - PUT_USER(rc,cnow.frame, &p_cuser->frame); - PUT_USER(rc,cnow.overrun, &p_cuser->overrun); - PUT_USER(rc,cnow.parity, &p_cuser->parity); - PUT_USER(rc,cnow.brk, &p_cuser->brk); - PUT_USER(rc,cnow.buf_overrun, &p_cuser->buf_overrun); + rc = put_user(cnow.cts, &p_cuser->cts); + rc = put_user(cnow.dsr, &p_cuser->dsr); + rc = put_user(cnow.rng, &p_cuser->rng); + rc = put_user(cnow.dcd, &p_cuser->dcd); + rc = put_user(cnow.rx, &p_cuser->rx); + rc = put_user(cnow.tx, &p_cuser->tx); + rc = put_user(cnow.frame, &p_cuser->frame); + rc = put_user(cnow.overrun, &p_cuser->overrun); + rc = put_user(cnow.parity, &p_cuser->parity); + rc = put_user(cnow.brk, &p_cuser->brk); + rc = put_user(cnow.buf_overrun, &p_cuser->buf_overrun); break; /* @@ -2387,7 +2257,7 @@ int rc; unsigned int arg; - GET_USER(rc,arg,value); + rc = get_user(arg,value); if (rc) return rc; switch(cmd) { @@ -2469,7 +2339,7 @@ tmp.close_delay = pCh->ClosingDelay; tmp.closing_wait = pCh->ClosingWaitTime; tmp.custom_divisor = pCh->BaudDivisor; - COPY_TO_USER(rc,retinfo,&tmp,sizeof(*retinfo)); + rc = copy_to_user(retinfo,&tmp,sizeof(*retinfo)); return rc; } @@ -2489,15 +2359,15 @@ { struct serial_struct ns; int old_flags, old_baud_divisor; - int rc = 0; if ( !new_info ) { return -EFAULT; } - COPY_FROM_USER(rc, &ns, new_info, sizeof (ns) ); - if (rc) { - return rc; + + if (copy_from_user(&ns, new_info, sizeof (ns))) { + return -EFAULT; } + /* * We don't allow setserial to change IRQ, board address, type or baud * base. Also line nunber as such is meaningless but we use it for our @@ -2537,7 +2407,7 @@ set_params( pCh, NULL ); } - return rc; + return 0; } /******************************************************************************/ @@ -2860,16 +2730,10 @@ /******************************************************************************/ static -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) -int -ip2_ipl_read(struct inode *pInode, char *pData, size_t count, loff_t *off ) - unsigned int minor = minor( pInode->i_rdev ); -#else ssize_t ip2_ipl_read(struct file *pFile, char *pData, size_t count, loff_t *off ) { unsigned int minor = minor( pFile->f_dentry->d_inode->i_rdev ); -#endif int rc = 0; #ifdef IP2DEBUG_IPL @@ -2904,7 +2768,7 @@ { #ifdef DEBUG_FIFO int rc; - COPY_TO_USER(rc, pData, DBGBuf, count); + rc = copy_to_user(pData, DBGBuf, count); printk(KERN_DEBUG "Last index %d\n", I ); @@ -2925,10 +2789,10 @@ if ( count < (sizeof(int) * 6) ) { return -EIO; } - PUT_USER(rc, tracewrap, pIndex ); - PUT_USER(rc, TRACEMAX, ++pIndex ); - PUT_USER(rc, tracestrip, ++pIndex ); - PUT_USER(rc, tracestuff, ++pIndex ); + rc = put_user(tracewrap, pIndex ); + rc = put_user(TRACEMAX, ++pIndex ); + rc = put_user(tracestrip, ++pIndex ); + rc = put_user(tracestuff, ++pIndex ); pData += sizeof(int) * 6; count -= sizeof(int) * 6; @@ -2941,7 +2805,7 @@ } chunk = TRACEMAX - tracestrip; if ( dumpcount > chunk ) { - COPY_TO_USER(rc, pData, &tracebuf[tracestrip], + rc = copy_to_user(pData, &tracebuf[tracestrip], chunk * sizeof(tracebuf[0]) ); pData += chunk * sizeof(tracebuf[0]); tracestrip = 0; @@ -2949,13 +2813,13 @@ } else { chunk = dumpcount; } - COPY_TO_USER(rc, pData, &tracebuf[tracestrip], + rc = copy_to_user(pData, &tracebuf[tracestrip], chunk * sizeof(tracebuf[0]) ); tracestrip += chunk; tracewrap = 0; - PUT_USER(rc, tracestrip, ++pIndex ); - PUT_USER(rc, tracestuff, ++pIndex ); + rc = put_user(tracestrip, ++pIndex ); + rc = put_user(tracestuff, ++pIndex ); return dumpcount; #else @@ -3019,15 +2883,15 @@ case 13: switch ( cmd ) { case 64: /* Driver - ip2stat */ - PUT_USER(rc, ip2_tty_driver->refcount, pIndex++ ); - PUT_USER(rc, irq_counter, pIndex++ ); - PUT_USER(rc, bh_counter, pIndex++ ); + rc = put_user(ip2_tty_driver->refcount, pIndex++ ); + rc = put_user(irq_counter, pIndex++ ); + rc = put_user(bh_counter, pIndex++ ); break; case 65: /* Board - ip2stat */ if ( pB ) { - COPY_TO_USER(rc, (char*)arg, (char*)pB, sizeof(i2eBordStr) ); - PUT_USER(rc, INB(pB->i2eStatus), + rc = copy_to_user((char*)arg, (char*)pB, sizeof(i2eBordStr) ); + rc = put_user(INB(pB->i2eStatus), (ULONG*)(arg + (ULONG)(&pB->i2eStatus) - (ULONG)pB ) ); } else { rc = -ENODEV; @@ -3039,7 +2903,7 @@ pCh = DevTable[cmd]; if ( pCh ) { - COPY_TO_USER(rc, (char*)arg, (char*)pCh, sizeof(i2ChanStr) ); + rc = copy_to_user((char*)arg, (char*)pCh, sizeof(i2ChanStr) ); } else { rc = -ENODEV; } @@ -3054,60 +2918,60 @@ break; case 3: // Trace device if ( cmd == 1 ) { - PUT_USER(rc, iiSendPendingMail, pIndex++ ); - PUT_USER(rc, i2InitChannels, pIndex++ ); - PUT_USER(rc, i2QueueNeeds, pIndex++ ); - PUT_USER(rc, i2QueueCommands, pIndex++ ); - PUT_USER(rc, i2GetStatus, pIndex++ ); - PUT_USER(rc, i2Input, pIndex++ ); - PUT_USER(rc, i2InputFlush, pIndex++ ); - PUT_USER(rc, i2Output, pIndex++ ); - PUT_USER(rc, i2FlushOutput, pIndex++ ); - PUT_USER(rc, i2DrainWakeup, pIndex++ ); - PUT_USER(rc, i2DrainOutput, pIndex++ ); - PUT_USER(rc, i2OutputFree, pIndex++ ); - PUT_USER(rc, i2StripFifo, pIndex++ ); - PUT_USER(rc, i2StuffFifoBypass, pIndex++ ); - PUT_USER(rc, i2StuffFifoFlow, pIndex++ ); - PUT_USER(rc, i2StuffFifoInline, pIndex++ ); - PUT_USER(rc, i2ServiceBoard, pIndex++ ); - PUT_USER(rc, serviceOutgoingFifo, pIndex++ ); - // PUT_USER(rc, ip2_init, pIndex++ ); - PUT_USER(rc, ip2_init_board, pIndex++ ); - PUT_USER(rc, find_eisa_board, pIndex++ ); - PUT_USER(rc, set_irq, pIndex++ ); - PUT_USER(rc, ip2_interrupt, pIndex++ ); - PUT_USER(rc, ip2_poll, pIndex++ ); - PUT_USER(rc, service_all_boards, pIndex++ ); - PUT_USER(rc, do_input, pIndex++ ); - PUT_USER(rc, do_status, pIndex++ ); + rc = put_user(iiSendPendingMail, pIndex++ ); + rc = put_user(i2InitChannels, pIndex++ ); + rc = put_user(i2QueueNeeds, pIndex++ ); + rc = put_user(i2QueueCommands, pIndex++ ); + rc = put_user(i2GetStatus, pIndex++ ); + rc = put_user(i2Input, pIndex++ ); + rc = put_user(i2InputFlush, pIndex++ ); + rc = put_user(i2Output, pIndex++ ); + rc = put_user(i2FlushOutput, pIndex++ ); + rc = put_user(i2DrainWakeup, pIndex++ ); + rc = put_user(i2DrainOutput, pIndex++ ); + rc = put_user(i2OutputFree, pIndex++ ); + rc = put_user(i2StripFifo, pIndex++ ); + rc = put_user(i2StuffFifoBypass, pIndex++ ); + rc = put_user(i2StuffFifoFlow, pIndex++ ); + rc = put_user(i2StuffFifoInline, pIndex++ ); + rc = put_user(i2ServiceBoard, pIndex++ ); + rc = put_user(serviceOutgoingFifo, pIndex++ ); + // rc = put_user(ip2_init, pIndex++ ); + rc = put_user(ip2_init_board, pIndex++ ); + rc = put_user(find_eisa_board, pIndex++ ); + rc = put_user(set_irq, pIndex++ ); + rc = put_user(ip2_interrupt, pIndex++ ); + rc = put_user(ip2_poll, pIndex++ ); + rc = put_user(service_all_boards, pIndex++ ); + rc = put_user(do_input, pIndex++ ); + rc = put_user(do_status, pIndex++ ); #ifndef IP2DEBUG_OPEN - PUT_USER(rc, 0, pIndex++ ); + rc = put_user(0, pIndex++ ); #else - PUT_USER(rc, open_sanity_check, pIndex++ ); + rc = put_user(open_sanity_check, pIndex++ ); #endif - PUT_USER(rc, ip2_open, pIndex++ ); - PUT_USER(rc, ip2_close, pIndex++ ); - PUT_USER(rc, ip2_hangup, pIndex++ ); - PUT_USER(rc, ip2_write, pIndex++ ); - PUT_USER(rc, ip2_putchar, pIndex++ ); - PUT_USER(rc, ip2_flush_chars, pIndex++ ); - PUT_USER(rc, ip2_write_room, pIndex++ ); - PUT_USER(rc, ip2_chars_in_buf, pIndex++ ); - PUT_USER(rc, ip2_flush_buffer, pIndex++ ); - - //PUT_USER(rc, ip2_wait_until_sent, pIndex++ ); - PUT_USER(rc, 0, pIndex++ ); - - PUT_USER(rc, ip2_throttle, pIndex++ ); - PUT_USER(rc, ip2_unthrottle, pIndex++ ); - PUT_USER(rc, ip2_ioctl, pIndex++ ); - PUT_USER(rc, set_modem_info, pIndex++ ); - PUT_USER(rc, get_serial_info, pIndex++ ); - PUT_USER(rc, set_serial_info, pIndex++ ); - PUT_USER(rc, ip2_set_termios, pIndex++ ); - PUT_USER(rc, ip2_set_line_discipline, pIndex++ ); - PUT_USER(rc, set_params, pIndex++ ); + rc = put_user(ip2_open, pIndex++ ); + rc = put_user(ip2_close, pIndex++ ); + rc = put_user(ip2_hangup, pIndex++ ); + rc = put_user(ip2_write, pIndex++ ); + rc = put_user(ip2_putchar, pIndex++ ); + rc = put_user(ip2_flush_chars, pIndex++ ); + rc = put_user(ip2_write_room, pIndex++ ); + rc = put_user(ip2_chars_in_buf, pIndex++ ); + rc = put_user(ip2_flush_buffer, pIndex++ ); + + //rc = put_user(ip2_wait_until_sent, pIndex++ ); + rc = put_user(0, pIndex++ ); + + rc = put_user(ip2_throttle, pIndex++ ); + rc = put_user(ip2_unthrottle, pIndex++ ); + rc = put_user(ip2_ioctl, pIndex++ ); + rc = put_user(set_modem_info, pIndex++ ); + rc = put_user(get_serial_info, pIndex++ ); + rc = put_user(set_serial_info, pIndex++ ); + rc = put_user(ip2_set_termios, pIndex++ ); + rc = put_user(ip2_set_line_discipline, pIndex++ ); + rc = put_user(set_params, pIndex++ ); } else { rc = -EINVAL; } diff -Nru a/drivers/char/istallion.c b/drivers/char/istallion.c --- a/drivers/char/istallion.c Sun Jul 27 10:13:47 2003 +++ b/drivers/char/istallion.c Sun Jul 27 10:13:47 2003 @@ -650,8 +650,6 @@ */ #ifdef MODULE -int init_module(void); -void cleanup_module(void); static void stli_argbrds(void); static int stli_parsebrd(stlconf_t *confp, char **argp); diff -Nru a/drivers/char/moxa.c b/drivers/char/moxa.c --- a/drivers/char/moxa.c Sun Jul 27 10:13:51 2003 +++ b/drivers/char/moxa.c Sun Jul 27 10:13:51 2003 @@ -216,10 +216,7 @@ static struct semaphore moxaBuffSem; int moxa_init(void); -#ifdef MODULE -int init_module(void); -void cleanup_module(void); -#endif + /* * static functions: */ diff -Nru a/drivers/char/nwbutton.h b/drivers/char/nwbutton.h --- a/drivers/char/nwbutton.h Sun Jul 27 10:13:43 2003 +++ b/drivers/char/nwbutton.h Sun Jul 27 10:13:43 2003 @@ -32,10 +32,6 @@ int button_add_callback (void (*callback) (void), int count); int button_del_callback (void (*callback) (void)); static void button_consume_callbacks (int bpcount); -#ifdef MODULE -int init_module (void); -void cleanup_module (void); -#endif /* MODULE */ #else /* Not compiling the driver itself */ diff -Nru a/drivers/char/pcxx.c b/drivers/char/pcxx.c --- a/drivers/char/pcxx.c Sun Jul 27 10:13:47 2003 +++ b/drivers/char/pcxx.c Sun Jul 27 10:13:47 2003 @@ -209,17 +209,9 @@ #ifdef MODULE -/* - * pcxe_init() is our init_module(): - */ -#define pcxe_init init_module - -void cleanup_module(void); - - /*****************************************************************************/ -void cleanup_module() +static void pcxe_cleanup() { unsigned long flags; @@ -240,6 +232,12 @@ kfree(digi_channels); restore_flags(flags); } + +/* + * pcxe_init() is our init_module(): + */ +module_init(pcxe_init); +module_cleanup(pcxe_cleanup); #endif static inline struct channel *chan(register struct tty_struct *tty) diff -Nru a/drivers/char/stallion.c b/drivers/char/stallion.c --- a/drivers/char/stallion.c Sun Jul 27 10:13:49 2003 +++ b/drivers/char/stallion.c Sun Jul 27 10:13:49 2003 @@ -472,8 +472,6 @@ */ #ifdef MODULE -int init_module(void); -void cleanup_module(void); static void stl_argbrds(void); static int stl_parsebrd(stlconf_t *confp, char **argp); diff -Nru a/drivers/char/watchdog/acquirewdt.c b/drivers/char/watchdog/acquirewdt.c --- a/drivers/char/watchdog/acquirewdt.c Sun Jul 27 10:13:47 2003 +++ b/drivers/char/watchdog/acquirewdt.c Sun Jul 27 10:13:47 2003 @@ -143,7 +143,7 @@ return -EBUSY; } if (nowayout) - MOD_INC_USE_COUNT; + __module_get(THIS_MODULE); /* Activate */ acq_is_open=1; diff -Nru a/drivers/char/watchdog/i810-tco.c b/drivers/char/watchdog/i810-tco.c --- a/drivers/char/watchdog/i810-tco.c Sun Jul 27 10:13:40 2003 +++ b/drivers/char/watchdog/i810-tco.c Sun Jul 27 10:13:40 2003 @@ -25,7 +25,8 @@ * 82801AA & 82801AB chip : document number 290655-003, 290677-004, * 82801BA & 82801BAM chip : document number 290687-002, 298242-005, * 82801CA & 82801CAM chip : document number 290716-001, 290718-001, - * 82801DB & 82801E chip : document number 290744-001, 273599-001 + * 82801DB & 82801E chip : document number 290744-001, 273599-001, + * 82801EB & 82801ER chip : document number 252516-001 * * 20000710 Nils Faerber * Initial Version 0.01 @@ -42,9 +43,11 @@ * clean up ioctls (WDIOC_GETSTATUS, WDIOC_GETBOOTSTATUS and * WDIOC_SETOPTIONS), made i810tco_getdevice __init, * removed boot_status, removed tco_timer_read, - * added support for 82801DB and 82801E chipset, general cleanup. + * added support for 82801DB and 82801E chipset, + * added support for 82801EB and 8280ER chipset, + * general cleanup. */ - + #include #include #include @@ -164,7 +167,7 @@ * Reload (trigger) the timer. Lock is needed so we don't reload it during * a reprogramming event */ - + static void tco_timer_reload (void) { spin_lock(&tco_lock); @@ -307,6 +310,7 @@ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, PCI_ANY_ID, PCI_ANY_ID, }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, PCI_ANY_ID, PCI_ANY_ID, }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801E_0, PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, PCI_ANY_ID, PCI_ANY_ID, }, { 0, }, }; MODULE_DEVICE_TABLE (pci, i810tco_pci_tbl); diff -Nru a/drivers/char/watchdog/i810-tco.h b/drivers/char/watchdog/i810-tco.h --- a/drivers/char/watchdog/i810-tco.h Sun Jul 27 10:13:49 2003 +++ b/drivers/char/watchdog/i810-tco.h Sun Jul 27 10:13:49 2003 @@ -1,5 +1,5 @@ /* - * i810-tco 0.05: TCO timer driver for i8xx chipsets + * i810-tco: TCO timer driver for i8xx chipsets * * (c) Copyright 2000 kernel concepts , All Rights Reserved. * http://www.kernelconcepts.de @@ -8,7 +8,7 @@ * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. - * + * * Neither kernel concepts nor Nils Faerber admit liability nor provide * warranty for any of this software. This material is provided * "AS-IS" and at no charge. diff -Nru a/drivers/char/watchdog/ib700wdt.c b/drivers/char/watchdog/ib700wdt.c --- a/drivers/char/watchdog/ib700wdt.c Sun Jul 27 10:13:51 2003 +++ b/drivers/char/watchdog/ib700wdt.c Sun Jul 27 10:13:51 2003 @@ -230,7 +230,7 @@ return -EBUSY; } if (nowayout) - MOD_INC_USE_COUNT; + __module_get(THIS_MODULE); /* Activate */ ibwdt_is_open = 1; diff -Nru a/drivers/char/watchdog/indydog.c b/drivers/char/watchdog/indydog.c --- a/drivers/char/watchdog/indydog.c Sun Jul 27 10:13:51 2003 +++ b/drivers/char/watchdog/indydog.c Sun Jul 27 10:13:51 2003 @@ -54,7 +54,7 @@ return -EBUSY; if (nowayout) - MOD_INC_USE_COUNT; + __module_get(THIS_MODULE); /* * Activate timer diff -Nru a/drivers/char/watchdog/machzwd.c b/drivers/char/watchdog/machzwd.c --- a/drivers/char/watchdog/machzwd.c Sun Jul 27 10:13:42 2003 +++ b/drivers/char/watchdog/machzwd.c Sun Jul 27 10:13:42 2003 @@ -392,7 +392,7 @@ } if (nowayout) - MOD_INC_USE_COUNT; + __module_get(THIS_MODULE); zf_is_open = 1; diff -Nru a/drivers/char/watchdog/pcwd.c b/drivers/char/watchdog/pcwd.c --- a/drivers/char/watchdog/pcwd.c Sun Jul 27 10:13:41 2003 +++ b/drivers/char/watchdog/pcwd.c Sun Jul 27 10:13:41 2003 @@ -431,7 +431,7 @@ atomic_inc( &open_allowed ); return -EBUSY; } - MOD_INC_USE_COUNT; + __module_get(THIS_MODULE); /* Enable the port */ if (revision == PCWD_REVISION_C) { spin_lock(&io_lock); diff -Nru a/drivers/char/watchdog/sbc60xxwdt.c b/drivers/char/watchdog/sbc60xxwdt.c --- a/drivers/char/watchdog/sbc60xxwdt.c Sun Jul 27 10:13:49 2003 +++ b/drivers/char/watchdog/sbc60xxwdt.c Sun Jul 27 10:13:49 2003 @@ -207,9 +207,8 @@ /* Just in case we're already talking to someone... */ if(wdt_is_open) return -EBUSY; - if (nowayout) { - MOD_INC_USE_COUNT; - } + if (nowayout) + __module_get(THIS_MODULE); /* Good, fire up the show */ wdt_is_open = 1; wdt_startup(); diff -Nru a/drivers/char/watchdog/sc520_wdt.c b/drivers/char/watchdog/sc520_wdt.c --- a/drivers/char/watchdog/sc520_wdt.c Sun Jul 27 10:13:45 2003 +++ b/drivers/char/watchdog/sc520_wdt.c Sun Jul 27 10:13:45 2003 @@ -231,7 +231,7 @@ /* Good, fire up the show */ wdt_startup(); if (nowayout) - MOD_INC_USE_COUNT; + __module_get(THIS_MODULE); return 0; default: diff -Nru a/drivers/char/watchdog/shwdt.c b/drivers/char/watchdog/shwdt.c --- a/drivers/char/watchdog/shwdt.c Sun Jul 27 10:13:43 2003 +++ b/drivers/char/watchdog/shwdt.c Sun Jul 27 10:13:43 2003 @@ -3,7 +3,7 @@ * * Watchdog driver for integrated watchdog in the SuperH processors. * - * Copyright (C) 2001, 2002 Paul Mundt + * Copyright (C) 2001, 2002, 2003 Paul Mundt * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -12,6 +12,10 @@ * * 14-Dec-2001 Matt Domsch * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT + * + * 19-Apr-2002 Rob Radez + * Added expect close support, made emulated timeout runtime changeable + * general cleanups, add some ioctls */ #include #include @@ -22,76 +26,50 @@ #include #include #include +#include #include #include - -#if defined(CONFIG_CPU_SH5) - #define WTCNT CPRC_BASE + 0x10 - #define WTCSR CPRC_BASE + 0x18 -#elif defined(CONFIG_CPU_SH4) - #define WTCNT 0xffc00008 - #define WTCSR 0xffc0000c -#elif defined(CONFIG_CPU_SH3) - #define WTCNT 0xffffff84 - #define WTCSR 0xffffff86 -#else - #error "Can't use SuperH watchdog on this platform" -#endif - -#define WTCNT_HIGH 0x5a00 -#define WTCSR_HIGH 0xa500 - -#define WTCSR_TME 0x80 -#define WTCSR_WT 0x40 -#define WTCSR_RSTS 0x20 -#define WTCSR_WOVF 0x10 -#define WTCSR_IOVF 0x08 -#define WTCSR_CKS2 0x04 -#define WTCSR_CKS1 0x02 -#define WTCSR_CKS0 0x01 - -/* - * CKS0-2 supports a number of clock division ratios. At the time the watchdog - * is enabled, it defaults to a 41 usec overflow period .. we overload this to - * something a little more reasonable, and really can't deal with anything - * lower than WTCSR_CKS_1024, else we drop back into the usec range. - * - * Clock Division Ratio Overflow Period - * -------------------------------------------- - * 1/32 (initial value) 41 usecs - * 1/64 82 usecs - * 1/128 164 usecs - * 1/256 328 usecs - * 1/512 656 usecs - * 1/1024 1.31 msecs - * 1/2048 2.62 msecs - * 1/4096 5.25 msecs - */ -#define WTCSR_CKS_32 0x00 -#define WTCSR_CKS_64 0x01 -#define WTCSR_CKS_128 0x02 -#define WTCSR_CKS_256 0x03 -#define WTCSR_CKS_512 0x04 -#define WTCSR_CKS_1024 0x05 -#define WTCSR_CKS_2048 0x06 -#define WTCSR_CKS_4096 0x07 +#include /* - * Default clock division ratio is 5.25 msecs. Overload this at module load - * time. Any value not in the msec range will default to a timeout of one - * jiffy, which exceeds the usec overflow periods. + * Default clock division ratio is 5.25 msecs. For an additional table of + * values, consult the asm-sh/watchdog.h. Overload this at module load + * time. + * + * In order for this to work reliably we need to have HZ set to 1000 or + * something quite higher than 100 (or we need a proper high-res timer + * implementation that will deal with this properly), otherwise the 10ms + * resolution of a jiffy is enough to trigger the overflow. For things like + * the SH-4 and SH-5, this isn't necessarily that big of a problem, though + * for the SH-2 and SH-3, this isn't recommended unless the WDT is absolutely + * necssary. + * + * As a result of this timing problem, the only modes that are particularly + * feasible are the 4096 and the 2048 divisors, which yeild 5.25 and 2.62ms + * overflow periods respectively. + * + * Also, since we can't really expect userspace to be responsive enough + * before the overflow happens, we maintain two seperate timers .. One in + * the kernel for clearing out WOVF every 2ms or so (again, this depends on + * HZ == 1000), and another for monitoring userspace writes to the WDT device. + * + * As such, we currently use a configurable heartbeat interval which defaults + * to 30s. In this case, the userspace daemon is only responsible for periodic + * writes to the device before the next heartbeat is scheduled. If the daemon + * misses its deadline, the kernel timer will allow the WDT to overflow. */ static int clock_division_ratio = WTCSR_CKS_4096; -#define msecs_to_jiffies(msecs) (jiffies + ((HZ * msecs + 999) / 1000)) +#define msecs_to_jiffies(msecs) (jiffies + (HZ * msecs + 9999) / 10000) #define next_ping_period(cks) msecs_to_jiffies(cks - 4) -#define user_ping_period(cks) (next_ping_period(cks) * 10) -static unsigned long sh_is_open = 0; +static unsigned long shwdt_is_open; static struct watchdog_info sh_wdt_info; +static char shwdt_expect_close; static struct timer_list timer; static unsigned long next_heartbeat; +static int heartbeat = 30; #ifdef CONFIG_WATCHDOG_NOWAYOUT static int nowayout = 1; @@ -99,35 +77,6 @@ static int nowayout = 0; #endif -MODULE_PARM(nowayout,"i"); -MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); - -/** - * sh_wdt_write_cnt - Write to Counter - * - * @val: Value to write - * - * Writes the given value @val to the lower byte of the timer counter. - * The upper byte is set manually on each write. - */ -static void sh_wdt_write_cnt(__u8 val) -{ - ctrl_outw(WTCNT_HIGH | (__u16)val, WTCNT); -} - -/** - * sh_wdt_write_csr - Write to Control/Status Register - * - * @val: Value to write - * - * Writes the given value @val to the lower byte of the control/status - * register. The upper byte is set manually on each write. - */ -static void sh_wdt_write_csr(__u8 val) -{ - ctrl_outw(WTCSR_HIGH | (__u16)val, WTCSR); -} - /** * sh_wdt_start - Start the Watchdog * @@ -135,13 +84,44 @@ */ static void sh_wdt_start(void) { - timer.expires = next_ping_period(clock_division_ratio); - next_heartbeat = user_ping_period(clock_division_ratio); - add_timer(&timer); + __u8 csr; + + mod_timer(&timer, next_ping_period(clock_division_ratio)); + next_heartbeat = jiffies + (heartbeat * HZ); + + csr = sh_wdt_read_csr(); + csr |= WTCSR_WT | clock_division_ratio; + sh_wdt_write_csr(csr); - sh_wdt_write_csr(WTCSR_WT | WTCSR_CKS_4096); sh_wdt_write_cnt(0); - sh_wdt_write_csr((ctrl_inb(WTCSR) | WTCSR_TME)); + + /* + * These processors have a bit of an inconsistent initialization + * process.. starting with SH-3, RSTS was moved to WTCSR, and the + * RSTCSR register was removed. + * + * On the SH-2 however, in addition with bits being in different + * locations, we must deal with RSTCSR outright.. + */ + csr = sh_wdt_read_csr(); + csr |= WTCSR_TME; + csr &= ~WTCSR_RSTS; + sh_wdt_write_csr(csr); + +#ifdef CONFIG_CPU_SH2 + /* + * Whoever came up with the RSTCSR semantics must've been smoking + * some of the good stuff, since in addition to the WTCSR/WTCNT write + * brain-damage, it's managed to fuck things up one step further.. + * + * If we need to clear the WOVF bit, the upper byte has to be 0xa5.. + * but if we want to touch RSTE or RSTS, the upper byte has to be + * 0x5a.. + */ + csr = sh_wdt_read_rstcsr(); + csr &= ~RSTCSR_RSTS; + sh_wdt_write_rstcsr(csr); +#endif } /** @@ -151,9 +131,13 @@ */ static void sh_wdt_stop(void) { + __u8 csr; + del_timer(&timer); - sh_wdt_write_csr((ctrl_inb(WTCSR) & ~WTCSR_TME)); + csr = sh_wdt_read_csr(); + csr &= ~WTCSR_TME; + sh_wdt_write_csr(csr); } /** @@ -166,11 +150,15 @@ static void sh_wdt_ping(unsigned long data) { if (time_before(jiffies, next_heartbeat)) { - sh_wdt_write_csr((ctrl_inb(WTCSR) & ~WTCSR_IOVF)); + __u8 csr; + + csr = sh_wdt_read_csr(); + csr &= ~WTCSR_IOVF; + sh_wdt_write_csr(csr); + sh_wdt_write_cnt(0); - timer.expires = next_ping_period(clock_division_ratio); - add_timer(&timer); + mod_timer(&timer, next_ping_period(clock_division_ratio)); } } @@ -184,21 +172,12 @@ */ static int sh_wdt_open(struct inode *inode, struct file *file) { - switch (minor(inode->i_rdev)) { - case WATCHDOG_MINOR: - if (test_and_set_bit(0, &sh_is_open)) - return -EBUSY; + if (test_and_set_bit(0, &shwdt_is_open)) + return -EBUSY; + if (nowayout) + __module_get(THIS_MODULE); - if (nowayout) { - MOD_INC_USE_COUNT; - } - - sh_wdt_start(); - - break; - default: - return -ENODEV; - } + sh_wdt_start(); return 0; } @@ -213,33 +192,20 @@ */ static int sh_wdt_close(struct inode *inode, struct file *file) { - if (minor(inode->i_rdev) == WATCHDOG_MINOR) { - if (!nowayout) { - sh_wdt_stop(); - } - clear_bit(0, &sh_is_open); + if (!nowayout && shwdt_expect_close == 42) { + sh_wdt_stop(); + } else { + printk(KERN_CRIT "shwdt: Unexpected close, not stopping watchdog!\n"); + next_heartbeat = jiffies + (heartbeat * HZ); } + + clear_bit(0, &shwdt_is_open); + shwdt_expect_close = 0; return 0; } /** - * sh_wdt_read - Read from Device - * - * @file: file handle of device - * @buf: buffer to write to - * @count: length of buffer - * @ppos: offset - * - * Unsupported. - */ -static ssize_t sh_wdt_read(struct file *file, char *buf, - size_t count, loff_t *ppos) -{ - return -EINVAL; -} - -/** * sh_wdt_write - Write to Device * * @file: file handle of device @@ -257,11 +223,21 @@ return -ESPIPE; if (count) { - next_heartbeat = user_ping_period(clock_division_ratio); - return 1; + size_t i; + + shwdt_expect_close = 0; + + for (i = 0; i != count; i++) { + char c; + if (get_user(c, buf + i)) + return -EFAULT; + if (c == 'V') + shwdt_expect_close = 42; + } + next_heartbeat = jiffies + (heartbeat * HZ); } - return 0; + return count; } /** @@ -278,6 +254,8 @@ static int sh_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { + int new_timeout; + switch (cmd) { case WDIOC_GETSUPPORT: if (copy_to_user((struct watchdog_info *)arg, @@ -288,17 +266,41 @@ break; case WDIOC_GETSTATUS: - if (copy_to_user((int *)arg, - &sh_is_open, - sizeof(int))) { + case WDIOC_GETBOOTSTATUS: + return put_user(0, (int *)arg); + case WDIOC_KEEPALIVE: + next_heartbeat = jiffies + (heartbeat * HZ); + + break; + case WDIOC_SETTIMEOUT: + if (get_user(new_timeout, (int *)arg)) return -EFAULT; + if (new_timeout < 1 || new_timeout > 3600) /* arbitrary upper limit */ + return -EINVAL; + heartbeat = new_timeout; + next_heartbeat = jiffies + (heartbeat * HZ); + /* Fall */ + case WDIOC_GETTIMEOUT: + return put_user(heartbeat, (int *)arg); + case WDIOC_SETOPTIONS: + { + int options, retval = -EINVAL; + + if (get_user(options, (int *)arg)) + return -EFAULT; + + if (options & WDIOS_DISABLECARD) { + sh_wdt_stop(); + retval = 0; } - break; - case WDIOC_KEEPALIVE: - next_heartbeat = user_ping_period(clock_division_ratio); + if (options & WDIOS_ENABLECARD) { + sh_wdt_start(); + retval = 0; + } - break; + return retval; + } default: return -ENOTTY; } @@ -328,7 +330,7 @@ static struct file_operations sh_wdt_fops = { .owner = THIS_MODULE, - .read = sh_wdt_read, + .llseek = no_llseek, .write = sh_wdt_write, .ioctl = sh_wdt_ioctl, .open = sh_wdt_open, @@ -336,21 +338,20 @@ }; static struct watchdog_info sh_wdt_info = { - .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, - .firmware_version = 1, - .identity = "SH WDT", + .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, + .firmware_version = 1, + .identity = "SH WDT", }; static struct notifier_block sh_wdt_notifier = { - .notifier_call = sh_wdt_notify_sys, - .next = NULL, - .priority = 0 + .notifier_call = sh_wdt_notify_sys, + .priority = 0, }; static struct miscdevice sh_wdt_miscdev = { - .minor = WATCHDOG_MINOR, - .name = "watchdog", - .fops &sh_wdt_fops, + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &sh_wdt_fops, }; /** @@ -366,23 +367,8 @@ return -EINVAL; } - if (!request_region(WTCNT, 1, "shwdt")) { - printk(KERN_ERR "shwdt: Can't request WTCNT region\n"); - misc_deregister(&sh_wdt_miscdev); - return -ENXIO; - } - - if (!request_region(WTCSR, 1, "shwdt")) { - printk(KERN_ERR "shwdt: Can't request WTCSR region\n"); - release_region(WTCNT, 1); - misc_deregister(&sh_wdt_miscdev); - return -ENXIO; - } - if (register_reboot_notifier(&sh_wdt_notifier)) { printk(KERN_ERR "shwdt: Can't register reboot notifier\n"); - release_region(WTCSR, 1); - release_region(WTCNT, 1); misc_deregister(&sh_wdt_miscdev); return -EINVAL; } @@ -403,16 +389,16 @@ static void __exit sh_wdt_exit(void) { unregister_reboot_notifier(&sh_wdt_notifier); - release_region(WTCSR, 1); - release_region(WTCNT, 1); misc_deregister(&sh_wdt_miscdev); } -MODULE_AUTHOR("Paul Mundt "); +MODULE_AUTHOR("Paul Mundt "); MODULE_DESCRIPTION("SuperH watchdog driver"); MODULE_LICENSE("GPL"); MODULE_PARM(clock_division_ratio, "i"); MODULE_PARM_DESC(clock_division_ratio, "Clock division ratio. Valid ranges are from 0x5 (1.31ms) to 0x7 (5.25ms). Defaults to 0x7."); +MODULE_PARM(nowayout,"i"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); module_init(sh_wdt_init); module_exit(sh_wdt_exit); diff -Nru a/drivers/char/watchdog/softdog.c b/drivers/char/watchdog/softdog.c --- a/drivers/char/watchdog/softdog.c Sun Jul 27 10:13:44 2003 +++ b/drivers/char/watchdog/softdog.c Sun Jul 27 10:13:44 2003 @@ -104,9 +104,8 @@ { if(test_and_set_bit(0, &timer_alive)) return -EBUSY; - if (nowayout) { - MOD_INC_USE_COUNT; - } + if (nowayout) + __module_get(THIS_MODULE); /* * Activate timer */ diff -Nru a/drivers/char/watchdog/wdt977.c b/drivers/char/watchdog/wdt977.c --- a/drivers/char/watchdog/wdt977.c Sun Jul 27 10:13:50 2003 +++ b/drivers/char/watchdog/wdt977.c Sun Jul 27 10:13:50 2003 @@ -16,6 +16,8 @@ * 19-Dec-2001 Woody Suwalski: Netwinder fixes, ioctl interface * 06-Jan-2002 Woody Suwalski: For compatibility, convert all timeouts * from minutes to seconds. + * 07-Jul-2003 Daniele Bellucci: Audit return code of misc_register in + * nwwatchdog_init. */ #include @@ -99,7 +101,7 @@ if (nowayout) { - MOD_INC_USE_COUNT; + __module_get(THIS_MODULE); /* do not permit disabling the watchdog by writing 0 to reg. 0xF2 */ if (!timeoutM) timeoutM = DEFAULT_TIMEOUT; @@ -343,12 +345,14 @@ static int __init nwwatchdog_init(void) { + int retval; if (!machine_is_netwinder()) return -ENODEV; - misc_register(&wdt977_miscdev); - printk(KERN_INFO "Wdt977 Watchdog sleeping.\n"); - return 0; + retval = misc_register(&wdt977_miscdev); + if (!retval) + printk(KERN_INFO "Wdt977 Watchdog sleeping.\n"); + return retval; } static void __exit nwwatchdog_exit(void) diff -Nru a/drivers/char/watchdog/wdt_pci.c b/drivers/char/watchdog/wdt_pci.c --- a/drivers/char/watchdog/wdt_pci.c Sun Jul 27 10:13:48 2003 +++ b/drivers/char/watchdog/wdt_pci.c Sun Jul 27 10:13:48 2003 @@ -367,7 +367,7 @@ return -EBUSY; if (nowayout) { - MOD_INC_USE_COUNT; + __module_get(THIS_MODULE); } /* * Activate diff -Nru a/drivers/fc4/fc.c b/drivers/fc4/fc.c --- a/drivers/fc4/fc.c Sun Jul 27 10:13:47 2003 +++ b/drivers/fc4/fc.c Sun Jul 27 10:13:47 2003 @@ -33,7 +33,6 @@ #include #include #include -#include #include #include diff -Nru a/drivers/fc4/fcp_impl.h b/drivers/fc4/fcp_impl.h --- a/drivers/fc4/fcp_impl.h Sun Jul 27 10:13:44 2003 +++ b/drivers/fc4/fcp_impl.h Sun Jul 27 10:13:44 2003 @@ -8,7 +8,6 @@ #define _FCP_SCSI_H #include -#include #include "../scsi/scsi.h" #include "fc.h" diff -Nru a/drivers/ide/Kconfig b/drivers/ide/Kconfig --- a/drivers/ide/Kconfig Sun Jul 27 10:13:45 2003 +++ b/drivers/ide/Kconfig Sun Jul 27 10:13:45 2003 @@ -521,7 +521,7 @@ If you say Y here, you also need to say Y to "Use DMA by default when available", above. Please read the comments at the top of - . + . If unsure, say N. @@ -608,7 +608,7 @@ depends on BLK_DEV_HPT34X && IDEDMA_PCI_WIP help This is a dangerous thing to attempt currently! Please read the - comments at the top of . If you say Y + comments at the top of . If you say Y here, then say Y to "Use DMA by default when available" as well. If unsure, say N. @@ -670,14 +670,14 @@ This driver adds detection and support for the NS87415 chip (used in SPARC64, among others). - Please read the comments at the top of . + Please read the comments at the top of . config BLK_DEV_OPTI621 tristate "OPTi 82C621 chipset enhanced support (EXPERIMENTAL)" depends on PCI && BLK_DEV_IDEPCI && EXPERIMENTAL help This is a driver for the OPTi 82C621 EIDE controller. - Please read the comments at the top of . + Please read the comments at the top of . config BLK_DEV_PDC202XX_OLD tristate "PROMISE PDC202{46|62|65|67} support" @@ -696,7 +696,7 @@ when the PDC20265 BIOS has been disabled (for faster boot up). Please read the comments at the top of - . + . If unsure, say N. @@ -754,7 +754,7 @@ If you say Y here, you need to say Y to "Use DMA by default when available" as well. - Please read the comments at the top of . + Please read the comments at the top of . config BLK_DEV_SLC90E66 tristate "SLC90E66 chipset support" @@ -770,7 +770,7 @@ available" as well. Please read the comments at the top of - drivers/ide/slc90e66.c. + drivers/ide/pci/slc90e66.c. config BLK_DEV_TRM290 tristate "Tekram TRM290 chipset support" @@ -779,7 +779,7 @@ This driver adds support for bus master DMA transfers using the Tekram TRM290 PCI IDE chip. Volunteers are needed for further tweaking and development. - Please read the comments at the top of . + Please read the comments at the top of . config BLK_DEV_VIA82CXXX tristate "VIA82CXXX chipset support" @@ -1010,7 +1010,7 @@ boot parameter. It enables support for the secondary IDE interface of the ALI M1439/1443/1445/1487/1489 chipsets, and permits faster I/O speeds to be set as well. See the files - and for + and for more info. config BLK_DEV_DTC2278 @@ -1021,7 +1021,7 @@ boot parameter. It enables support for the secondary IDE interface of the DTC-2278 card, and permits faster I/O speeds to be set as well. See the and - files for more info. + files for more info. config BLK_DEV_HT6560B tristate "Holtek HT6560B support" @@ -1031,7 +1031,7 @@ boot parameter. It enables support for the secondary IDE interface of the Holtek card, and permits faster I/O speeds to be set as well. See the and - files for more info. + files for more info. config BLK_DEV_PDC4030 tristate "PROMISE DC4030 support (EXPERIMENTAL)" @@ -1044,7 +1044,7 @@ supported (and probably never will be since I don't think the cards support them). This driver is enabled at runtime using the "ide0=dc4030" or "ide1=dc4030" kernel boot parameter. See the - file for more info. + file for more info. config BLK_DEV_QD65XX tristate "QDI QD65xx support" @@ -1052,7 +1052,7 @@ help This driver is enabled at runtime using the "ide0=qd65xx" kernel boot parameter. It permits faster I/O speeds to be set. See the - and for + and for more info. config BLK_DEV_UMC8672 @@ -1063,7 +1063,7 @@ boot parameter. It enables support for the secondary IDE interface of the UMC-8672, and permits faster I/O speeds to be set as well. See the files and - for more info. + for more info. config BLK_DEV_HD_ONLY bool "Old hard disk (MFM/RLL/IDE) driver" @@ -1132,7 +1132,7 @@ available" as well. Please read the comments at the top of - . + . If unsure, say N. diff -Nru a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c --- a/drivers/ide/ide-cd.c Sun Jul 27 10:13:44 2003 +++ b/drivers/ide/ide-cd.c Sun Jul 27 10:13:44 2003 @@ -767,6 +767,9 @@ } else if (blk_fs_request(rq)) { /* Handle errors from READ and WRITE requests. */ + if (blk_noretry_request(rq)) + cdrom_end_request(drive, 0); + if (sense_key == NOT_READY) { /* Tray open. */ cdrom_saw_media_change (drive); diff -Nru a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c --- a/drivers/ide/ide-disk.c Sun Jul 27 10:13:44 2003 +++ b/drivers/ide/ide-disk.c Sun Jul 27 10:13:44 2003 @@ -907,7 +907,7 @@ /* force an abort */ hwif->OUTB(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG); } - if (rq->errors >= ERROR_MAX) + if (rq->errors >= ERROR_MAX || blk_noretry_request(rq)) DRIVER(drive)->end_request(drive, 0, 0); else { if ((rq->errors & ERROR_RESET) == ERROR_RESET) { @@ -1665,6 +1665,10 @@ drive->no_io_32bit = id->dword_io ? 1 : 0; if (drive->id->cfs_enable_2 & 0x3000) write_cache(drive, (id->cfs_enable_2 & 0x3000)); + +#ifdef CONFIG_BLK_DEV_IDE_TCQ_DEFAULT + HWIF(drive)->ide_dma_queued_on(drive); +#endif } static int idedisk_cleanup (ide_drive_t *drive) diff -Nru a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c --- a/drivers/ide/ide-dma.c Sun Jul 27 10:13:45 2003 +++ b/drivers/ide/ide-dma.c Sun Jul 27 10:13:45 2003 @@ -442,9 +442,10 @@ * the driver to resolve the problem, if a DMA transfer is still * in progress we continue to wait (arguably we need to add a * secondary 'I don't care what the drive thinks' timeout here) - * Finally if we have an interrupt but for some reason got the - * timeout first we complete the I/O. This can occur if an - * interrupt is lost or due to bugs. + * Finally if we have an interrupt we let it complete the I/O. + * But only one time - we clear expiry and if it's still not + * completed after WAIT_CMD, we error and retry in PIO. + * This can occur if an interrupt is lost or due to hang or bugs. */ static int dma_timer_expiry (ide_drive_t *drive) @@ -461,19 +462,16 @@ HWGROUP(drive)->expiry = NULL; /* one free ride for now */ /* 1 dmaing, 2 error, 4 intr */ - - if (dma_stat & 2) { /* ERROR */ - (void) hwif->ide_dma_end(drive); - return DRIVER(drive)->error(drive, - "dma_timer_expiry", hwif->INB(IDE_STATUS_REG)); - } + if (dma_stat & 2) /* ERROR */ + return -1; + if (dma_stat & 1) /* DMAing */ return WAIT_CMD; if (dma_stat & 4) /* Got an Interrupt */ - HWGROUP(drive)->handler(drive); + return WAIT_CMD; - return 0; + return 0; /* Status is unknown -- reset the bus */ } /** @@ -571,10 +569,6 @@ if (HWIF(drive)->ide_dma_host_on(drive)) return 1; - -#ifdef CONFIG_BLK_DEV_IDE_TCQ_DEFAULT - HWIF(drive)->ide_dma_queued_on(drive); -#endif return 0; } diff -Nru a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c --- a/drivers/ide/ide-io.c Sun Jul 27 10:13:50 2003 +++ b/drivers/ide/ide-io.c Sun Jul 27 10:13:50 2003 @@ -58,8 +58,7 @@ #if (DISK_RECOVERY_TIME > 0) -Error So the User Has To Fix the Compilation And Stop Hacking Port 0x43 -Does anyone ever use this anyway ?? +#error So the User Has To Fix the Compilation And Stop Hacking Port 0x43. Does anyone ever use this anyway ?? /* * For really screwy hardware (hey, at least it *can* be used with Linux) @@ -114,6 +113,13 @@ nr_sectors = rq->hard_cur_sectors; /* + * if failfast is set on a request, override number of sectors and + * complete the whole request right now + */ + if (blk_noretry_request(rq) && !uptodate) + nr_sectors = rq->hard_nr_sectors; + + /* * decide whether to reenable DMA -- 3 is a random magic for now, * if we DMA timeout more than 3 times, just stay in PIO */ @@ -949,14 +955,14 @@ * happens anyway when any interrupt comes in, IDE or otherwise * -- the kernel masks the IRQ while it is being handled. */ - if (masked_irq != IDE_NO_IRQ && hwif->irq != masked_irq) + if (hwif->irq != masked_irq) disable_irq_nosync(hwif->irq); spin_unlock(&ide_lock); local_irq_enable(); /* allow other IRQs while we start this request */ startstop = start_request(drive, rq); spin_lock_irq(&ide_lock); - if (masked_irq != IDE_NO_IRQ && hwif->irq != masked_irq) + if (hwif->irq != masked_irq) enable_irq(hwif->irq); if (startstop == ide_released) goto queue_next; @@ -980,21 +986,25 @@ * retry the current request in pio mode instead of risking tossing it * all away */ -void ide_dma_timeout_retry(ide_drive_t *drive) +static ide_startstop_t ide_dma_timeout_retry(ide_drive_t *drive, int error) { ide_hwif_t *hwif = HWIF(drive); struct request *rq; + ide_startstop_t ret = ide_stopped; /* * end current dma transaction */ - (void) hwif->ide_dma_end(drive); - /* - * complain a little, later we might remove some of this verbosity - */ - printk(KERN_WARNING "%s: timeout waiting for DMA\n", drive->name); - (void) hwif->ide_dma_timeout(drive); + if (error < 0) { + printk(KERN_WARNING "%s: DMA timeout error\n", drive->name); + (void)HWIF(drive)->ide_dma_end(drive); + ret = DRIVER(drive)->error(drive, "dma timeout error", + hwif->INB(IDE_STATUS_REG)); + } else { + printk(KERN_WARNING "%s: DMA timeout retry\n", drive->name); + (void) hwif->ide_dma_timeout(drive); + } /* * disable dma for now, but remember that we did so because of @@ -1018,9 +1028,9 @@ rq->hard_cur_sectors = rq->current_nr_sectors; if (rq->bio) rq->buffer = NULL; -} -EXPORT_SYMBOL(ide_dma_timeout_retry); + return ret; +} /** * ide_timer_expiry - handle lack of an IDE interrupt @@ -1041,11 +1051,10 @@ ide_hwgroup_t *hwgroup = (ide_hwgroup_t *) data; ide_handler_t *handler; ide_expiry_t *expiry; - unsigned long flags; - unsigned long wait; + unsigned long flags; + unsigned long wait = -1; spin_lock_irqsave(&ide_lock, flags); - del_timer(&hwgroup->timer); if ((handler = hwgroup->handler) == NULL) { /* @@ -1072,7 +1081,7 @@ } if ((expiry = hwgroup->expiry) != NULL) { /* continue */ - if ((wait = expiry(drive)) != 0) { + if ((wait = expiry(drive)) > 0) { /* reset timer */ hwgroup->timer.expires = jiffies + wait; add_timer(&hwgroup->timer); @@ -1107,15 +1116,15 @@ startstop = handler(drive); } else { if (drive->waiting_for_dma) { - startstop = ide_stopped; - ide_dma_timeout_retry(drive); + startstop = ide_dma_timeout_retry(drive, wait); } else - startstop = DRIVER(drive)->error(drive, "irq timeout", hwif->INB(IDE_STATUS_REG)); + startstop = + DRIVER(drive)->error(drive, "irq timeout", hwif->INB(IDE_STATUS_REG)); } set_recovery_timer(hwif); drive->service_time = jiffies - drive->service_start; - enable_irq(hwif->irq); spin_lock_irq(&ide_lock); + enable_irq(hwif->irq); if (startstop == ide_stopped) hwgroup->busy = 0; } diff -Nru a/drivers/ide/legacy/hd.c b/drivers/ide/legacy/hd.c --- a/drivers/ide/legacy/hd.c Sun Jul 27 10:13:39 2003 +++ b/drivers/ide/legacy/hd.c Sun Jul 27 10:13:39 2003 @@ -26,7 +26,7 @@ /* Uncomment the following if you want verbose error reports. */ /* #define VERBOSE_ERRORS */ -#include +#include #include #include #include diff -Nru a/drivers/ide/legacy/hd98.c b/drivers/ide/legacy/hd98.c --- a/drivers/ide/legacy/hd98.c Sun Jul 27 10:13:49 2003 +++ b/drivers/ide/legacy/hd98.c Sun Jul 27 10:13:49 2003 @@ -46,8 +46,6 @@ #include #include -#include - #include "io_ports.h" #ifdef __arm__ diff -Nru a/drivers/ide/pci/via82cxxx.c b/drivers/ide/pci/via82cxxx.c --- a/drivers/ide/pci/via82cxxx.c Sun Jul 27 10:13:39 2003 +++ b/drivers/ide/pci/via82cxxx.c Sun Jul 27 10:13:39 2003 @@ -484,7 +484,7 @@ for (i = 24; i >= 0; i -= 8) if (((u >> i) & 0x10) || (((u >> i) & 0x20) && - (((u >> i) & 7) < 8))) { + (((u >> i) & 7) < 6))) { /* BIOS 80-wire bit or * UDMA w/ < 60ns/cycle */ diff -Nru a/drivers/ide/ppc/mpc8xx.c b/drivers/ide/ppc/mpc8xx.c --- a/drivers/ide/ppc/mpc8xx.c Sun Jul 27 10:13:52 2003 +++ b/drivers/ide/ppc/mpc8xx.c Sun Jul 27 10:13:52 2003 @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include diff -Nru a/drivers/ide/setup-pci.c b/drivers/ide/setup-pci.c --- a/drivers/ide/setup-pci.c Sun Jul 27 10:13:44 2003 +++ b/drivers/ide/setup-pci.c Sun Jul 27 10:13:44 2003 @@ -172,7 +172,7 @@ * is already in DMA mode we check and enforce IDE simplex rules. */ -static unsigned long __init ide_get_or_set_dma_base (ide_hwif_t *hwif) +static unsigned long ide_get_or_set_dma_base (ide_hwif_t *hwif) { unsigned long dma_base = 0; struct pci_dev *dev = hwif->pci_dev; diff -Nru a/drivers/ieee1394/amdtp.c b/drivers/ieee1394/amdtp.c --- a/drivers/ieee1394/amdtp.c Sun Jul 27 10:13:47 2003 +++ b/drivers/ieee1394/amdtp.c Sun Jul 27 10:13:47 2003 @@ -62,6 +62,12 @@ * - Maybe make an ALSA interface, that is, create a file_ops * implementation that recognizes ALSA ioctls and uses defaults for * things that can't be controlled through ALSA (iso channel). + * + * Changes: + * + * - Audit copy_from_user in amdtp_write. + * Daniele Bellucci + * */ #include @@ -1112,7 +1118,8 @@ for (i = 0; i < count; i += length) { p = buffer_put_bytes(s->input, count - i, &length); - copy_from_user(p, buffer + i, length); + if (copy_from_user(p, buffer + i, length)) + return -EFAULT; if (s->input->length < s->input->size) continue; diff -Nru a/drivers/ieee1394/csr.c b/drivers/ieee1394/csr.c --- a/drivers/ieee1394/csr.c Sun Jul 27 10:13:42 2003 +++ b/drivers/ieee1394/csr.c Sun Jul 27 10:13:42 2003 @@ -89,6 +89,37 @@ 0x3f1)); } +/* + * HI == seconds (bits 0:2) + * LO == fraction units of 1/8000 of a second, as per 1394 (bits 19:31) + * + * Convert to units and then to HZ, for comparison to jiffies. + * + * By default this will end up being 800 units, or 100ms (125usec per + * unit). + * + * NOTE: The spec says 1/8000, but also says we can compute based on 1/8192 + * like CSR specifies. Should make our math less complex. + */ +static inline void calculate_expire(struct csr_control *csr) +{ + unsigned long units; + + /* Take the seconds, and convert to units */ + units = (unsigned long)(csr->split_timeout_hi & 0x07) << 13; + + /* Add in the fractional units */ + units += (unsigned long)(csr->split_timeout_lo >> 19); + + /* Convert to jiffies */ + csr->expire = (unsigned long)(units * HZ) >> 13UL; + + /* Just to keep from rounding low */ + csr->expire++; + + HPSB_VERBOSE("CSR: setting expire to %lu, HZ=%lu", csr->expire, HZ); +} + static void add_host(struct hpsb_host *host) { @@ -100,6 +131,7 @@ host->csr.node_ids = 0; host->csr.split_timeout_hi = 0; host->csr.split_timeout_lo = 800 << 19; + calculate_expire(&host->csr); host->csr.cycle_time = 0; host->csr.bus_time = 0; host->csr.bus_manager_id = 0x3f; @@ -336,10 +368,12 @@ case CSR_SPLIT_TIMEOUT_HI: host->csr.split_timeout_hi = be32_to_cpu(*(data++)) & 0x00000007; + calculate_expire(&host->csr); out; case CSR_SPLIT_TIMEOUT_LO: host->csr.split_timeout_lo = be32_to_cpu(*(data++)) & 0xfff80000; + calculate_expire(&host->csr); out; /* address gap */ @@ -410,7 +444,7 @@ * eventually. */ HPSB_WARN("Node [" NODE_BUS_FMT "] wants to release " "broadcast channel 31. Ignoring.", - NODE_BUS_ARGS(nodeid)); + NODE_BUS_ARGS(host, nodeid)); data &= ~0x1; /* keep broadcast channel allocated */ } @@ -556,7 +590,7 @@ * eventually. */ HPSB_WARN("Node [" NODE_BUS_FMT "] wants to release " "broadcast channel 31. Ignoring.", - NODE_BUS_ARGS(nodeid)); + NODE_BUS_ARGS(host, nodeid)); data &= ~0x100000000ULL; /* keep broadcast channel allocated */ } diff -Nru a/drivers/ieee1394/csr.h b/drivers/ieee1394/csr.h --- a/drivers/ieee1394/csr.h Sun Jul 27 10:13:40 2003 +++ b/drivers/ieee1394/csr.h Sun Jul 27 10:13:40 2003 @@ -41,6 +41,7 @@ quadlet_t state; quadlet_t node_ids; quadlet_t split_timeout_hi, split_timeout_lo; + unsigned long expire; // Calculated from split_timeout quadlet_t cycle_time; quadlet_t bus_time; quadlet_t bus_manager_id; diff -Nru a/drivers/ieee1394/dma.c b/drivers/ieee1394/dma.c --- a/drivers/ieee1394/dma.c Sun Jul 27 10:13:45 2003 +++ b/drivers/ieee1394/dma.c Sun Jul 27 10:13:45 2003 @@ -151,13 +151,15 @@ for (i = 0; i < dma->n_dma_pages; i++) { if (off < sg_dma_len(&dma->sglist[i])) { *rem = off; - return i; + break; } off -= sg_dma_len(&dma->sglist[i]); } - panic("dma_region_find: offset %lu beyond end of DMA mapping\n", offset); + BUG_ON(i >= dma->n_dma_pages); + + return i; } dma_addr_t dma_region_offset_to_bus(struct dma_region *dma, unsigned long offset) diff -Nru a/drivers/ieee1394/dv1394-private.h b/drivers/ieee1394/dv1394-private.h --- a/drivers/ieee1394/dv1394-private.h Sun Jul 27 10:13:47 2003 +++ b/drivers/ieee1394/dv1394-private.h Sun Jul 27 10:13:47 2003 @@ -1,7 +1,7 @@ /* * dv1394-private.h - DV input/output over IEEE 1394 on OHCI chips * Copyright (C)2001 Daniel Maas - * receive, proc_fs by Dan Dennedy + * receive by Dan Dennedy * * based on: * video1394.h - driver for OHCI 1394 boards diff -Nru a/drivers/ieee1394/dv1394.c b/drivers/ieee1394/dv1394.c --- a/drivers/ieee1394/dv1394.c Sun Jul 27 10:13:49 2003 +++ b/drivers/ieee1394/dv1394.c Sun Jul 27 10:13:49 2003 @@ -1,7 +1,7 @@ /* * dv1394.c - DV input/output over IEEE 1394 on OHCI chips * Copyright (C)2001 Daniel Maas - * receive, proc_fs by Dan Dennedy + * receive by Dan Dennedy * * based on: * video1394.c - video driver for OHCI 1394 boards @@ -80,7 +80,6 @@ - add proc fs interface to set cip_n, cip_d, syt_offset, and video signal - expose xmit and recv as separate devices (not exclusive) - expose NTSC and PAL as separate devices (can be overridden) - - read/edit channel in procfs */ @@ -102,7 +101,6 @@ #include #include #include -#include #include #include #include @@ -1103,7 +1101,7 @@ init.api_version = DV1394_API_VERSION; init.n_frames = DV1394_MAX_FRAMES / 4; - /* the following are now set via proc_fs or devfs */ + /* the following are now set via devfs */ init.channel = video->channel; init.format = video->pal_or_ntsc; init.cip_n = video->cip_n; @@ -1857,244 +1855,6 @@ } -/*** PROC_FS INTERFACE ******************************************************/ -#ifdef CONFIG_PROC_FS -static LIST_HEAD(dv1394_procfs); -struct dv1394_procfs_entry { - struct list_head list; - struct proc_dir_entry *procfs; - char name[32]; - struct dv1394_procfs_entry *parent; -}; -static spinlock_t dv1394_procfs_lock = SPIN_LOCK_UNLOCKED; - -static int dv1394_procfs_read( char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - struct video_card *video = (struct video_card*) data; - - snprintf( page, count, - "\ -format=%s\n\ -channel=%d\n\ -cip_n=%lu\n\ -cip_d=%lu\n\ -syt_offset=%u\n", - (video->pal_or_ntsc == DV1394_NTSC ? "NTSC" : "PAL"), - video->channel, - video->cip_n, video->cip_d, video->syt_offset ); - return strlen(page); -} - -/* lifted from the stallion.c driver */ -#undef TOLOWER -#define TOLOWER(x) ((((x) >= 'A') && ((x) <= 'Z')) ? ((x) + 0x20) : (x)) -static unsigned long atol(char *str) -{ - unsigned long val; - int base, c; - char *sp; - - val = 0; - sp = str; - if ((*sp == '0') && (*(sp+1) == 'x')) { - base = 16; - sp += 2; - } else if (*sp == '0') { - base = 8; - sp++; - } else { - base = 10; - } - - for (; (*sp != 0); sp++) { - c = (*sp > '9') ? (TOLOWER(*sp) - 'a' + 10) : (*sp - '0'); - if ((c < 0) || (c >= base)) { - printk(KERN_ERR "dv1394: atol() invalid argument %s\n", str); - val = 0; - break; - } - val = (val * base) + c; - } - return(val); -} - -static int dv1394_procfs_write( struct file *file, - const char *buffer, unsigned long count, void *data) -{ - int len = 0; - char new_value[65]; - char *pos; - struct video_card *video = (struct video_card*) data; - - if (count > 64) - len = 64; - else - len = count; - - if (copy_from_user( new_value, buffer, len)) - return -EFAULT; - - new_value[len] = 0; - pos = strchr(new_value, '='); - if (pos != NULL) { - int val_len = len - (pos-new_value) - 1; - char buf[65]; - memset(buf, 0, 65); - strncpy(buf, pos+1, val_len); - if (buf[val_len-1] == '\n') buf[val_len-1] = 0; - - if (strnicmp( new_value, "format", (pos-new_value)) == 0) { - if (strnicmp( buf, "NTSC", val_len) == 0) - video->pal_or_ntsc = DV1394_NTSC; - else if (strnicmp( buf, "PAL", val_len) == 0) - video->pal_or_ntsc = DV1394_PAL; - - } else if (strnicmp( new_value, "cip_n", (pos-new_value)) == 0) { - video->cip_n = atol(buf); - } else if (strnicmp( new_value, "cip_d", (pos-new_value)) == 0) { - video->cip_d = atol(buf); - } else if (strnicmp( new_value, "syt_offset", (pos-new_value)) == 0) { - video->syt_offset = atol(buf); - } else if (strnicmp( new_value, "channel", (pos-new_value)) == 0) { - video->channel = atol(buf); - } - } - - return len; -} - -struct dv1394_procfs_entry * -dv1394_procfs_find( char *name) -{ - struct list_head *lh; - struct dv1394_procfs_entry *p; - - spin_lock( &dv1394_procfs_lock); - if (!list_empty(&dv1394_procfs)) { - list_for_each(lh, &dv1394_procfs) { - p = list_entry(lh, struct dv1394_procfs_entry, list); - if (!strncmp(p->name, name, sizeof(p->name))) { - spin_unlock( &dv1394_procfs_lock); - return p; - } - } - } - spin_unlock( &dv1394_procfs_lock); - return NULL; -} - -static int dv1394_procfs_add_entry(struct video_card *video) -{ - char buf[32]; - struct dv1394_procfs_entry *p; - struct dv1394_procfs_entry *parent; - - p = kmalloc(sizeof(struct dv1394_procfs_entry), GFP_KERNEL); - if (!p) { - printk(KERN_ERR "dv1394: cannot allocate dv1394_procfs_entry\n"); - goto err; - } - memset(p, 0, sizeof(struct dv1394_procfs_entry)); - - snprintf(buf, sizeof(buf), "dv/host%d/%s", (video->id>>2), - (video->pal_or_ntsc == DV1394_NTSC ? "NTSC" : "PAL")); - - parent = dv1394_procfs_find(buf); - if (parent == NULL) { - printk(KERN_ERR "dv1394: unable to locate parent procfs of %s\n", buf); - goto err_free; - } - - p->procfs = create_proc_entry( - (video->mode == MODE_RECEIVE ? "in" : "out"), - 0666, parent->procfs); - - if (p->procfs == NULL) { - printk(KERN_ERR "dv1394: unable to create /proc/bus/ieee1394/%s/%s\n", - parent->name, - (video->mode == MODE_RECEIVE ? "in" : "out")); - goto err_free; - } - - p->procfs->owner = THIS_MODULE; - p->procfs->data = video; - p->procfs->read_proc = dv1394_procfs_read; - p->procfs->write_proc = dv1394_procfs_write; - - spin_lock( &dv1394_procfs_lock); - INIT_LIST_HEAD(&p->list); - list_add_tail(&p->list, &dv1394_procfs); - spin_unlock( &dv1394_procfs_lock); - - return 0; - - err_free: - kfree(p); - err: - return -ENOMEM; -} - -static int -dv1394_procfs_add_dir( char *name, - struct dv1394_procfs_entry *parent, - struct dv1394_procfs_entry **out) -{ - struct dv1394_procfs_entry *p; - - p = kmalloc(sizeof(struct dv1394_procfs_entry), GFP_KERNEL); - if (!p) { - printk(KERN_ERR "dv1394: cannot allocate dv1394_procfs_entry\n"); - goto err; - } - memset(p, 0, sizeof(struct dv1394_procfs_entry)); - - if (parent == NULL) { - snprintf(p->name, sizeof(p->name), "%s", name); - p->procfs = proc_mkdir( name, ieee1394_procfs_entry); - } else { - snprintf(p->name, sizeof(p->name), "%s/%s", parent->name, name); - p->procfs = proc_mkdir( name, parent->procfs); - } - if (p->procfs == NULL) { - printk(KERN_ERR "dv1394: unable to create /proc/bus/ieee1394/%s\n", p->name); - goto err_free; - } - - p->procfs->owner = THIS_MODULE; - p->parent = parent; - if (out != NULL) *out = p; - - spin_lock( &dv1394_procfs_lock); - INIT_LIST_HEAD(&p->list); - list_add_tail(&p->list, &dv1394_procfs); - spin_unlock( &dv1394_procfs_lock); - - return 0; - - err_free: - kfree(p); - err: - return -ENOMEM; -} - -void dv1394_procfs_del( char *name) -{ - struct dv1394_procfs_entry *p = dv1394_procfs_find(name); - if (p != NULL) { - if (p->parent == NULL) - remove_proc_entry(p->name, ieee1394_procfs_entry); - else - remove_proc_entry(p->name, p->parent->procfs); - - spin_lock( &dv1394_procfs_lock); - list_del(&p->list); - spin_unlock( &dv1394_procfs_lock); - kfree(p); - } -} -#endif /* CONFIG_PROC_FS */ - /*** DEVICE DRIVER HANDLERS ************************************************/ static void it_tasklet_func(unsigned long data) @@ -2485,18 +2245,13 @@ video->channel = 63; /* default to broadcast channel */ video->active_frame = -1; - /* initialize the following for proc_fs */ + /* initialize the following */ video->pal_or_ntsc = format; video->cip_n = 0; /* 0 = use builtin default */ video->cip_d = 0; video->syt_offset = 0; video->mode = mode; -#ifdef CONFIG_PROC_FS - if ( dv1394_procfs_add_entry(video) < 0 ) - goto err_free; -#endif - for (i = 0; i < DV1394_MAX_FRAMES; i++) video->frames[i] = NULL; @@ -2548,9 +2303,6 @@ ); devfs_remove("ieee1394/%s", buf); -#ifdef CONFIG_PROC_FS - dv1394_procfs_del(buf); -#endif list_del(&video->list); kfree(video); } @@ -2562,7 +2314,6 @@ struct video_card *video = NULL; unsigned long flags; struct list_head *lh, *templh; - char buf[32]; int n; /* We only work with the OHCI-1394 driver */ @@ -2588,21 +2339,11 @@ devfs_remove("ieee1394/dv/host%d/NTSC", n); devfs_remove("ieee1394/dv/host%d/PAL", n); devfs_remove("ieee1394/dv/host%d", n); - -#ifdef CONFIG_PROC_FS - snprintf(buf, sizeof(buf), "dv/host%d/NTSC", n); - dv1394_procfs_del(buf); - snprintf(buf, sizeof(buf), "dv/host%d/PAL", n); - dv1394_procfs_del(buf); - snprintf(buf, sizeof(buf), "dv/host%d", n); - dv1394_procfs_del(buf); -#endif } static void dv1394_add_host (struct hpsb_host *host) { struct ti_ohci *ohci; - char buf[16]; /* We only work with the OHCI-1394 driver */ if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME)) @@ -2610,19 +2351,6 @@ ohci = (struct ti_ohci *)host->hostdata; -#ifdef CONFIG_PROC_FS -{ - struct dv1394_procfs_entry *p; - p = dv1394_procfs_find("dv"); - if (p != NULL) { - snprintf(buf, sizeof(buf), "host%d", ohci->id); - dv1394_procfs_add_dir(buf, p, &p); - dv1394_procfs_add_dir("NTSC", p, NULL); - dv1394_procfs_add_dir("PAL", p, NULL); - } -} -#endif - devfs_mk_dir("ieee1394/dv/host%d", ohci->id); devfs_mk_dir("ieee1394/dv/host%d/NTSC", ohci->id); devfs_mk_dir("ieee1394/dv/host%d/PAL", ohci->id); @@ -2881,9 +2609,6 @@ hpsb_unregister_highlevel(&dv1394_highlevel); ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_DV1394); devfs_remove("ieee1394/dv"); -#ifdef CONFIG_PROC_FS - dv1394_procfs_del("dv"); -#endif } static int __init dv1394_init_module(void) @@ -2898,16 +2623,6 @@ } devfs_mk_dir("ieee1394/dv"); - -#ifdef CONFIG_PROC_FS - ret = dv1394_procfs_add_dir("dv",NULL,NULL); - if (ret < 0) { - printk(KERN_ERR "dv1394: unable to create /proc/bus/ieee1394/dv\n"); - ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_DV1394); - devfs_remove("ieee1394/dv"); - return -ENOMEM; - } -#endif hpsb_register_highlevel(&dv1394_highlevel); diff -Nru a/drivers/ieee1394/dv1394.h b/drivers/ieee1394/dv1394.h --- a/drivers/ieee1394/dv1394.h Sun Jul 27 10:13:49 2003 +++ b/drivers/ieee1394/dv1394.h Sun Jul 27 10:13:49 2003 @@ -1,7 +1,7 @@ /* * dv1394.h - DV input/output over IEEE 1394 on OHCI chips * Copyright (C)2001 Daniel Maas - * receive, proc_fs by Dan Dennedy + * receive by Dan Dennedy * * based on: * video1394.h - driver for OHCI 1394 boards diff -Nru a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c --- a/drivers/ieee1394/eth1394.c Sun Jul 27 10:13:47 2003 +++ b/drivers/ieee1394/eth1394.c Sun Jul 27 10:13:47 2003 @@ -89,7 +89,7 @@ #define TRACE() printk(KERN_ERR "%s:%s[%d] ---- TRACE\n", driver_name, __FUNCTION__, __LINE__) static char version[] __devinitdata = - "$Rev: 986 $ Ben Collins "; + "$Rev: 1010 $ Ben Collins "; struct fragment_info { struct list_head list; @@ -1285,7 +1285,7 @@ if (hpsb_get_tlabel(p, !in_interrupt())) { ETH1394_PRINT_G(KERN_ERR, "No more tlabels left while sending " - "to node " NODE_BUS_FMT "\n", NODE_BUS_ARGS(node)); + "to node " NODE_BUS_FMT "\n", NODE_BUS_ARGS(host, node)); return -1; } p->header[0] = (p->node_id << 16) | (p->tlabel << 10) @@ -1600,7 +1600,7 @@ case ETHTOOL_GDRVINFO: { struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO }; strcpy (info.driver, driver_name); - strcpy (info.version, "$Rev: 986 $"); + strcpy (info.version, "$Rev: 1010 $"); /* FIXME XXX provide sane businfo */ strcpy (info.bus_info, "ieee1394"); if (copy_to_user (useraddr, &info, sizeof (info))) diff -Nru a/drivers/ieee1394/highlevel.h b/drivers/ieee1394/highlevel.h --- a/drivers/ieee1394/highlevel.h Sun Jul 27 10:13:43 2003 +++ b/drivers/ieee1394/highlevel.h Sun Jul 27 10:13:43 2003 @@ -21,6 +21,7 @@ */ struct hpsb_highlevel { + struct module *owner; const char *name; /* Any of the following pointers can legally be NULL, except for diff -Nru a/drivers/ieee1394/hosts.c b/drivers/ieee1394/hosts.c --- a/drivers/ieee1394/hosts.c Sun Jul 27 10:13:44 2003 +++ b/drivers/ieee1394/hosts.c Sun Jul 27 10:13:44 2003 @@ -16,7 +16,6 @@ #include #include #include -#include #include "ieee1394_types.h" #include "hosts.h" @@ -67,7 +66,7 @@ list_for_each(lh, &hpsb_hosts) { if (host == list_entry(lh, struct hpsb_host, host_list)) { if (try_module_get(host->driver->owner)) { - host->refcount++; + atomic_inc(&host->refcount); retval = 1; } break; @@ -92,9 +91,7 @@ module_put(host->driver->owner); down(&hpsb_hosts_lock); - host->refcount--; - - if (!host->refcount && host->is_shutdown) + if (atomic_dec_and_test(&host->refcount) && host->is_shutdown) kfree(host); up(&hpsb_hosts_lock); } @@ -131,7 +128,7 @@ h->hostdata = h + 1; h->driver = drv; - h->refcount = 1; + atomic_set(&h->refcount, 1); INIT_LIST_HEAD(&h->pending_packets); spin_lock_init(&h->pending_pkt_lock); @@ -141,7 +138,10 @@ atomic_set(&h->generation, 0); - INIT_WORK(&h->timeout_tq, (void (*)(void*))abort_timedouts, h); + init_timer(&h->timeout); + h->timeout.data = (unsigned long) h; + h->timeout.function = abort_timedouts; + h->timeout_interval = HZ / 20; // 50ms by default h->topology_map = h->csr.topology_map + 3; h->speed_map = (u8 *)(h->csr.speed_map + 2); diff -Nru a/drivers/ieee1394/hosts.h b/drivers/ieee1394/hosts.h --- a/drivers/ieee1394/hosts.h Sun Jul 27 10:13:42 2003 +++ b/drivers/ieee1394/hosts.h Sun Jul 27 10:13:42 2003 @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include #include "ieee1394_types.h" @@ -29,11 +29,12 @@ atomic_t generation; - int refcount; + atomic_t refcount; struct list_head pending_packets; spinlock_t pending_pkt_lock; - struct work_struct timeout_tq; + struct timer_list timeout; + unsigned long timeout_interval; unsigned char iso_listen_count[64]; @@ -107,6 +108,7 @@ enum isoctl_cmd { /* rawiso API - see iso.h for the meanings of these commands + (they correspond exactly to the hpsb_iso_* API functions) * INIT = allocate resources * START = begin transmission/reception * STOP = halt transmission/reception @@ -128,6 +130,7 @@ RECV_STOP, RECV_RELEASE, RECV_SHUTDOWN, + RECV_FLUSH }; enum reset_types { diff -Nru a/drivers/ieee1394/ieee1394-ioctl.h b/drivers/ieee1394/ieee1394-ioctl.h --- a/drivers/ieee1394/ieee1394-ioctl.h Sun Jul 27 10:13:41 2003 +++ b/drivers/ieee1394/ieee1394-ioctl.h Sun Jul 27 10:13:41 2003 @@ -100,6 +100,8 @@ _IOW ('#', 0x27, struct raw1394_iso_packets) #define RAW1394_IOC_ISO_XMIT_SYNC \ _IO ('#', 0x28) +#define RAW1394_IOC_ISO_RECV_FLUSH \ + _IO ('#', 0x29) #endif /* __IEEE1394_IOCTL_H */ diff -Nru a/drivers/ieee1394/ieee1394_core.c b/drivers/ieee1394/ieee1394_core.c --- a/drivers/ieee1394/ieee1394_core.c Sun Jul 27 10:13:42 2003 +++ b/drivers/ieee1394/ieee1394_core.c Sun Jul 27 10:13:42 2003 @@ -29,9 +29,7 @@ #include #include #include -#include #include -#include #include #include #include @@ -62,19 +60,22 @@ /* Some globals used */ const char *hpsb_speedto_str[] = { "S100", "S200", "S400", "S800", "S1600", "S3200" }; +#ifdef CONFIG_IEEE1394_VERBOSEDEBUG static void dump_packet(const char *text, quadlet_t *data, int size) { - int i; + int i; - size /= 4; - size = (size > 4 ? 4 : size); + size /= 4; + size = (size > 4 ? 4 : size); - printk(KERN_DEBUG "ieee1394: %s", text); - for (i = 0; i < size; i++) { - printk(" %8.8x", data[i]); - } - printk("\n"); + printk(KERN_DEBUG "ieee1394: %s", text); + for (i = 0; i < size; i++) + printk(" %08x", data[i]); + printk("\n"); } +#else +#define dump_packet(x,y,z) +#endif static void run_packet_complete(struct hpsb_packet *packet) { @@ -355,9 +356,7 @@ void hpsb_selfid_received(struct hpsb_host *host, quadlet_t sid) { if (host->in_bus_reset) { -#ifdef CONFIG_IEEE1394_VERBOSEDEBUG - HPSB_INFO("Including SelfID 0x%x", sid); -#endif + HPSB_VERBOSE("Including SelfID 0x%x", sid); host->topology_map[host->selfid_count++] = sid; } else { HPSB_NOTICE("Spurious SelfID packet (0x%08x) received from bus %d", @@ -384,15 +383,16 @@ } else { HPSB_NOTICE("Stopping out-of-control reset loop"); HPSB_NOTICE("Warning - topology map and speed map will not be valid"); + host->reset_retries = 0; } } else { + host->reset_retries = 0; build_speed_map(host, host->node_count); } -#ifdef CONFIG_IEEE1394_VERBOSEDEBUG - HPSB_INFO("selfid_complete called with successful SelfID stage " - "... irm_id: 0x%X node_id: 0x%X",host->irm_id,host->node_id); -#endif + HPSB_VERBOSE("selfid_complete called with successful SelfID stage " + "... irm_id: 0x%X node_id: 0x%X",host->irm_id,host->node_id); + /* irm_id is kept up to date by check_selfids() */ if (host->irm_id == host->node_id) { host->is_irm = 1; @@ -440,7 +440,7 @@ spin_unlock_irqrestore(&host->pending_pkt_lock, flags); up(&packet->state_change); - schedule_work(&host->timeout_tq); + mod_timer(&host->timeout, jiffies + host->timeout_interval); } /** @@ -550,10 +550,9 @@ } } -#ifdef CONFIG_IEEE1394_VERBOSEDEBUG dump_packet("send packet local:", packet->header, packet->header_size); -#endif + hpsb_packet_sent(host, packet, packet->expect_response?ACK_PENDING:ACK_COMPLETE); hpsb_packet_received(host, data, size, 0); @@ -568,7 +567,6 @@ + NODEID_TO_NODE(packet->node_id)]; } -#ifdef CONFIG_IEEE1394_VERBOSEDEBUG switch (packet->speed_code) { case 2: dump_packet("send packet 400:", packet->header, @@ -582,7 +580,6 @@ dump_packet("send packet 100:", packet->header, packet->header_size); } -#endif return host->driver->transmit_packet(host, packet); } @@ -617,7 +614,7 @@ } if (lh == &host->pending_packets) { - HPSB_DEBUG("unsolicited response packet received - np"); + HPSB_DEBUG("unsolicited response packet received - no tlabel match"); dump_packet("contents:", data, 16); spin_unlock_irqrestore(&host->pending_pkt_lock, flags); return; @@ -641,7 +638,7 @@ if (!tcode_match || (packet->tlabel != tlabel) || (packet->node_id != (data[1] >> 16))) { - HPSB_INFO("unsolicited response packet received"); + HPSB_INFO("unsolicited response packet received - tcode mismatch"); dump_packet("contents:", data, 16); spin_unlock_irqrestore(&host->pending_pkt_lock, flags); @@ -896,9 +893,7 @@ return; } -#ifdef CONFIG_IEEE1394_VERBOSEDEBUG dump_packet("received packet:", data, size); -#endif tcode = (data[0] >> 4) & 0xf; @@ -959,28 +954,23 @@ } } -void abort_timedouts(struct hpsb_host *host) +void abort_timedouts(unsigned long __opaque) { + struct hpsb_host *host = (struct hpsb_host *)__opaque; unsigned long flags; struct hpsb_packet *packet; unsigned long expire; - struct list_head *lh, *next, *tlh; + struct list_head *lh, *tlh; LIST_HEAD(expiredlist); spin_lock_irqsave(&host->csr.lock, flags); - expire = (host->csr.split_timeout_hi * 8000 - + (host->csr.split_timeout_lo >> 19)) - * HZ / 8000; - /* Avoid shortening of timeout due to rounding errors: */ - expire++; + expire = host->csr.expire; spin_unlock_irqrestore(&host->csr.lock, flags); - spin_lock_irqsave(&host->pending_pkt_lock, flags); - for (lh = host->pending_packets.next; lh != &host->pending_packets; lh = next) { + list_for_each_safe(lh, tlh, &host->pending_packets) { packet = list_entry(lh, struct hpsb_packet, list); - next = lh->next; if (time_before(packet->sendtime + expire, jiffies)) { list_del(&packet->list); list_add(&packet->list, &expiredlist); @@ -988,7 +978,7 @@ } if (!list_empty(&host->pending_packets)) - schedule_work(&host->timeout_tq); + mod_timer(&host->timeout, jiffies + host->timeout_interval); spin_unlock_irqrestore(&host->pending_pkt_lock, flags); @@ -1179,8 +1169,6 @@ return retval; } -struct proc_dir_entry *ieee1394_procfs_entry; - static int __init ieee1394_init(void) { hpsb_packet_cache = kmem_cache_create("hpsb_packet", sizeof(struct hpsb_packet), @@ -1194,19 +1182,6 @@ return -ENODEV; } -#ifdef CONFIG_PROC_FS - /* Must be done before we start everything else, since the drivers - * may use it. */ - ieee1394_procfs_entry = proc_mkdir("ieee1394", proc_bus); - if (ieee1394_procfs_entry == NULL) { - HPSB_ERR("unable to create /proc/bus/ieee1394\n"); - unregister_chrdev(IEEE1394_MAJOR, "ieee1394"); - devfs_remove("ieee1394"); - return -ENOMEM; - } - ieee1394_procfs_entry->owner = THIS_MODULE; -#endif - init_hpsb_highlevel(); init_csr(); if (!disable_nodemgr) @@ -1227,7 +1202,6 @@ unregister_chrdev(IEEE1394_MAJOR, "ieee1394"); devfs_remove("ieee1394"); - remove_proc_entry("ieee1394", proc_bus); } module_init(ieee1394_init); @@ -1257,7 +1231,6 @@ EXPORT_SYMBOL(hpsb_packet_received); EXPORT_SYMBOL(ieee1394_register_chardev); EXPORT_SYMBOL(ieee1394_unregister_chardev); -EXPORT_SYMBOL(ieee1394_procfs_entry); /** ieee1394_transactions.c **/ EXPORT_SYMBOL(hpsb_get_tlabel); @@ -1341,3 +1314,4 @@ EXPORT_SYMBOL(hpsb_iso_packet_sent); EXPORT_SYMBOL(hpsb_iso_packet_received); EXPORT_SYMBOL(hpsb_iso_wake); +EXPORT_SYMBOL(hpsb_iso_recv_flush); diff -Nru a/drivers/ieee1394/ieee1394_core.h b/drivers/ieee1394/ieee1394_core.h --- a/drivers/ieee1394/ieee1394_core.h Sun Jul 27 10:13:41 2003 +++ b/drivers/ieee1394/ieee1394_core.h Sun Jul 27 10:13:41 2003 @@ -4,7 +4,6 @@ #include #include -#include #include #include "hosts.h" @@ -88,7 +87,7 @@ return list_entry(l, struct hpsb_packet, driver_list); } -void abort_timedouts(struct hpsb_host *host); +void abort_timedouts(unsigned long __opaque); void abort_requests(struct hpsb_host *host); struct hpsb_packet *alloc_hpsb_packet(size_t data_size); @@ -223,9 +222,6 @@ /* release a block of minor numbers */ void ieee1394_unregister_chardev(int blocknum); - -/* the proc_fs entry for /proc/ieee1394 */ -extern struct proc_dir_entry *ieee1394_procfs_entry; /* Our sysfs bus entry */ extern struct bus_type ieee1394_bus_type; diff -Nru a/drivers/ieee1394/ieee1394_transactions.c b/drivers/ieee1394/ieee1394_transactions.c --- a/drivers/ieee1394/ieee1394_transactions.c Sun Jul 27 10:13:43 2003 +++ b/drivers/ieee1394/ieee1394_transactions.c Sun Jul 27 10:13:43 2003 @@ -580,9 +580,7 @@ u16 specifier_id_hi = (specifier_id & 0x00ffff00) >> 8; u8 specifier_id_lo = specifier_id & 0xff; -#ifdef CONFIG_IEEE1394_VERBOSEDEBUG - HPSB_DEBUG("Send GASP: channel = %d, length = %d", channel, length); -#endif + HPSB_VERBOSE("Send GASP: channel = %d, length = %d", channel, length); length += 8; diff -Nru a/drivers/ieee1394/ieee1394_types.h b/drivers/ieee1394/ieee1394_types.h --- a/drivers/ieee1394/ieee1394_types.h Sun Jul 27 10:13:49 2003 +++ b/drivers/ieee1394/ieee1394_types.h Sun Jul 27 10:13:49 2003 @@ -61,8 +61,9 @@ #define NODEID_TO_NODE(nodeid) (nodeid & NODE_MASK) /* Can be used to consistently print a node/bus ID. */ -#define NODE_BUS_FMT "%02d:%04d" -#define NODE_BUS_ARGS(nodeid) NODEID_TO_NODE(nodeid), NODEID_TO_BUS(nodeid) +#define NODE_BUS_FMT "%d-%02d:%04d" +#define NODE_BUS_ARGS(__host, __nodeid) \ + __host->id, NODEID_TO_NODE(__nodeid), NODEID_TO_BUS(__nodeid) #define HPSB_PRINT(level, fmt, args...) printk(level "ieee1394: " fmt "\n" , ## args) @@ -71,6 +72,12 @@ #define HPSB_NOTICE(fmt, args...) HPSB_PRINT(KERN_NOTICE, fmt , ## args) #define HPSB_WARN(fmt, args...) HPSB_PRINT(KERN_WARNING, fmt , ## args) #define HPSB_ERR(fmt, args...) HPSB_PRINT(KERN_ERR, fmt , ## args) + +#ifdef CONFIG_IEEE1394_VERBOSEDEBUG +#define HPSB_VERBOSE(fmt, args...) HPSB_PRINT(KERN_DEBUG, fmt , ## args) +#else +#define HPSB_VERBOSE(fmt, args...) +#endif #define HPSB_PANIC(fmt, args...) panic("ieee1394: " fmt "\n" , ## args) diff -Nru a/drivers/ieee1394/iso.c b/drivers/ieee1394/iso.c --- a/drivers/ieee1394/iso.c Sun Jul 27 10:13:50 2003 +++ b/drivers/ieee1394/iso.c Sun Jul 27 10:13:50 2003 @@ -200,6 +200,13 @@ return iso->host->driver->isoctl(iso, RECV_SET_CHANNEL_MASK, (unsigned long) &mask); } +int hpsb_iso_recv_flush(struct hpsb_iso *iso) +{ + if (iso->type != HPSB_ISO_RECV) + return -EINVAL; + return iso->host->driver->isoctl(iso, RECV_FLUSH, 0); +} + static int do_iso_xmit_start(struct hpsb_iso *iso, int cycle) { int retval = iso->host->driver->isoctl(iso, XMIT_START, cycle); diff -Nru a/drivers/ieee1394/iso.h b/drivers/ieee1394/iso.h --- a/drivers/ieee1394/iso.h Sun Jul 27 10:13:51 2003 +++ b/drivers/ieee1394/iso.h Sun Jul 27 10:13:51 2003 @@ -165,6 +165,10 @@ /* N packets have been read out of the buffer, re-use the buffer space */ int hpsb_iso_recv_release_packets(struct hpsb_iso *recv, unsigned int n_packets); +/* check for arrival of new packets immediately (even if irq_interval + has not yet been reached) */ +int hpsb_iso_recv_flush(struct hpsb_iso *iso); + /* returns # of packets ready to send or receive */ int hpsb_iso_n_ready(struct hpsb_iso *iso); diff -Nru a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c --- a/drivers/ieee1394/nodemgr.c Sun Jul 27 10:13:47 2003 +++ b/drivers/ieee1394/nodemgr.c Sun Jul 27 10:13:47 2003 @@ -424,8 +424,15 @@ static void nodemgr_remove_ud(struct unit_directory *ud) { struct device *dev = &ud->device; + struct list_head *lh, *next; int i; + list_for_each_safe(lh, next, &ud->device.children) { + struct unit_directory *ud; + ud = container_of(list_to_dev(lh), struct unit_directory, device); + nodemgr_remove_ud(ud); + } + for (i = 0; i < ARRAY_SIZE(fw_ud_attrs); i++) device_remove_file(dev, fw_ud_attrs[i]); @@ -462,8 +469,8 @@ ud = container_of(list_to_dev(lh), struct unit_directory, device); snprintf(ud->device.name, DEVICE_NAME_SIZE, - "IEEE-1394 unit directory %d-" NODE_BUS_FMT "-%u", - hi->host->id, NODE_BUS_ARGS(ne->nodeid), ud->id); + "IEEE-1394 unit directory " NODE_BUS_FMT "-%u", + NODE_BUS_ARGS(hi->host, ne->nodeid), ud->id); } } @@ -714,8 +721,8 @@ snprintf(ne->device.bus_id, BUS_ID_SIZE, "%016Lx", (unsigned long long)(ne->guid)); snprintf(ne->device.name, DEVICE_NAME_SIZE, - "IEEE-1394 device %d-" NODE_BUS_FMT, host->id, - NODE_BUS_ARGS(ne->nodeid)); + "IEEE-1394 device " NODE_BUS_FMT, + NODE_BUS_ARGS(host, ne->nodeid)); device_register(&ne->device); @@ -727,9 +734,9 @@ nodemgr_update_ud_names(hi, ne); - HPSB_DEBUG("%s added: ID:BUS[%d-" NODE_BUS_FMT "] GUID[%016Lx]", + HPSB_DEBUG("%s added: ID:BUS[" NODE_BUS_FMT "] GUID[%016Lx]", (host->node_id == nodeid) ? "Host" : "Node", - host->id, NODE_BUS_ARGS(nodeid), (unsigned long long)guid); + NODE_BUS_ARGS(host, nodeid), (unsigned long long)guid); return ne; } @@ -911,7 +918,8 @@ * immediate unit directories looking for software_id and * software_version entries, in order to get driver autoloading working. */ static struct unit_directory *nodemgr_process_unit_directory - (struct host_info *hi, struct node_entry *ne, octlet_t address, unsigned int *id) + (struct host_info *hi, struct node_entry *ne, octlet_t address, unsigned int *id, + struct unit_directory *parent) { struct unit_directory *ud; quadlet_t quad; @@ -1001,37 +1009,38 @@ break; case CONFIG_ROM_LOGICAL_UNIT_DIRECTORY: - /* TODO: Parent this with it's UD */ - ud_temp = nodemgr_process_unit_directory(hi, ne, address + value * 4, id); + ud->flags |= UNIT_DIRECTORY_HAS_LUN_DIRECTORY; + ud_temp = nodemgr_process_unit_directory(hi, ne, address + value * 4, id, + parent); + + if (ud_temp == NULL) + break; /* inherit unspecified values */ - if (ud_temp != NULL) + if ((ud->flags & UNIT_DIRECTORY_VENDOR_ID) && + !(ud_temp->flags & UNIT_DIRECTORY_VENDOR_ID)) { - if ((ud->flags & UNIT_DIRECTORY_VENDOR_ID) && - !(ud_temp->flags & UNIT_DIRECTORY_VENDOR_ID)) - { - ud_temp->flags |= UNIT_DIRECTORY_VENDOR_ID; - ud_temp->vendor_id = ud->vendor_id; - ud_temp->vendor_oui = ud->vendor_oui; - } - if ((ud->flags & UNIT_DIRECTORY_MODEL_ID) && - !(ud_temp->flags & UNIT_DIRECTORY_MODEL_ID)) - { - ud_temp->flags |= UNIT_DIRECTORY_MODEL_ID; - ud_temp->model_id = ud->model_id; - } - if ((ud->flags & UNIT_DIRECTORY_SPECIFIER_ID) && - !(ud_temp->flags & UNIT_DIRECTORY_SPECIFIER_ID)) - { - ud_temp->flags |= UNIT_DIRECTORY_SPECIFIER_ID; - ud_temp->specifier_id = ud->specifier_id; - } - if ((ud->flags & UNIT_DIRECTORY_VERSION) && - !(ud_temp->flags & UNIT_DIRECTORY_VERSION)) - { - ud_temp->flags |= UNIT_DIRECTORY_VERSION; - ud_temp->version = ud->version; - } + ud_temp->flags |= UNIT_DIRECTORY_VENDOR_ID; + ud_temp->vendor_id = ud->vendor_id; + ud_temp->vendor_oui = ud->vendor_oui; + } + if ((ud->flags & UNIT_DIRECTORY_MODEL_ID) && + !(ud_temp->flags & UNIT_DIRECTORY_MODEL_ID)) + { + ud_temp->flags |= UNIT_DIRECTORY_MODEL_ID; + ud_temp->model_id = ud->model_id; + } + if ((ud->flags & UNIT_DIRECTORY_SPECIFIER_ID) && + !(ud_temp->flags & UNIT_DIRECTORY_SPECIFIER_ID)) + { + ud_temp->flags |= UNIT_DIRECTORY_SPECIFIER_ID; + ud_temp->specifier_id = ud->specifier_id; + } + if ((ud->flags & UNIT_DIRECTORY_VERSION) && + !(ud_temp->flags & UNIT_DIRECTORY_VERSION)) + { + ud_temp->flags |= UNIT_DIRECTORY_VERSION; + ud_temp->version = ud->version; } break; @@ -1049,7 +1058,13 @@ memcpy(&ud->device, &nodemgr_dev_template_ud, sizeof(ud->device)); - ud->device.parent = &ne->device; + + if (parent) { + ud->flags |= UNIT_DIRECTORY_LUN_DIRECTORY; + ud->device.parent = &parent->device; + } else + ud->device.parent = &ne->device; + snprintf(ud->device.bus_id, BUS_ID_SIZE, "%s-%u", ne->device.bus_id, ud->id); @@ -1125,7 +1140,8 @@ break; case CONFIG_ROM_UNIT_DIRECTORY: - nodemgr_process_unit_directory(hi, ne, address + value * 4, &ud_id); + nodemgr_process_unit_directory(hi, ne, address + value * 4, &ud_id, + NULL); break; case CONFIG_ROM_DESCRIPTOR_LEAF: @@ -1239,14 +1255,13 @@ ne->busopt.generation = (busoptions >> 4) & 0xf; ne->busopt.lnkspd = busoptions & 0x7; -#ifdef CONFIG_IEEE1394_VERBOSEDEBUG - HPSB_DEBUG("NodeMgr: raw=0x%08x irmc=%d cmc=%d isc=%d bmc=%d pmc=%d " - "cyc_clk_acc=%d max_rec=%d gen=%d lspd=%d", - busoptions, ne->busopt.irmc, ne->busopt.cmc, - ne->busopt.isc, ne->busopt.bmc, ne->busopt.pmc, - ne->busopt.cyc_clk_acc, ne->busopt.max_rec, - ne->busopt.generation, ne->busopt.lnkspd); -#endif + HPSB_VERBOSE("NodeMgr: raw=0x%08x irmc=%d cmc=%d isc=%d bmc=%d pmc=%d " + "cyc_clk_acc=%d max_rec=%d gen=%d lspd=%d", + busoptions, ne->busopt.irmc, ne->busopt.cmc, + ne->busopt.isc, ne->busopt.bmc, ne->busopt.pmc, + ne->busopt.cyc_clk_acc, ne->busopt.max_rec, + ne->busopt.generation, ne->busopt.lnkspd); + device_remove_file(&ne->device, &dev_attr_ne_vendor_oui); nodemgr_process_root_directory(hi, ne); @@ -1301,11 +1316,11 @@ if (ne->nodeid != nodeid) { snprintf(ne->device.name, DEVICE_NAME_SIZE, - "IEEE-1394 device %d-" NODE_BUS_FMT, - hi->host->id, NODE_BUS_ARGS(ne->nodeid)); - HPSB_DEBUG("Node changed: %d-" NODE_BUS_FMT " -> %d-" NODE_BUS_FMT, - ne->host->id, NODE_BUS_ARGS(ne->nodeid), - ne->host->id, NODE_BUS_ARGS(nodeid)); + "IEEE-1394 device " NODE_BUS_FMT, + NODE_BUS_ARGS(hi->host, ne->nodeid)); + HPSB_DEBUG("Node changed: " NODE_BUS_FMT " -> " NODE_BUS_FMT, + NODE_BUS_ARGS(ne->host, ne->nodeid), + NODE_BUS_ARGS(ne->host, nodeid)); ne->nodeid = nodeid; update_ud_names++; @@ -1345,10 +1360,9 @@ * work though, and we are forced to doing quadlet sized * reads. */ -#ifdef CONFIG_IEEE1394_VERBOSEDEBUG - HPSB_INFO("Initiating ConfigROM request for node " NODE_BUS_FMT, - NODE_BUS_ARGS(nodeid)); -#endif + HPSB_VERBOSE("Initiating ConfigROM request for node " NODE_BUS_FMT, + NODE_BUS_ARGS(host, nodeid)); + /* * Must retry a few times if config rom read returns zero (how long?). Will * not normally occur, but we should do the right thing. For example, with @@ -1360,7 +1374,7 @@ if (nodemgr_read_quadlet(host, nodeid, generation, addr, &buffer[0]) < 0) { HPSB_ERR("ConfigROM quadlet transaction error for node " - NODE_BUS_FMT, NODE_BUS_ARGS(nodeid)); + NODE_BUS_FMT, NODE_BUS_ARGS(host, nodeid)); return -1; } if (buffer[0]) @@ -1377,14 +1391,14 @@ if (header_size == 1) { HPSB_INFO("Node " NODE_BUS_FMT " has a minimal ROM. " "Vendor is %08x", - NODE_BUS_ARGS(nodeid), buffer[0] & 0x00ffffff); + NODE_BUS_ARGS(host, nodeid), buffer[0] & 0x00ffffff); return -1; } if (header_size < 4) { HPSB_INFO("Node " NODE_BUS_FMT " has non-standard ROM " "format (%d quads), cannot parse", - NODE_BUS_ARGS(nodeid), header_size); + NODE_BUS_ARGS(host, nodeid), header_size); return -1; } @@ -1393,7 +1407,7 @@ addr, &buffer[i]) < 0) { HPSB_ERR("ConfigROM quadlet transaction " "error for node " NODE_BUS_FMT, - NODE_BUS_ARGS(nodeid)); + NODE_BUS_ARGS(host, nodeid)); return -1; } } @@ -1428,7 +1442,7 @@ * shouldn't be held responsible, so we'll allow it with a * warning. */ HPSB_WARN("Node " NODE_BUS_FMT " has invalid busID magic [0x%08x]", - NODE_BUS_ARGS(nodeid), buffer[1]); + NODE_BUS_ARGS(host, nodeid), buffer[1]); } guid = ((u64)buffer[3] << 32) | buffer[4]; @@ -1508,8 +1522,8 @@ nodemgr_remove_node)) { struct node_entry *ne = cleanup.ne; - HPSB_DEBUG("Node removed: ID:BUS[%d-" NODE_BUS_FMT "] GUID[%016Lx]", - host->id, NODE_BUS_ARGS(ne->nodeid), (unsigned long long)ne->guid); + HPSB_DEBUG("Node removed: ID:BUS[" NODE_BUS_FMT "] GUID[%016Lx]", + NODE_BUS_ARGS(host, ne->nodeid), (unsigned long long)ne->guid); nodemgr_remove_ne(ne); } @@ -1618,11 +1632,12 @@ * happens when we get a bus reset. */ while (!down_interruptible(&hi->reset_sem) && !down_interruptible(&nodemgr_serialize)) { - unsigned int generation; + unsigned int generation = 0; int i; - /* Pause for 1/4 second, to make sure things settle down. */ - for (i = HZ/4; i > 0; i-= HZ/16) { + /* Pause for 1/4 second in 1/16 second intervals, + * to make sure things settle down. */ + for (i = 0; i < 4 ; i++) { set_current_state(TASK_INTERRUPTIBLE); if (schedule_timeout(HZ/16)) goto caught_signal; @@ -1637,7 +1652,7 @@ /* If we get a reset before we are done waiting, then * start the the waiting over again */ while (!down_trylock(&hi->reset_sem)) - i = HZ/4; + i = 0; } if (!nodemgr_check_irm_capability(host, reset_cycles++)) { @@ -1658,9 +1673,7 @@ } caught_signal: -#ifdef CONFIG_IEEE1394_VERBOSEDEBUG - HPSB_DEBUG ("NodeMgr: Exiting thread"); -#endif + HPSB_VERBOSE("NodeMgr: Exiting thread"); complete_and_exit(&hi->exited, 0); } @@ -1782,9 +1795,7 @@ struct host_info *hi = hpsb_get_hostinfo(&nodemgr_highlevel, host); if (hi != NULL) { -#ifdef CONFIG_IEEE1394_VERBOSEDEBUG - HPSB_DEBUG ("NodeMgr: Processing host reset for %s", hi->daemon_name); -#endif + HPSB_VERBOSE("NodeMgr: Processing host reset for %s", hi->daemon_name); up(&hi->reset_sem); } else HPSB_ERR ("NodeMgr: could not process reset of unused host"); diff -Nru a/drivers/ieee1394/nodemgr.h b/drivers/ieee1394/nodemgr.h --- a/drivers/ieee1394/nodemgr.h Sun Jul 27 10:13:46 2003 +++ b/drivers/ieee1394/nodemgr.h Sun Jul 27 10:13:46 2003 @@ -82,12 +82,14 @@ }; -#define UNIT_DIRECTORY_VENDOR_ID 0x01 -#define UNIT_DIRECTORY_MODEL_ID 0x02 -#define UNIT_DIRECTORY_SPECIFIER_ID 0x04 -#define UNIT_DIRECTORY_VERSION 0x08 -#define UNIT_DIRECTORY_VENDOR_TEXT 0x10 -#define UNIT_DIRECTORY_MODEL_TEXT 0x20 +#define UNIT_DIRECTORY_VENDOR_ID 0x01 +#define UNIT_DIRECTORY_MODEL_ID 0x02 +#define UNIT_DIRECTORY_SPECIFIER_ID 0x04 +#define UNIT_DIRECTORY_VERSION 0x08 +#define UNIT_DIRECTORY_VENDOR_TEXT 0x10 +#define UNIT_DIRECTORY_MODEL_TEXT 0x20 +#define UNIT_DIRECTORY_HAS_LUN_DIRECTORY 0x40 +#define UNIT_DIRECTORY_LUN_DIRECTORY 0x80 /* * A unit directory corresponds to a protocol supported by the diff -Nru a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c --- a/drivers/ieee1394/ohci1394.c Sun Jul 27 10:13:50 2003 +++ b/drivers/ieee1394/ohci1394.c Sun Jul 27 10:13:50 2003 @@ -47,9 +47,6 @@ * Adam J Richter * . Use of pci_class to find device * - * Andreas Tobler - * . Updated proc_fs calls - * * Emilie Chung * . Tip on Async Request Filter * @@ -74,7 +71,6 @@ * Ben Collins * . Working big-endian support * . Updated to 2.4.x module scheme (PCI aswell) - * . Removed procfs support since it trashes random mem * . Config ROM generation * * Manfred Weihs @@ -98,6 +94,7 @@ #include #include #include +#include #include #include #include @@ -164,7 +161,7 @@ printk(level "%s_%d: " fmt "\n" , OHCI1394_DRIVER_NAME, card , ## args) static char version[] __devinitdata = - "$Rev: 986 $ Ben Collins "; + "$Rev: 1011 $ Ben Collins "; /* Module Parameters */ static int phys_dma = 1; @@ -502,6 +499,7 @@ /* Global initialization */ static void ohci_initialize(struct ti_ohci *ohci) { + char irq_buf[16]; quadlet_t buf; spin_lock_init(&ohci->phy_reg_lock); @@ -601,10 +599,15 @@ reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_linkEnable); buf = reg_read(ohci, OHCI1394_Version); - PRINT(KERN_INFO, ohci->id, "OHCI-1394 %d.%d (PCI): IRQ=[%d] " +#ifndef __sparc__ + sprintf (irq_buf, "%d", ohci->dev->irq); +#else + sprintf (irq_buf, "%s", __irq_itoa(ohci->dev->irq)); +#endif + PRINT(KERN_INFO, ohci->id, "OHCI-1394 %d.%d (PCI): IRQ=[%s] " "MMIO=[%lx-%lx] Max Packet=[%d]", ((((buf) >> 16) & 0xf) + (((buf) >> 20) & 0xf) * 10), - ((((buf) >> 4) & 0xf) + ((buf) & 0xf) * 10), ohci->dev->irq, + ((((buf) >> 4) & 0xf) + ((buf) & 0xf) * 10), irq_buf, pci_resource_start(ohci->dev, 0), pci_resource_start(ohci->dev, 0) + OHCI1394_REGISTER_SIZE - 1, ohci->max_packet_size); @@ -625,7 +628,7 @@ DBGMSG(ohci->id, "Inserting packet for node " NODE_BUS_FMT ", tlabel=%d, tcode=0x%x, speed=%d", - NODE_BUS_ARGS(packet->node_id), packet->tlabel, + NODE_BUS_ARGS(ohci->host, packet->node_id), packet->tlabel, packet->tcode, packet->speed_code); d->prg_cpu[idx]->begin.address = 0; @@ -650,8 +653,8 @@ if (packet->type == hpsb_raw) { d->prg_cpu[idx]->data[0] = cpu_to_le32(OHCI1394_TCODE_PHY<<4); - d->prg_cpu[idx]->data[1] = packet->header[0]; - d->prg_cpu[idx]->data[2] = packet->header[1]; + d->prg_cpu[idx]->data[1] = cpu_to_le32(packet->header[0]); + d->prg_cpu[idx]->data[2] = cpu_to_le32(packet->header[1]); } else { d->prg_cpu[idx]->data[0] = packet->speed_code<<16 | (packet->header[0] & 0xFFFF); @@ -1146,8 +1149,7 @@ u32 ContextMatch; }; -static void ohci_iso_recv_bufferfill_task(unsigned long data); -static void ohci_iso_recv_packetperbuf_task(unsigned long data); +static void ohci_iso_recv_task(unsigned long data); static void ohci_iso_recv_stop(struct hpsb_iso *iso); static void ohci_iso_recv_shutdown(struct hpsb_iso *iso); static int ohci_iso_recv_start(struct hpsb_iso *iso, int cycle, int tag_mask, int sync); @@ -1237,10 +1239,7 @@ ohci1394_init_iso_tasklet(&recv->task, iso->channel == -1 ? OHCI_ISO_MULTICHANNEL_RECEIVE : OHCI_ISO_RECEIVE, - recv->dma_mode == BUFFER_FILL_MODE ? - ohci_iso_recv_bufferfill_task : - ohci_iso_recv_packetperbuf_task, - (unsigned long) iso); + ohci_iso_recv_task, (unsigned long) iso); if (ohci1394_register_iso_tasklet(recv->ohci, &recv->task) < 0) goto err; @@ -1665,18 +1664,14 @@ hpsb_iso_wake(iso); } -static void ohci_iso_recv_bufferfill_task(unsigned long data) +static void ohci_iso_recv_bufferfill_task(struct hpsb_iso *iso, struct ohci_iso_recv *recv) { - struct hpsb_iso *iso = (struct hpsb_iso*) data; - struct ohci_iso_recv *recv = iso->hostdata; - int loop; /* loop over all blocks */ for (loop = 0; loop < recv->nblocks; loop++) { /* check block_dma to see if it's done */ - struct dma_cmd *im = &recv->block[recv->block_dma]; /* check the DMA descriptor for new writes to xferStatus */ @@ -1726,10 +1721,8 @@ ohci_iso_recv_bufferfill_parse(iso, recv); } -static void ohci_iso_recv_packetperbuf_task(unsigned long data) +static void ohci_iso_recv_packetperbuf_task(struct hpsb_iso *iso, struct ohci_iso_recv *recv) { - struct hpsb_iso *iso = (struct hpsb_iso*) data; - struct ohci_iso_recv *recv = iso->hostdata; int count; int wake = 0; @@ -1803,6 +1796,16 @@ hpsb_iso_wake(iso); } +static void ohci_iso_recv_task(unsigned long data) +{ + struct hpsb_iso *iso = (struct hpsb_iso*) data; + struct ohci_iso_recv *recv = iso->hostdata; + + if (recv->dma_mode == BUFFER_FILL_MODE) + ohci_iso_recv_bufferfill_task(iso, recv); + else + ohci_iso_recv_packetperbuf_task(iso, recv); +} /*********************************** * rawiso ISO transmission * @@ -2125,6 +2128,9 @@ case RECV_RELEASE: ohci_iso_recv_release(iso, (struct hpsb_iso_packet_info*) arg); return 0; + case RECV_FLUSH: + ohci_iso_recv_task((unsigned long) iso); + return 0; case RECV_SHUTDOWN: ohci_iso_recv_shutdown(iso); return 0; @@ -3465,7 +3471,31 @@ case OHCI_INIT_DONE: hpsb_remove_host(ohci->host); + /* Clear out BUS Options */ + reg_write(ohci, OHCI1394_ConfigROMhdr, 0); + reg_write(ohci, OHCI1394_BusOptions, + (reg_read(ohci, OHCI1394_BusOptions) & 0x0000f007) | + 0x00ff0000); + memset(ohci->csr_config_rom_cpu, 0, OHCI_CONFIG_ROM_LEN); + case OHCI_INIT_HAVE_IRQ: + /* Clear interrupt registers */ + reg_write(ohci, OHCI1394_IntMaskClear, 0xffffffff); + reg_write(ohci, OHCI1394_IntEventClear, 0xffffffff); + reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, 0xffffffff); + reg_write(ohci, OHCI1394_IsoXmitIntEventClear, 0xffffffff); + reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 0xffffffff); + reg_write(ohci, OHCI1394_IsoRecvIntEventClear, 0xffffffff); + + /* Disable IRM Contender */ + set_phy_reg(ohci, 4, ~0xc0 & get_phy_reg(ohci, 4)); + + /* Clear link control register */ + reg_write(ohci, OHCI1394_LinkControlClear, 0xffffffff); + + /* Let all other nodes know to ignore us */ + ohci_devctl(ohci->host, RESET_BUS, LONG_RESET_NO_FORCE_ROOT); + /* Soft reset before we start - this disables * interrupts and clears linkEnable and LPS. */ ohci_soft_reset(ohci); diff -Nru a/drivers/ieee1394/pcilynx.c b/drivers/ieee1394/pcilynx.c --- a/drivers/ieee1394/pcilynx.c Sun Jul 27 10:13:43 2003 +++ b/drivers/ieee1394/pcilynx.c Sun Jul 27 10:13:43 2003 @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -1457,6 +1458,14 @@ case have_intr: reg_write(lynx, PCI_INT_ENABLE, 0); free_irq(lynx->dev->irq, lynx); + + /* Disable IRM Contender */ + if (lynx->phyic.reg_1394a) + set_phy_reg(lynx, 4, ~0xc0 & get_phy_reg(lynx, 4)); + + /* Let all other nodes know to ignore us */ + lynx_devctl(lynx->host, RESET_BUS, LONG_RESET_NO_FORCE_ROOT); + case have_iomappings: reg_set_bits(lynx, MISC_CONTROL, MISC_CONTROL_SWRESET); /* Fix buggy cards with autoboot pin not tied low: */ @@ -1504,6 +1513,7 @@ return error; \ } while (0) + char irq_buf[16]; struct hpsb_host *host; struct ti_lynx *lynx; /* shortcut to currently handled device */ struct ti_pcl pcl; @@ -1603,12 +1613,18 @@ /* Fix buggy cards with autoboot pin not tied low: */ reg_write(lynx, DMA0_CHAN_CTRL, 0); +#ifndef __sparc__ + sprintf (irq_buf, "%d", dev->irq); +#else + sprintf (irq_buf, "%s", __irq_itoa(dev->irq)); +#endif + if (!request_irq(dev->irq, lynx_irq_handler, SA_SHIRQ, PCILYNX_DRIVER_NAME, lynx)) { - PRINT(KERN_INFO, lynx->id, "allocated interrupt %d", dev->irq); + PRINT(KERN_INFO, lynx->id, "allocated interrupt %s", irq_buf); lynx->state = have_intr; } else { - FAIL("failed to allocate shared interrupt %d", dev->irq); + FAIL("failed to allocate shared interrupt %s", irq_buf); } /* alloc_pcl return values are not checked, it is expected that the @@ -1787,9 +1803,8 @@ i2c_adapter.algo_data = &i2c_adapter_data; i2c_adapter_data.data = lynx; -#ifdef CONFIG_IEEE1394_VERBOSEDEBUG - PRINT(KERN_DEBUG, lynx->id,"original eeprom control: %d",reg_read(lynx,SERIAL_EEPROM_CONTROL)); -#endif + PRINTD(KERN_DEBUG, lynx->id,"original eeprom control: %d", + reg_read(lynx, SERIAL_EEPROM_CONTROL)); /* reset hardware to sane state */ lynx->i2c_driven_state = 0x00000070; @@ -1832,17 +1847,16 @@ if (i2c_transfer(&i2c_adapter, msg, 2) < 0) { PRINT(KERN_ERR, lynx->id, "unable to read bus info block from i2c"); } else { -#ifdef CONFIG_IEEE1394_VERBOSEDEBUG int i; -#endif - PRINT(KERN_INFO, lynx->id, "got bus info block from serial eeprom"); - /* FIXME: probably we shoud rewrite the max_rec, max_ROM(1394a), generation(1394a) and link_spd(1394a) field - and recalculate the CRC */ -#ifdef CONFIG_IEEE1394_VERBOSEDEBUG - for (i=0; i < 5 ; i++) - PRINT(KERN_DEBUG, lynx->id, "Businfo block quadlet %i: %08x",i, be32_to_cpu(lynx->config_rom[i])); -#endif + PRINT(KERN_INFO, lynx->id, "got bus info block from serial eeprom"); + /* FIXME: probably we shoud rewrite the max_rec, max_ROM(1394a), + * generation(1394a) and link_spd(1394a) field and recalculate + * the CRC */ + + for (i = 0; i < 5 ; i++) + PRINTD(KERN_DEBUG, lynx->id, "Businfo block quadlet %i: %08x", + i, be32_to_cpu(lynx->config_rom[i])); /* info_length, crc_length and 1394 magic number to check, if it is really a bus info block */ if (((be32_to_cpu(lynx->config_rom[0]) & 0xffff0000) == 0x04040000) && diff -Nru a/drivers/ieee1394/raw1394.c b/drivers/ieee1394/raw1394.c --- a/drivers/ieee1394/raw1394.c Sun Jul 27 10:13:40 2003 +++ b/drivers/ieee1394/raw1394.c Sun Jul 27 10:13:40 2003 @@ -1566,8 +1566,8 @@ req->req.length, ((req->req.misc >> 8) & 0xFF), (req->req.misc & 0xFF),((req->req.misc >> 16) & 0xFFFF)); /* check addressrange */ - if ((((req->req.address) & ~(0xFFFFFFFFFFFF)) != 0) || - (((req->req.address + req->req.length) & ~(0xFFFFFFFFFFFF)) != 0)) { + if ((((req->req.address) & ~((u64)0xFFFFFFFFFFFFLL)) != 0) || + (((req->req.address + req->req.length) & ~((u64)0xFFFFFFFFFFFFLL)) != 0)) { req->req.length = 0; return (-EINVAL); } @@ -2273,6 +2273,8 @@ return raw1394_iso_recv_packets(fi, (void*) arg); case RAW1394_IOC_ISO_RECV_RELEASE_PACKETS: return hpsb_iso_recv_release_packets(fi->iso_handle, arg); + case RAW1394_IOC_ISO_RECV_FLUSH: + return hpsb_iso_recv_flush(fi->iso_handle); case RAW1394_IOC_ISO_SHUTDOWN: raw1394_iso_shutdown(fi); return 0; diff -Nru a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c --- a/drivers/ieee1394/sbp2.c Sun Jul 27 10:13:41 2003 +++ b/drivers/ieee1394/sbp2.c Sun Jul 27 10:13:41 2003 @@ -51,8 +51,7 @@ #include #include #include -#include -#include +#include #include #include #include @@ -81,7 +80,7 @@ #include "sbp2.h" static char version[] __devinitdata = - "$Rev: 967 $ Ben Collins "; + "$Rev: 1010 $ Ben Collins "; /* * Module load parameter definitions @@ -611,6 +610,11 @@ ud = container_of(dev, struct unit_directory, device); + /* Don't probe UD's that have the LUN flag. We'll probe the LUN(s) + * instead. */ + if (ud->flags & UNIT_DIRECTORY_HAS_LUN_DIRECTORY) + return -ENODEV; + /* This will only add it if it doesn't exist */ hi = sbp2_add_host(ud->ne->host); @@ -1142,7 +1146,7 @@ SBP2_DEBUG("sbp2_query_logins: orb byte-swapped"); - sbp2util_packet_dump(scsi_id->query_logins_orb, sizeof(stuct sbp2_query_logins_orb), + sbp2util_packet_dump(scsi_id->query_logins_orb, sizeof(struct sbp2_query_logins_orb), "sbp2 query logins orb", scsi_id->query_logins_orb_dma); memset(scsi_id->query_logins_response, 0, sizeof(struct sbp2_query_logins_response)); @@ -1620,7 +1624,7 @@ SBP2_128KB_BROKEN_FIRMWARE && (max_sectors * 512) > (128*1024)) { SBP2_WARN("Node " NODE_BUS_FMT ": Bridge only supports 128KB max transfer size.", - NODE_BUS_ARGS(ud->ne->nodeid)); + NODE_BUS_ARGS(ud->ne->host, ud->ne->nodeid)); SBP2_WARN("WARNING: Current max_sectors setting is larger than 128KB (%d sectors)!", max_sectors); workarounds |= SBP2_BREAKAGE_128K_MAX_TRANSFER; @@ -1633,36 +1637,44 @@ if ((firmware_revision & 0xffff00) == sbp2_broken_inquiry_list[i]) { SBP2_WARN("Node " NODE_BUS_FMT ": Using 36byte inquiry workaround", - NODE_BUS_ARGS(ud->ne->nodeid)); + NODE_BUS_ARGS(ud->ne->host, ud->ne->nodeid)); workarounds |= SBP2_BREAKAGE_INQUIRY_HACK; break; /* No need to continue. */ } } - /* If our list is empty, add a base scsi_id (happens in a normal - * case where there is no logical_unit_number entry */ - if (list_empty(&scsi_group->scsi_id_list)) { - scsi_id = kmalloc(sizeof(*scsi_id), GFP_KERNEL); - if (!scsi_id) { - SBP2_ERR("Out of memory adding scsi_id"); - return; - } - memset(scsi_id, 0, sizeof(*scsi_id)); - - scsi_id->sbp2_device_type_and_lun = SBP2_DEVICE_TYPE_LUN_UNINITIALIZED; - list_add_tail(&scsi_id->list, &scsi_group->scsi_id_list); - } + /* If this is a logical unit directory entry, process the parent + * to get the common values. */ + if (ud->flags & UNIT_DIRECTORY_LUN_DIRECTORY) { + struct unit_directory *parent_ud = + container_of(ud->device.parent, struct unit_directory, device); + sbp2_parse_unit_directory(scsi_group, parent_ud); + } else { + /* If our list is empty, add a base scsi_id (happens in a normal + * case where there is no logical_unit_number entry */ + if (list_empty(&scsi_group->scsi_id_list)) { + scsi_id = kmalloc(sizeof(*scsi_id), GFP_KERNEL); + if (!scsi_id) { + SBP2_ERR("Out of memory adding scsi_id"); + return; + } + memset(scsi_id, 0, sizeof(*scsi_id)); - /* Update the generic fields in all the LUN's */ - list_for_each (lh, &scsi_group->scsi_id_list) { - scsi_id = list_entry(lh, struct scsi_id_instance_data, list); + scsi_id->sbp2_device_type_and_lun = SBP2_DEVICE_TYPE_LUN_UNINITIALIZED; + list_add_tail(&scsi_id->list, &scsi_group->scsi_id_list); + } - scsi_id->sbp2_management_agent_addr = management_agent_addr; - scsi_id->sbp2_command_set_spec_id = command_set_spec_id; - scsi_id->sbp2_command_set = command_set; - scsi_id->sbp2_unit_characteristics = unit_characteristics; - scsi_id->sbp2_firmware_revision = firmware_revision; - scsi_id->workarounds = workarounds; + /* Update the generic fields in all the LUN's */ + list_for_each (lh, &scsi_group->scsi_id_list) { + scsi_id = list_entry(lh, struct scsi_id_instance_data, list); + + scsi_id->sbp2_management_agent_addr = management_agent_addr; + scsi_id->sbp2_command_set_spec_id = command_set_spec_id; + scsi_id->sbp2_command_set = command_set; + scsi_id->sbp2_unit_characteristics = unit_characteristics; + scsi_id->sbp2_firmware_revision = firmware_revision; + scsi_id->workarounds = workarounds; + } } } @@ -1697,8 +1709,9 @@ scsi_id->max_payload_size = min(sbp2_speedto_max_payload[scsi_id->speed_code], (u8)(((be32_to_cpu(hi->host->csr.rom[2]) >> 12) & 0xf) - 1)); - SBP2_ERR("Node[" NODE_BUS_FMT "]: Max speed [%s] - Max payload [%u]", - NODE_BUS_ARGS(scsi_id->ne->nodeid), hpsb_speedto_str[scsi_id->speed_code], + SBP2_ERR("Node " NODE_BUS_FMT ": Max speed [%s] - Max payload [%u]", + NODE_BUS_ARGS(hi->host, scsi_id->ne->nodeid), + hpsb_speedto_str[scsi_id->speed_code], 1 << ((u32)scsi_id->max_payload_size + 2)); return(0); @@ -2845,70 +2858,6 @@ return "SCSI emulation for IEEE-1394 SBP-2 Devices"; } -/* Called for contents of procfs */ -#define SPRINTF(args...) \ - do { if (pos < buffer+length) pos += sprintf(pos, ## args); } while (0) - -static int sbp2scsi_proc_info(struct Scsi_Host *scsi_host, char *buffer, char **start, off_t offset, - int length, int inout) -{ - Scsi_Device *scd; - struct hpsb_host *host; - char *pos = buffer; - - /* if someone is sending us data, just throw it away */ - if (inout) - return length; - - host = hpsb_get_host_bykey(&sbp2_highlevel, (unsigned long)scsi_host); - if (!host) /* shouldn't happen, but... */ - return -ESRCH; - - SPRINTF("Host scsi%d : SBP-2 IEEE-1394 (%s)\n", - scsi_host->host_no, host->driver->name); - SPRINTF("Driver version : %s\n", version); - - SPRINTF("\nModule options :\n"); - SPRINTF(" max_speed : %s\n", hpsb_speedto_str[max_speed]); - SPRINTF(" max_sectors : %d\n", max_sectors); - SPRINTF(" serialize_io : %s\n", serialize_io ? "yes" : "no"); - SPRINTF(" exclusive_login : %s\n", exclusive_login ? "yes" : "no"); - - SPRINTF("\nAttached devices : %s\n", !list_empty(&scsi_host->my_devices) ? - "" : "none"); - - list_for_each_entry (scd, &scsi_host->my_devices, siblings) { - int i; - - SPRINTF(" [Channel: %02d, Id: %02d, Lun: %02d] ", scd->channel, - scd->id, scd->lun); - SPRINTF("%s ", (scd->type < MAX_SCSI_DEVICE_CODE) ? - scsi_device_types[(short) scd->type] : "Unknown device"); - - for (i = 0; (i < 8) && (scd->vendor[i] >= 0x20); i++) - SPRINTF("%c", scd->vendor[i]); - - SPRINTF(" "); - - for (i = 0; (i < 16) && (scd->model[i] >= 0x20); i++) - SPRINTF("%c", scd->model[i]); - - SPRINTF("\n"); - } - - SPRINTF("\n"); - - /* Calculate start of next buffer, and return value. */ - *start = buffer + offset; - - if ((pos - buffer) < offset) - return (0); - else if ((pos - buffer - offset) < length) - return (pos - buffer - offset); - else - return (length); -} - MODULE_AUTHOR("Ben Collins "); MODULE_DESCRIPTION("IEEE-1394 SBP-2 protocol driver"); MODULE_SUPPORTED_DEVICE(SBP2_DEVICE_NAME); @@ -2920,7 +2869,6 @@ .name = "SBP-2 IEEE-1394", .proc_name = SBP2_DEVICE_NAME, .info = sbp2scsi_info, - .proc_info = sbp2scsi_proc_info, .queuecommand = sbp2scsi_queuecommand, .eh_abort_handler = sbp2scsi_abort, .eh_device_reset_handler = sbp2scsi_reset, @@ -2938,6 +2886,8 @@ static int sbp2_module_init(void) { SBP2_DEBUG("sbp2_module_init"); + + printk(KERN_INFO "sbp2: %s\n", version); /* Module load debug option to force one command at a time (serializing I/O) */ if (serialize_io) { diff -Nru a/drivers/ieee1394/video1394.c b/drivers/ieee1394/video1394.c --- a/drivers/ieee1394/video1394.c Sun Jul 27 10:13:41 2003 +++ b/drivers/ieee1394/video1394.c Sun Jul 27 10:13:41 2003 @@ -34,7 +34,6 @@ #include #include #include -#include #include #include #include diff -Nru a/drivers/input/gameport/ns558.c b/drivers/input/gameport/ns558.c --- a/drivers/input/gameport/ns558.c Sun Jul 27 10:13:50 2003 +++ b/drivers/input/gameport/ns558.c Sun Jul 27 10:13:50 2003 @@ -243,7 +243,7 @@ #else -static const struct pnp_driver ns558_pnp_driver; +static struct pnp_driver ns558_pnp_driver; #endif diff -Nru a/drivers/input/keyboard/sunkbd.c b/drivers/input/keyboard/sunkbd.c --- a/drivers/input/keyboard/sunkbd.c Sun Jul 27 10:13:39 2003 +++ b/drivers/input/keyboard/sunkbd.c Sun Jul 27 10:13:39 2003 @@ -80,8 +80,8 @@ char name[64]; char phys[32]; char type; - char reset; - char layout; + volatile char reset; + volatile char layout; }; /* diff -Nru a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig --- a/drivers/input/misc/Kconfig Sun Jul 27 10:13:44 2003 +++ b/drivers/input/misc/Kconfig Sun Jul 27 10:13:44 2003 @@ -28,7 +28,7 @@ config INPUT_SPARCSPKR tristate "SPARC Speaker support" - depends on (SPARC32 || SPARC64) && INPUT && INPUT_MISC + depends on (SPARC32 || SPARC64) && INPUT && INPUT_MISC && PCI help Say Y here if you want the standard Speaker on Sparc PCI systems to be used for bells and whistles. diff -Nru a/drivers/input/serio/i8042-sparcio.h b/drivers/input/serio/i8042-sparcio.h --- a/drivers/input/serio/i8042-sparcio.h Sun Jul 27 10:13:52 2003 +++ b/drivers/input/serio/i8042-sparcio.h Sun Jul 27 10:13:52 2003 @@ -1,8 +1,13 @@ #ifndef _I8042_SPARCIO_H #define _I8042_SPARCIO_H +#include +#include + +#ifdef CONFIG_PCI #include #include +#endif static int i8042_kbd_irq = -1; static int i8042_aux_irq = -1; @@ -45,6 +50,9 @@ static int i8042_platform_init(void) { +#ifndef CONFIG_PCI + return -1; +#else char prop[128]; int len; @@ -95,11 +103,14 @@ i8042_reset = 1; return 0; +#endif /* CONFIG_PCI */ } static inline void i8042_platform_exit(void) { +#ifdef CONFIG_PCI iounmap((void *)kbd_iobase); +#endif } #endif /* _I8042_SPARCIO_H */ diff -Nru a/drivers/input/serio/q40kbd.c b/drivers/input/serio/q40kbd.c --- a/drivers/input/serio/q40kbd.c Sun Jul 27 10:13:43 2003 +++ b/drivers/input/serio/q40kbd.c Sun Jul 27 10:13:43 2003 @@ -66,12 +66,14 @@ .close = q40kbd_close, }; -static void q40kbd_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t q40kbd_interrupt(int irq, void *dev_id, + struct pt_regs *regs) { if (Q40_IRQ_KEYB_MASK & master_inb(INTERRUPT_REG)) serio_interrupt(&q40kbd_port, master_inb(KEYCODE_REG), 0, regs); master_outb(-1, KEYBOARD_UNLOCK_REG); + return IRQ_HANDLED; } static int __init q40kbd_init(void) diff -Nru a/drivers/isdn/hardware/eicon/capimain.c b/drivers/isdn/hardware/eicon/capimain.c --- a/drivers/isdn/hardware/eicon/capimain.c Sun Jul 27 10:13:42 2003 +++ b/drivers/isdn/hardware/eicon/capimain.c Sun Jul 27 10:13:42 2003 @@ -160,8 +160,6 @@ char tmprev[32]; int ret = 0; - MOD_INC_USE_COUNT; - sprintf(DRIVERRELEASE, "%d.%d%s", DRRELMAJOR, DRRELMINOR, DRRELEXTRA); @@ -177,7 +175,6 @@ ret = -EIO; } - MOD_DEC_USE_COUNT; return ret; } diff -Nru a/drivers/isdn/hardware/eicon/diva_didd.c b/drivers/isdn/hardware/eicon/diva_didd.c --- a/drivers/isdn/hardware/eicon/diva_didd.c Sun Jul 27 10:13:47 2003 +++ b/drivers/isdn/hardware/eicon/diva_didd.c Sun Jul 27 10:13:47 2003 @@ -135,8 +135,6 @@ char tmprev[32]; int ret = 0; - MOD_INC_USE_COUNT; - printk(KERN_INFO "%s\n", DRIVERNAME); printk(KERN_INFO "%s: Rel:%s Rev:", DRIVERLNAME, DRIVERRELEASE); strcpy(tmprev, main_revision); @@ -159,7 +157,6 @@ } out: - MOD_DEC_USE_COUNT; return (ret); } diff -Nru a/drivers/isdn/hardware/eicon/divamnt.c b/drivers/isdn/hardware/eicon/divamnt.c --- a/drivers/isdn/hardware/eicon/divamnt.c Sun Jul 27 10:13:46 2003 +++ b/drivers/isdn/hardware/eicon/divamnt.c Sun Jul 27 10:13:46 2003 @@ -442,8 +442,6 @@ int ret = 0; void *buffer = 0; - MOD_INC_USE_COUNT; - do_gettimeofday(&start_time); init_waitqueue_head(&msgwaitq); @@ -479,7 +477,6 @@ (diva_dbg_mem == 0) ? "internal" : "external"); out: - MOD_DEC_USE_COUNT; return (ret); } diff -Nru a/drivers/isdn/hardware/eicon/divasi.c b/drivers/isdn/hardware/eicon/divasi.c --- a/drivers/isdn/hardware/eicon/divasi.c Sun Jul 27 10:13:44 2003 +++ b/drivers/isdn/hardware/eicon/divasi.c Sun Jul 27 10:13:44 2003 @@ -192,8 +192,6 @@ char tmprev[50]; int ret = 0; - MOD_INC_USE_COUNT; - printk(KERN_INFO "%s\n", DRIVERNAME); printk(KERN_INFO "%s: Rel:%s Rev:", DRIVERLNAME, DRIVERRELEASE); strcpy(tmprev, main_revision); @@ -223,7 +221,6 @@ } out: - MOD_DEC_USE_COUNT; return (ret); } diff -Nru a/drivers/isdn/hardware/eicon/divasmain.c b/drivers/isdn/hardware/eicon/divasmain.c --- a/drivers/isdn/hardware/eicon/divasmain.c Sun Jul 27 10:13:41 2003 +++ b/drivers/isdn/hardware/eicon/divasmain.c Sun Jul 27 10:13:41 2003 @@ -508,15 +508,11 @@ diva_os_register_io_port(int on, unsigned long port, unsigned long length, const char *name) { - int ret; - if (on) { - if ((ret = check_region(port, length)) < 0) { - DBG_ERR(("A: I/O: can't register port=%08x, error=%d", - port, ret)) + if (!request_region(port, length, name)) { + DBG_ERR(("A: I/O: can't register port=%08x", port)) return (-1); } - request_region(port, length, name); } else { release_region(port, length); } @@ -880,8 +876,6 @@ char tmprev[50]; int ret = 0; - MOD_INC_USE_COUNT; - printk(KERN_INFO "%s\n", DRIVERNAME); printk(KERN_INFO "%s: Rel:%s Rev:", DRIVERLNAME, DRIVERRELEASE); strcpy(tmprev, main_revision); @@ -932,7 +926,6 @@ } out: - MOD_DEC_USE_COUNT; return (ret); } diff -Nru a/drivers/isdn/hardware/eicon/i4lididrv.c b/drivers/isdn/hardware/eicon/i4lididrv.c --- a/drivers/isdn/hardware/eicon/i4lididrv.c Sun Jul 27 10:13:52 2003 +++ b/drivers/isdn/hardware/eicon/i4lididrv.c Sun Jul 27 10:13:52 2003 @@ -1354,8 +1354,6 @@ status_lock = SPIN_LOCK_UNLOCKED; ll_lock = SPIN_LOCK_UNLOCKED; - MOD_INC_USE_COUNT; - if (strlen(id) < 1) strcpy(id, "diva"); @@ -1382,7 +1380,6 @@ create_proc(); out: - MOD_DEC_USE_COUNT; return(ret); } diff -Nru a/drivers/isdn/hisax/avm_pci.c b/drivers/isdn/hisax/avm_pci.c --- a/drivers/isdn/hisax/avm_pci.c Sun Jul 27 10:13:43 2003 +++ b/drivers/isdn/hisax/avm_pci.c Sun Jul 27 10:13:43 2003 @@ -530,21 +530,17 @@ modehdlc(cs->bcs + 1, -1, 1); } -static void +static irqreturn_t avm_pcipnp_interrupt(int intno, void *dev_id, struct pt_regs *regs) { struct IsdnCardState *cs = dev_id; u8 val; u8 sval; - if (!cs) { - printk(KERN_WARNING "AVM PCI: Spurious interrupt!\n"); - return; - } sval = inb(cs->hw.avm.cfg_reg + 2); if ((sval & AVM_STATUS0_IRQ_MASK) == AVM_STATUS0_IRQ_MASK) /* possible a shared IRQ reqest */ - return; + return IRQ_NONE; if (!(sval & AVM_STATUS0_IRQ_ISAC)) { val = ReadISAC(cs, ISAC_ISTA); isac_interrupt(cs, val); @@ -554,6 +550,7 @@ } WriteISAC(cs, ISAC_MASK, 0xFF); WriteISAC(cs, ISAC_MASK, 0x0); + return IRQ_HANDLED; } static int diff -Nru a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c --- a/drivers/isdn/hisax/config.c Sun Jul 27 10:13:50 2003 +++ b/drivers/isdn/hisax/config.c Sun Jul 27 10:13:50 2003 @@ -859,6 +859,65 @@ kfree(cs); } +static void +do_register_isdn(struct IsdnCardState *cs) +{ + if (!cs->iif.owner) + cs->iif.owner = THIS_MODULE; + + cs->iif.channels = 2; + cs->iif.maxbufsize = MAX_DATA_SIZE; + cs->iif.hl_hdrlen = MAX_HEADER_LEN; + cs->iif.features = + ISDN_FEATURE_L2_X75I | + ISDN_FEATURE_L2_HDLC | + ISDN_FEATURE_L2_HDLC_56K | + ISDN_FEATURE_L2_TRANS | + ISDN_FEATURE_L3_TRANS | +#ifdef CONFIG_HISAX_1TR6 + ISDN_FEATURE_P_1TR6 | +#endif +#ifdef CONFIG_HISAX_EURO + ISDN_FEATURE_P_EURO | +#endif +#ifdef CONFIG_HISAX_NI1 + ISDN_FEATURE_P_NI1 | +#endif + 0; + + cs->iif.command = HiSax_command; + cs->iif.writecmd = NULL; + cs->iif.writebuf_skb = HiSax_writebuf_skb; + cs->iif.readstat = HiSax_readstatus; + register_isdn(&cs->iif); + cs->myid = cs->iif.channels; + printk(KERN_INFO + "HiSax: Card %d Protocol %s Id=%s (%d)\n", cs->cardnr + 1, + (cs->protocol == ISDN_PTYPE_1TR6) ? "1TR6" : + (cs->protocol == ISDN_PTYPE_EURO) ? "EDSS1" : + (cs->protocol == ISDN_PTYPE_LEASED) ? "LEASED" : + (cs->protocol == ISDN_PTYPE_NI1) ? "NI1" : + "NONE", cs->iif.id, cs->myid); +} + +static int +do_init(struct IsdnCardState *cs) +{ + int ret; + + init_tei(cs, cs->protocol); + ret = CallcNewChan(cs); + if (ret) + return -EIO; + + /* ISAR needs firmware download first */ + if (!test_bit(HW_ISAR, &cs->HW_Flags)) + ll_run(cs, 0); + + return 0; +} + + static int __devinit checkcard(int cardnr, char *id, int *busy_flag) { int ret = 0; @@ -889,41 +948,8 @@ "HiSax: Card Type %d out of range\n", card->typ); goto outf_cs; } - cs->iif.owner = THIS_MODULE; strcpy(cs->iif.id, id); - cs->iif.channels = 2; - cs->iif.maxbufsize = MAX_DATA_SIZE; - cs->iif.hl_hdrlen = MAX_HEADER_LEN; - cs->iif.features = - ISDN_FEATURE_L2_X75I | - ISDN_FEATURE_L2_HDLC | - ISDN_FEATURE_L2_HDLC_56K | - ISDN_FEATURE_L2_TRANS | - ISDN_FEATURE_L3_TRANS | -#ifdef CONFIG_HISAX_1TR6 - ISDN_FEATURE_P_1TR6 | -#endif -#ifdef CONFIG_HISAX_EURO - ISDN_FEATURE_P_EURO | -#endif -#ifdef CONFIG_HISAX_NI1 - ISDN_FEATURE_P_NI1 | -#endif - 0; - - cs->iif.command = HiSax_command; - cs->iif.writecmd = NULL; - cs->iif.writebuf_skb = HiSax_writebuf_skb; - cs->iif.readstat = HiSax_readstatus; - register_isdn(&cs->iif); - cs->myid = cs->iif.channels; - printk(KERN_INFO - "HiSax: Card %d Protocol %s Id=%s (%d)\n", cardnr + 1, - (card->protocol == ISDN_PTYPE_1TR6) ? "1TR6" : - (card->protocol == ISDN_PTYPE_EURO) ? "EDSS1" : - (card->protocol == ISDN_PTYPE_LEASED) ? "LEASED" : - (card->protocol == ISDN_PTYPE_NI1) ? "NI1" : - "NONE", cs->iif.id, cs->myid); + do_register_isdn(cs); switch (card->typ) { #ifdef CONFIG_HISAX_16_0 case ISDN_CTYPE_16_0: @@ -1117,17 +1143,11 @@ ret = 0; goto outf_cs; } - init_tei(cs, cs->protocol); - ret = CallcNewChan(cs); - if (ret) { + if (do_init(cs)) { closecard(cardnr); ret = 0; goto outf_cs; } - /* ISAR needs firmware download first */ - if (!test_bit(HW_ISAR, &cs->HW_Flags)) - ll_run(cs, 0); - ret = 1; goto out; @@ -1677,43 +1697,61 @@ static void hisax_bh(void *data); static void EChannel_proc_rcv(struct hisax_d_if *d_if); +static int +hisax_l1_open(struct PStack *st, struct IsdnCardState *cs) +{ + st->l1.l2l1 = hisax_d_l2l1; + return 0; +} + static struct dc_l1_ops hisax_l1_ops = { + .open = hisax_l1_open, .bh_func = hisax_bh, }; +static struct bc_l1_ops hisax_bc_l1_ops = { + .open = hisax_bc_setstack, + .close = hisax_bc_close, +}; + int hisax_register(struct hisax_d_if *hisax_d_if, struct hisax_b_if *b_if[], char *name, int protocol) { - int i, retval; - char id[20]; + int i; struct IsdnCardState *cs; - + for (i = 0; i < HISAX_MAX_CARDS; i++) { if (!cards[i].typ) break; } - + if (i >= HISAX_MAX_CARDS) return -EBUSY; - - cards[i].typ = ISDN_CTYPE_DYNAMIC; - cards[i].protocol = protocol; - sprintf(id, "%s%d", name, i); + nrcards++; - retval = checkcard(i, id, 0); - if (retval == 0) { // yuck - cards[i].typ = 0; - nrcards--; - return retval; - } - cs = cards[i].cs; + + cs = alloc_IsdnCardState(); + if (!cs) + return -ENOMEM; + +#if TEI_PER_CARD + if (protocol == ISDN_PTYPE_NI1) + test_and_set_bit(FLG_TWO_DCHAN, &cs->HW_Flags); +#else + test_and_set_bit(FLG_TWO_DCHAN, &cs->HW_Flags); +#endif + cs->cardnr = i; + cs->protocol = protocol; + cs->typ = ISDN_CTYPE_DYNAMIC; + + sprintf(cs->iif.id, "%s%d", name, i); + do_register_isdn(cs); + hisax_d_if->cs = cs; cs->hw.hisax_d_if = hisax_d_if; - cs->iif.owner = hisax_d_if->owner; // FIXME should be done before registering + cs->iif.owner = hisax_d_if->owner; dc_l1_init(cs, &hisax_l1_ops); - cs->channel[0].d_st->l1.l2l1 = hisax_d_l2l1; - cs->bc_l1_ops->open = hisax_bc_setstack; - cs->bc_l1_ops->close = hisax_bc_close; + cs->bc_l1_ops = &hisax_bc_l1_ops; for (i = 0; i < 2; i++) { b_if[i]->ifc.l1l2 = hisax_b_l1l2; @@ -1724,6 +1762,8 @@ skb_queue_head_init(&hisax_d_if->erq); clear_bit(0, &hisax_d_if->ph_state); + do_init(cs); + return 0; } diff -Nru a/drivers/isdn/hisax/fsm.c b/drivers/isdn/hisax/fsm.c --- a/drivers/isdn/hisax/fsm.c Sun Jul 27 10:13:42 2003 +++ b/drivers/isdn/hisax/fsm.c Sun Jul 27 10:13:42 2003 @@ -20,7 +20,7 @@ #define FSM_TIMER_DEBUG 0 -int __init +int FsmNew(struct Fsm *fsm, struct FsmNode *fnlist, int fncount) { int i; diff -Nru a/drivers/isdn/hisax/st5481_init.c b/drivers/isdn/hisax/st5481_init.c --- a/drivers/isdn/hisax/st5481_init.c Sun Jul 27 10:13:52 2003 +++ b/drivers/isdn/hisax/st5481_init.c Sun Jul 27 10:13:52 2003 @@ -196,7 +196,7 @@ st5481_debug = debug; #endif - printk(KERN_INFO "hiax_st5481: ST5481 USB ISDN driver v0.1.0\n"); + printk(KERN_INFO "hisax_st5481: ST5481 USB ISDN driver v0.1.0\n"); retval = st5481_d_init(); if (retval < 0) @@ -217,6 +217,7 @@ static void __exit st5481_usb_exit(void) { usb_deregister(&st5481_usb_driver); + st5481_d_exit(); } module_init(st5481_usb_init); diff -Nru a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c --- a/drivers/isdn/i4l/isdn_common.c Sun Jul 27 10:13:43 2003 +++ b/drivers/isdn/i4l/isdn_common.c Sun Jul 27 10:13:43 2003 @@ -534,8 +534,7 @@ unsigned long flags; struct isdn_driver *drv; - if (di < 0) - return NULL; + BUG_ON(di < 0 || di >= ISDN_MAX_DRIVERS); spin_lock_irqsave(&drivers_lock, flags); drv = drivers[di]; @@ -1148,7 +1147,7 @@ int di, ch; struct isdn_driver *drv; - for (di = 0; di < ISDN_MAX_CHANNELS; di++) { + for (di = 0; di < ISDN_MAX_DRIVERS; di++) { drv = get_drv_by_nr(di); if (!drv) continue; diff -Nru a/drivers/macintosh/adbhid.c b/drivers/macintosh/adbhid.c --- a/drivers/macintosh/adbhid.c Sun Jul 27 10:13:52 2003 +++ b/drivers/macintosh/adbhid.c Sun Jul 27 10:13:52 2003 @@ -44,7 +44,9 @@ #include #include +#ifdef CONFIG_PPC_PMAC #include +#endif #ifdef CONFIG_PMAC_BACKLIGHT #include @@ -160,6 +162,7 @@ return; case 0x3f: /* ignore Powerbook Fn key */ return; +#ifdef CONFIG_PPC_PMAC case 0x7e: /* Power key on PBook 3400 needs remapping */ switch(pmac_call_feature(PMAC_FTR_GET_MB_INFO, NULL, PMAC_MB_INFO_MODEL, 0)) { @@ -169,6 +172,7 @@ keycode = 0x7f; } break; +#endif /* CONFIG_PPC_PMAC */ } if (adbhid[id]->keycode[keycode]) { diff -Nru a/drivers/md/Kconfig b/drivers/md/Kconfig --- a/drivers/md/Kconfig Sun Jul 27 10:13:41 2003 +++ b/drivers/md/Kconfig Sun Jul 27 10:13:41 2003 @@ -145,5 +145,12 @@ If unsure, say N. +config DM_IOCTL_V4 + bool "ioctl interface version 4" + depends on BLK_DEV_DM + ---help--- + Recent tools use a new version of the ioctl interface, only + select this option if you intend using such tools. + endmenu diff -Nru a/drivers/md/dm-ioctl-v1.c b/drivers/md/dm-ioctl-v1.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/md/dm-ioctl-v1.c Sun Jul 27 10:13:53 2003 @@ -0,0 +1,1160 @@ +/* + * Copyright (C) 2001, 2002 Sistina Software (UK) Limited. + * + * This file is released under the GPL. + */ + +#include "dm.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define DM_DRIVER_EMAIL "dm@uk.sistina.com" + +/*----------------------------------------------------------------- + * The ioctl interface needs to be able to look up devices by + * name or uuid. + *---------------------------------------------------------------*/ +struct hash_cell { + struct list_head name_list; + struct list_head uuid_list; + + char *name; + char *uuid; + struct mapped_device *md; +}; + +#define NUM_BUCKETS 64 +#define MASK_BUCKETS (NUM_BUCKETS - 1) +static struct list_head _name_buckets[NUM_BUCKETS]; +static struct list_head _uuid_buckets[NUM_BUCKETS]; + +void dm_hash_remove_all(void); + +/* + * Guards access to all three tables. + */ +static DECLARE_RWSEM(_hash_lock); + +static void init_buckets(struct list_head *buckets) +{ + unsigned int i; + + for (i = 0; i < NUM_BUCKETS; i++) + INIT_LIST_HEAD(buckets + i); +} + +int dm_hash_init(void) +{ + init_buckets(_name_buckets); + init_buckets(_uuid_buckets); + devfs_mk_dir(DM_DIR); + return 0; +} + +void dm_hash_exit(void) +{ + dm_hash_remove_all(); + devfs_remove(DM_DIR); +} + +/*----------------------------------------------------------------- + * Hash function: + * We're not really concerned with the str hash function being + * fast since it's only used by the ioctl interface. + *---------------------------------------------------------------*/ +static unsigned int hash_str(const char *str) +{ + const unsigned int hash_mult = 2654435387U; + unsigned int h = 0; + + while (*str) + h = (h + (unsigned int) *str++) * hash_mult; + + return h & MASK_BUCKETS; +} + +/*----------------------------------------------------------------- + * Code for looking up a device by name + *---------------------------------------------------------------*/ +static struct hash_cell *__get_name_cell(const char *str) +{ + struct list_head *tmp; + struct hash_cell *hc; + unsigned int h = hash_str(str); + + list_for_each (tmp, _name_buckets + h) { + hc = list_entry(tmp, struct hash_cell, name_list); + if (!strcmp(hc->name, str)) + return hc; + } + + return NULL; +} + +static struct hash_cell *__get_uuid_cell(const char *str) +{ + struct list_head *tmp; + struct hash_cell *hc; + unsigned int h = hash_str(str); + + list_for_each (tmp, _uuid_buckets + h) { + hc = list_entry(tmp, struct hash_cell, uuid_list); + if (!strcmp(hc->uuid, str)) + return hc; + } + + return NULL; +} + +/*----------------------------------------------------------------- + * Inserting, removing and renaming a device. + *---------------------------------------------------------------*/ +static inline char *kstrdup(const char *str) +{ + char *r = kmalloc(strlen(str) + 1, GFP_KERNEL); + if (r) + strcpy(r, str); + return r; +} + +static struct hash_cell *alloc_cell(const char *name, const char *uuid, + struct mapped_device *md) +{ + struct hash_cell *hc; + + hc = kmalloc(sizeof(*hc), GFP_KERNEL); + if (!hc) + return NULL; + + hc->name = kstrdup(name); + if (!hc->name) { + kfree(hc); + return NULL; + } + + if (!uuid) + hc->uuid = NULL; + + else { + hc->uuid = kstrdup(uuid); + if (!hc->uuid) { + kfree(hc->name); + kfree(hc); + return NULL; + } + } + + INIT_LIST_HEAD(&hc->name_list); + INIT_LIST_HEAD(&hc->uuid_list); + hc->md = md; + return hc; +} + +static void free_cell(struct hash_cell *hc) +{ + if (hc) { + kfree(hc->name); + kfree(hc->uuid); + kfree(hc); + } +} + +/* + * devfs stuff. + */ +static int register_with_devfs(struct hash_cell *hc) +{ + struct gendisk *disk = dm_disk(hc->md); + + devfs_mk_bdev(MKDEV(disk->major, disk->first_minor), + S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP, + DM_DIR "/%s", hc->name); + return 0; +} + +static int unregister_with_devfs(struct hash_cell *hc) +{ + devfs_remove(DM_DIR"/%s", hc->name); + return 0; +} + +/* + * The kdev_t and uuid of a device can never change once it is + * initially inserted. + */ +int dm_hash_insert(const char *name, const char *uuid, struct mapped_device *md) +{ + struct hash_cell *cell; + + /* + * Allocate the new cells. + */ + cell = alloc_cell(name, uuid, md); + if (!cell) + return -ENOMEM; + + /* + * Insert the cell into all three hash tables. + */ + down_write(&_hash_lock); + if (__get_name_cell(name)) + goto bad; + + list_add(&cell->name_list, _name_buckets + hash_str(name)); + + if (uuid) { + if (__get_uuid_cell(uuid)) { + list_del(&cell->name_list); + goto bad; + } + list_add(&cell->uuid_list, _uuid_buckets + hash_str(uuid)); + } + register_with_devfs(cell); + dm_get(md); + up_write(&_hash_lock); + + return 0; + + bad: + up_write(&_hash_lock); + free_cell(cell); + return -EBUSY; +} + +void __hash_remove(struct hash_cell *hc) +{ + /* remove from the dev hash */ + list_del(&hc->uuid_list); + list_del(&hc->name_list); + unregister_with_devfs(hc); + dm_put(hc->md); + free_cell(hc); +} + +void dm_hash_remove_all(void) +{ + int i; + struct hash_cell *hc; + struct list_head *tmp, *n; + + down_write(&_hash_lock); + for (i = 0; i < NUM_BUCKETS; i++) { + list_for_each_safe (tmp, n, _name_buckets + i) { + hc = list_entry(tmp, struct hash_cell, name_list); + __hash_remove(hc); + } + } + up_write(&_hash_lock); +} + +int dm_hash_rename(const char *old, const char *new) +{ + char *new_name, *old_name; + struct hash_cell *hc; + + /* + * duplicate new. + */ + new_name = kstrdup(new); + if (!new_name) + return -ENOMEM; + + down_write(&_hash_lock); + + /* + * Is new free ? + */ + hc = __get_name_cell(new); + if (hc) { + DMWARN("asked to rename to an already existing name %s -> %s", + old, new); + up_write(&_hash_lock); + kfree(new_name); + return -EBUSY; + } + + /* + * Is there such a device as 'old' ? + */ + hc = __get_name_cell(old); + if (!hc) { + DMWARN("asked to rename a non existent device %s -> %s", + old, new); + up_write(&_hash_lock); + kfree(new_name); + return -ENXIO; + } + + /* + * rename and move the name cell. + */ + unregister_with_devfs(hc); + + list_del(&hc->name_list); + old_name = hc->name; + hc->name = new_name; + list_add(&hc->name_list, _name_buckets + hash_str(new_name)); + + /* rename the device node in devfs */ + register_with_devfs(hc); + + up_write(&_hash_lock); + kfree(old_name); + return 0; +} + + +/*----------------------------------------------------------------- + * Implementation of the ioctl commands + *---------------------------------------------------------------*/ + +/* + * All the ioctl commands get dispatched to functions with this + * prototype. + */ +typedef int (*ioctl_fn)(struct dm_ioctl *param, struct dm_ioctl *user); + +/* + * Check a string doesn't overrun the chunk of + * memory we copied from userland. + */ +static int valid_str(char *str, void *begin, void *end) +{ + while (((void *) str >= begin) && ((void *) str < end)) + if (!*str++) + return 0; + + return -EINVAL; +} + +static int next_target(struct dm_target_spec *last, uint32_t next, + void *begin, void *end, + struct dm_target_spec **spec, char **params) +{ + *spec = (struct dm_target_spec *) + ((unsigned char *) last + next); + *params = (char *) (*spec + 1); + + if (*spec < (last + 1) || ((void *) *spec > end)) + return -EINVAL; + + return valid_str(*params, begin, end); +} + +static int populate_table(struct dm_table *table, struct dm_ioctl *args) +{ + int r, first = 1; + unsigned int i = 0; + struct dm_target_spec *spec; + char *params; + void *begin, *end; + + if (!args->target_count) { + DMWARN("populate_table: no targets specified"); + return -EINVAL; + } + + begin = (void *) args; + end = begin + args->data_size; + + for (i = 0; i < args->target_count; i++) { + + if (first) + r = next_target((struct dm_target_spec *) args, + args->data_start, + begin, end, &spec, ¶ms); + else + r = next_target(spec, spec->next, begin, end, + &spec, ¶ms); + + if (r) { + DMWARN("unable to find target"); + return -EINVAL; + } + + r = dm_table_add_target(table, spec->target_type, + (sector_t) spec->sector_start, + (sector_t) spec->length, + params); + if (r) { + DMWARN("internal error adding target to table"); + return -EINVAL; + } + + first = 0; + } + + return dm_table_complete(table); +} + +/* + * Round up the ptr to the next 'align' boundary. Obviously + * 'align' must be a power of 2. + */ +static inline void *align_ptr(void *ptr, unsigned int align) +{ + align--; + return (void *) (((unsigned long) (ptr + align)) & ~align); +} + +/* + * Copies a dm_ioctl and an optional additional payload to + * userland. + */ +static int results_to_user(struct dm_ioctl *user, struct dm_ioctl *param, + void *data, uint32_t len) +{ + int r; + void *ptr = NULL; + + if (data) { + ptr = align_ptr(user + 1, sizeof(unsigned long)); + param->data_start = ptr - (void *) user; + } + + /* + * The version number has already been filled in, so we + * just copy later fields. + */ + r = copy_to_user(&user->data_size, ¶m->data_size, + sizeof(*param) - sizeof(param->version)); + if (r) + return -EFAULT; + + if (data) { + if (param->data_start + len > param->data_size) + return -ENOSPC; + + if (copy_to_user(ptr, data, len)) + r = -EFAULT; + } + + return r; +} + +/* + * Fills in a dm_ioctl structure, ready for sending back to + * userland. + */ +static int __info(struct mapped_device *md, struct dm_ioctl *param) +{ + struct dm_table *table; + struct block_device *bdev; + struct gendisk *disk = dm_disk(md); + + param->flags = DM_EXISTS_FLAG; + if (dm_suspended(md)) + param->flags |= DM_SUSPEND_FLAG; + + bdev = bdget_disk(disk, 0); + if (!bdev) + return -ENXIO; + + param->dev = bdev->bd_dev; + param->open_count = bdev->bd_openers; + bdput(bdev); + + if (disk->policy) + param->flags |= DM_READONLY_FLAG; + + table = dm_get_table(md); + param->target_count = dm_table_get_num_targets(table); + dm_table_put(table); + + return 0; +} + +/* + * Always use UUID for lookups if it's present, otherwise use name. + */ +static inline struct mapped_device *find_device(struct dm_ioctl *param) +{ + struct hash_cell *hc; + struct mapped_device *md = NULL; + + down_read(&_hash_lock); + hc = *param->uuid ? __get_uuid_cell(param->uuid) : + __get_name_cell(param->name); + if (hc) { + md = hc->md; + + /* + * Sneakily write in both the name and the uuid + * while we have the cell. + */ + strlcpy(param->name, hc->name, sizeof(param->name)); + if (hc->uuid) + strlcpy(param->uuid, hc->uuid, sizeof(param->uuid)); + else + param->uuid[0] = '\0'; + + dm_get(md); + } + up_read(&_hash_lock); + + return md; +} + +#define ALIGNMENT sizeof(int) +static void *_align(void *ptr, unsigned int a) +{ + register unsigned long align = --a; + + return (void *) (((unsigned long) ptr + align) & ~align); +} + +/* + * Copies device info back to user space, used by + * the create and info ioctls. + */ +static int info(struct dm_ioctl *param, struct dm_ioctl *user) +{ + struct mapped_device *md; + + param->flags = 0; + + md = find_device(param); + if (!md) + /* + * Device not found - returns cleared exists flag. + */ + goto out; + + __info(md, param); + dm_put(md); + + out: + return results_to_user(user, param, NULL, 0); +} + +static inline int get_mode(struct dm_ioctl *param) +{ + int mode = FMODE_READ | FMODE_WRITE; + + if (param->flags & DM_READONLY_FLAG) + mode = FMODE_READ; + + return mode; +} + +static int check_name(const char *name) +{ + if (name[0] == '/') { + DMWARN("invalid device name"); + return -EINVAL; + } + + return 0; +} + +static int create(struct dm_ioctl *param, struct dm_ioctl *user) +{ + int r; + struct dm_table *t; + struct mapped_device *md; + + r = check_name(param->name); + if (r) + return r; + + r = dm_table_create(&t, get_mode(param)); + if (r) + return r; + + r = populate_table(t, param); + if (r) { + dm_table_put(t); + return r; + } + + if (param->flags & DM_PERSISTENT_DEV_FLAG) + r = dm_create_with_minor(minor(to_kdev_t(param->dev)), &md); + else + r = dm_create(&md); + + if (r) { + dm_table_put(t); + return r; + } + + /* suspend the device */ + r = dm_suspend(md); + if (r) { + DMWARN("suspend failed"); + dm_table_put(t); + dm_put(md); + return r; + } + /* swap in the table */ + r = dm_swap_table(md, t); + if (r) { + DMWARN("table swap failed"); + dm_table_put(t); + dm_put(md); + return r; + } + + /* resume the device */ + r = dm_resume(md); + if (r) { + DMWARN("resume failed"); + dm_table_put(t); + dm_put(md); + return r; + } + + dm_table_put(t); /* md will have grabbed its own reference */ + + set_disk_ro(dm_disk(md), (param->flags & DM_READONLY_FLAG) ? 1 : 0); + r = dm_hash_insert(param->name, *param->uuid ? param->uuid : NULL, md); + dm_put(md); + + return r ? r : info(param, user); +} + +/* + * Build up the status struct for each target + */ +static int __status(struct mapped_device *md, struct dm_ioctl *param, + char *outbuf, size_t *len) +{ + unsigned int i, num_targets; + struct dm_target_spec *spec; + char *outptr; + status_type_t type; + struct dm_table *table = dm_get_table(md); + + if (param->flags & DM_STATUS_TABLE_FLAG) + type = STATUSTYPE_TABLE; + else + type = STATUSTYPE_INFO; + + outptr = outbuf; + + /* Get all the target info */ + num_targets = dm_table_get_num_targets(table); + for (i = 0; i < num_targets; i++) { + struct dm_target *ti = dm_table_get_target(table, i); + + if (outptr - outbuf + + sizeof(struct dm_target_spec) > param->data_size) { + dm_table_put(table); + return -ENOMEM; + } + + spec = (struct dm_target_spec *) outptr; + + spec->status = 0; + spec->sector_start = ti->begin; + spec->length = ti->len; + strlcpy(spec->target_type, ti->type->name, + sizeof(spec->target_type)); + + outptr += sizeof(struct dm_target_spec); + + /* Get the status/table string from the target driver */ + if (ti->type->status) + ti->type->status(ti, type, outptr, + outbuf + param->data_size - outptr); + else + outptr[0] = '\0'; + + outptr += strlen(outptr) + 1; + _align(outptr, ALIGNMENT); + spec->next = outptr - outbuf; + } + + param->target_count = num_targets; + *len = outptr - outbuf; + dm_table_put(table); + + return 0; +} + +/* + * Return the status of a device as a text string for each + * target. + */ +static int get_status(struct dm_ioctl *param, struct dm_ioctl *user) +{ + struct mapped_device *md; + size_t len = 0; + int ret; + char *outbuf = NULL; + + md = find_device(param); + if (!md) + /* + * Device not found - returns cleared exists flag. + */ + goto out; + + /* We haven't a clue how long the resultant data will be so + just allocate as much as userland has allowed us and make sure + we don't overun it */ + outbuf = kmalloc(param->data_size, GFP_KERNEL); + if (!outbuf) + goto out; + /* + * Get the status of all targets + */ + __status(md, param, outbuf, &len); + + /* + * Setup the basic dm_ioctl structure. + */ + __info(md, param); + + out: + if (md) + dm_put(md); + + ret = results_to_user(user, param, outbuf, len); + + if (outbuf) + kfree(outbuf); + + return ret; +} + +/* + * Wait for a device to report an event + */ +static int wait_device_event(struct dm_ioctl *param, struct dm_ioctl *user) +{ + struct mapped_device *md; + DECLARE_WAITQUEUE(wq, current); + + md = find_device(param); + if (!md) + /* + * Device not found - returns cleared exists flag. + */ + goto out; + + /* + * Setup the basic dm_ioctl structure. + */ + __info(md, param); + + /* + * Wait for a notification event + */ + set_current_state(TASK_INTERRUPTIBLE); + if (!dm_add_wait_queue(md, &wq, dm_get_event_nr(md))) { + schedule(); + dm_remove_wait_queue(md, &wq); + } + set_current_state(TASK_RUNNING); + dm_put(md); + + out: + return results_to_user(user, param, NULL, 0); +} + +/* + * Retrieves a list of devices used by a particular dm device. + */ +static int dep(struct dm_ioctl *param, struct dm_ioctl *user) +{ + int r; + unsigned int count; + struct mapped_device *md; + struct list_head *tmp; + size_t len = 0; + struct dm_target_deps *deps = NULL; + struct dm_table *table; + + md = find_device(param); + if (!md) + goto out; + table = dm_get_table(md); + + /* + * Setup the basic dm_ioctl structure. + */ + __info(md, param); + + /* + * Count the devices. + */ + count = 0; + list_for_each(tmp, dm_table_get_devices(table)) + count++; + + /* + * Allocate a kernel space version of the dm_target_status + * struct. + */ + if (array_too_big(sizeof(*deps), sizeof(*deps->dev), count)) { + dm_table_put(table); + dm_put(md); + return -ENOMEM; + } + + len = sizeof(*deps) + (sizeof(*deps->dev) * count); + deps = kmalloc(len, GFP_KERNEL); + if (!deps) { + dm_table_put(table); + dm_put(md); + return -ENOMEM; + } + + /* + * Fill in the devices. + */ + deps->count = count; + count = 0; + list_for_each(tmp, dm_table_get_devices(table)) { + struct dm_dev *dd = list_entry(tmp, struct dm_dev, list); + deps->dev[count++] = dd->bdev->bd_dev; + } + dm_table_put(table); + dm_put(md); + + out: + r = results_to_user(user, param, deps, len); + + kfree(deps); + return r; +} + +static int remove(struct dm_ioctl *param, struct dm_ioctl *user) +{ + struct hash_cell *hc; + + down_write(&_hash_lock); + hc = *param->uuid ? __get_uuid_cell(param->uuid) : + __get_name_cell(param->name); + if (!hc) { + DMWARN("device doesn't appear to be in the dev hash table."); + up_write(&_hash_lock); + return -EINVAL; + } + + /* + * You may ask the interface to drop its reference to an + * in use device. This is no different to unlinking a + * file that someone still has open. The device will not + * actually be destroyed until the last opener closes it. + * The name and uuid of the device (both are interface + * properties) will be available for reuse immediately. + * + * You don't want to drop a _suspended_ device from the + * interface, since that will leave you with no way of + * resuming it. + */ + if (dm_suspended(hc->md)) { + DMWARN("refusing to remove a suspended device."); + up_write(&_hash_lock); + return -EPERM; + } + + __hash_remove(hc); + up_write(&_hash_lock); + return 0; +} + +static int remove_all(struct dm_ioctl *param, struct dm_ioctl *user) +{ + dm_hash_remove_all(); + return 0; +} + +static int suspend(struct dm_ioctl *param, struct dm_ioctl *user) +{ + int r; + struct mapped_device *md; + + md = find_device(param); + if (!md) + return -ENXIO; + + if (param->flags & DM_SUSPEND_FLAG) + r = dm_suspend(md); + else + r = dm_resume(md); + + dm_put(md); + return r; +} + +static int reload(struct dm_ioctl *param, struct dm_ioctl *user) +{ + int r; + struct mapped_device *md; + struct dm_table *t; + + r = dm_table_create(&t, get_mode(param)); + if (r) + return r; + + r = populate_table(t, param); + if (r) { + dm_table_put(t); + return r; + } + + md = find_device(param); + if (!md) { + dm_table_put(t); + return -ENXIO; + } + + r = dm_swap_table(md, t); + if (r) { + dm_put(md); + dm_table_put(t); + return r; + } + dm_table_put(t); /* md will have taken its own reference */ + + set_disk_ro(dm_disk(md), (param->flags & DM_READONLY_FLAG) ? 1 : 0); + dm_put(md); + + r = info(param, user); + return r; +} + +static int rename(struct dm_ioctl *param, struct dm_ioctl *user) +{ + int r; + char *new_name = (char *) param + param->data_start; + + if (valid_str(new_name, (void *) param, + (void *) param + param->data_size)) { + DMWARN("Invalid new logical volume name supplied."); + return -EINVAL; + } + + r = check_name(new_name); + if (r) + return r; + + return dm_hash_rename(param->name, new_name); +} + + +/*----------------------------------------------------------------- + * Implementation of open/close/ioctl on the special char + * device. + *---------------------------------------------------------------*/ +static ioctl_fn lookup_ioctl(unsigned int cmd) +{ + static struct { + int cmd; + ioctl_fn fn; + } _ioctls[] = { + {DM_VERSION_CMD, NULL}, /* version is dealt with elsewhere */ + {DM_REMOVE_ALL_CMD, remove_all}, + {DM_DEV_CREATE_CMD, create}, + {DM_DEV_REMOVE_CMD, remove}, + {DM_DEV_RELOAD_CMD, reload}, + {DM_DEV_RENAME_CMD, rename}, + {DM_DEV_SUSPEND_CMD, suspend}, + {DM_DEV_DEPS_CMD, dep}, + {DM_DEV_STATUS_CMD, info}, + {DM_TARGET_STATUS_CMD, get_status}, + {DM_TARGET_WAIT_CMD, wait_device_event}, + }; + + return (cmd >= ARRAY_SIZE(_ioctls)) ? NULL : _ioctls[cmd].fn; +} + +/* + * As well as checking the version compatibility this always + * copies the kernel interface version out. + */ +static int check_version(unsigned int cmd, struct dm_ioctl *user) +{ + uint32_t version[3]; + int r = 0; + + if (copy_from_user(version, user->version, sizeof(version))) + return -EFAULT; + + if ((DM_VERSION_MAJOR != version[0]) || + (DM_VERSION_MINOR < version[1])) { + DMWARN("ioctl interface mismatch: " + "kernel(%u.%u.%u), user(%u.%u.%u), cmd(%d)", + DM_VERSION_MAJOR, DM_VERSION_MINOR, + DM_VERSION_PATCHLEVEL, + version[0], version[1], version[2], cmd); + r = -EINVAL; + } + + /* + * Fill in the kernel version. + */ + version[0] = DM_VERSION_MAJOR; + version[1] = DM_VERSION_MINOR; + version[2] = DM_VERSION_PATCHLEVEL; + if (copy_to_user(user->version, version, sizeof(version))) + return -EFAULT; + + return r; +} + +static void free_params(struct dm_ioctl *param) +{ + vfree(param); +} + +static int copy_params(struct dm_ioctl *user, struct dm_ioctl **param) +{ + struct dm_ioctl tmp, *dmi; + + if (copy_from_user(&tmp, user, sizeof(tmp))) + return -EFAULT; + + if (tmp.data_size < sizeof(tmp)) + return -EINVAL; + + dmi = (struct dm_ioctl *) vmalloc(tmp.data_size); + if (!dmi) + return -ENOMEM; + + if (copy_from_user(dmi, user, tmp.data_size)) { + vfree(dmi); + return -EFAULT; + } + + *param = dmi; + return 0; +} + +static int validate_params(uint cmd, struct dm_ioctl *param) +{ + /* Ignores parameters */ + if (cmd == DM_REMOVE_ALL_CMD) + return 0; + + /* Unless creating, either name of uuid but not both */ + if (cmd != DM_DEV_CREATE_CMD) { + if ((!*param->uuid && !*param->name) || + (*param->uuid && *param->name)) { + DMWARN("one of name or uuid must be supplied"); + return -EINVAL; + } + } + + /* Ensure strings are terminated */ + param->name[DM_NAME_LEN - 1] = '\0'; + param->uuid[DM_UUID_LEN - 1] = '\0'; + + return 0; +} + +static int ctl_ioctl(struct inode *inode, struct file *file, + uint command, ulong u) +{ + int r = 0; + unsigned int cmd; + struct dm_ioctl *param; + struct dm_ioctl *user = (struct dm_ioctl *) u; + ioctl_fn fn = NULL; + + /* only root can play with this */ + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + if (_IOC_TYPE(command) != DM_IOCTL) + return -ENOTTY; + + cmd = _IOC_NR(command); + + /* + * Check the interface version passed in. This also + * writes out the kernels interface version. + */ + r = check_version(cmd, user); + if (r) + return r; + + /* + * Nothing more to do for the version command. + */ + if (cmd == DM_VERSION_CMD) + return 0; + + fn = lookup_ioctl(cmd); + if (!fn) { + DMWARN("dm_ctl_ioctl: unknown command 0x%x", command); + return -ENOTTY; + } + + /* + * Copy the parameters into kernel space. + */ + r = copy_params(user, ¶m); + if (r) + return r; + + r = validate_params(cmd, param); + if (r) { + free_params(param); + return r; + } + + r = fn(param, user); + free_params(param); + return r; +} + +static struct file_operations _ctl_fops = { + .ioctl = ctl_ioctl, + .owner = THIS_MODULE, +}; + +static struct miscdevice _dm_misc = { + .minor = MISC_DYNAMIC_MINOR, + .name = DM_NAME, + .devfs_name = "mapper/control", + .fops = &_ctl_fops +}; + +/* + * Create misc character device and link to DM_DIR/control. + */ +int __init dm_interface_init(void) +{ + int r; + + r = dm_hash_init(); + if (r) + return r; + + r = misc_register(&_dm_misc); + if (r) { + DMERR("misc_register failed for control device"); + dm_hash_exit(); + return r; + } + + DMINFO("%d.%d.%d%s initialised: %s", DM_VERSION_MAJOR, + DM_VERSION_MINOR, DM_VERSION_PATCHLEVEL, DM_VERSION_EXTRA, + DM_DRIVER_EMAIL); + return 0; + + if (misc_deregister(&_dm_misc) < 0) + DMERR("misc_deregister failed for control device"); + dm_hash_exit(); + return r; +} + +void dm_interface_exit(void) +{ + if (misc_deregister(&_dm_misc) < 0) + DMERR("misc_deregister failed for control device"); + dm_hash_exit(); +} diff -Nru a/drivers/md/dm-ioctl-v4.c b/drivers/md/dm-ioctl-v4.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/md/dm-ioctl-v4.c Sun Jul 27 10:13:53 2003 @@ -0,0 +1,1252 @@ +/* + * Copyright (C) 2001, 2002 Sistina Software (UK) Limited. + * + * This file is released under the GPL. + */ + +#include "dm.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define DM_DRIVER_EMAIL "dm@uk.sistina.com" + +/*----------------------------------------------------------------- + * The ioctl interface needs to be able to look up devices by + * name or uuid. + *---------------------------------------------------------------*/ +struct hash_cell { + struct list_head name_list; + struct list_head uuid_list; + + char *name; + char *uuid; + struct mapped_device *md; + struct dm_table *new_map; +}; + +#define NUM_BUCKETS 64 +#define MASK_BUCKETS (NUM_BUCKETS - 1) +static struct list_head _name_buckets[NUM_BUCKETS]; +static struct list_head _uuid_buckets[NUM_BUCKETS]; + +void dm_hash_remove_all(void); + +/* + * Guards access to both hash tables. + */ +static DECLARE_RWSEM(_hash_lock); + +static void init_buckets(struct list_head *buckets) +{ + unsigned int i; + + for (i = 0; i < NUM_BUCKETS; i++) + INIT_LIST_HEAD(buckets + i); +} + +int dm_hash_init(void) +{ + init_buckets(_name_buckets); + init_buckets(_uuid_buckets); + devfs_mk_dir(DM_DIR); + return 0; +} + +void dm_hash_exit(void) +{ + dm_hash_remove_all(); + devfs_remove(DM_DIR); +} + +/*----------------------------------------------------------------- + * Hash function: + * We're not really concerned with the str hash function being + * fast since it's only used by the ioctl interface. + *---------------------------------------------------------------*/ +static unsigned int hash_str(const char *str) +{ + const unsigned int hash_mult = 2654435387U; + unsigned int h = 0; + + while (*str) + h = (h + (unsigned int) *str++) * hash_mult; + + return h & MASK_BUCKETS; +} + +/*----------------------------------------------------------------- + * Code for looking up a device by name + *---------------------------------------------------------------*/ +static struct hash_cell *__get_name_cell(const char *str) +{ + struct list_head *tmp; + struct hash_cell *hc; + unsigned int h = hash_str(str); + + list_for_each (tmp, _name_buckets + h) { + hc = list_entry(tmp, struct hash_cell, name_list); + if (!strcmp(hc->name, str)) + return hc; + } + + return NULL; +} + +static struct hash_cell *__get_uuid_cell(const char *str) +{ + struct list_head *tmp; + struct hash_cell *hc; + unsigned int h = hash_str(str); + + list_for_each (tmp, _uuid_buckets + h) { + hc = list_entry(tmp, struct hash_cell, uuid_list); + if (!strcmp(hc->uuid, str)) + return hc; + } + + return NULL; +} + +/*----------------------------------------------------------------- + * Inserting, removing and renaming a device. + *---------------------------------------------------------------*/ +static inline char *kstrdup(const char *str) +{ + char *r = kmalloc(strlen(str) + 1, GFP_KERNEL); + if (r) + strcpy(r, str); + return r; +} + +static struct hash_cell *alloc_cell(const char *name, const char *uuid, + struct mapped_device *md) +{ + struct hash_cell *hc; + + hc = kmalloc(sizeof(*hc), GFP_KERNEL); + if (!hc) + return NULL; + + hc->name = kstrdup(name); + if (!hc->name) { + kfree(hc); + return NULL; + } + + if (!uuid) + hc->uuid = NULL; + + else { + hc->uuid = kstrdup(uuid); + if (!hc->uuid) { + kfree(hc->name); + kfree(hc); + return NULL; + } + } + + INIT_LIST_HEAD(&hc->name_list); + INIT_LIST_HEAD(&hc->uuid_list); + hc->md = md; + hc->new_map = NULL; + return hc; +} + +static void free_cell(struct hash_cell *hc) +{ + if (hc) { + kfree(hc->name); + kfree(hc->uuid); + kfree(hc); + } +} + +/* + * devfs stuff. + */ +static int register_with_devfs(struct hash_cell *hc) +{ + struct gendisk *disk = dm_disk(hc->md); + + devfs_mk_bdev(MKDEV(disk->major, disk->first_minor), + S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP, + DM_DIR "/%s", hc->name); + return 0; +} + +static int unregister_with_devfs(struct hash_cell *hc) +{ + devfs_remove(DM_DIR"/%s", hc->name); + return 0; +} + +/* + * The kdev_t and uuid of a device can never change once it is + * initially inserted. + */ +int dm_hash_insert(const char *name, const char *uuid, struct mapped_device *md) +{ + struct hash_cell *cell; + + /* + * Allocate the new cells. + */ + cell = alloc_cell(name, uuid, md); + if (!cell) + return -ENOMEM; + + /* + * Insert the cell into both hash tables. + */ + down_write(&_hash_lock); + if (__get_name_cell(name)) + goto bad; + + list_add(&cell->name_list, _name_buckets + hash_str(name)); + + if (uuid) { + if (__get_uuid_cell(uuid)) { + list_del(&cell->name_list); + goto bad; + } + list_add(&cell->uuid_list, _uuid_buckets + hash_str(uuid)); + } + register_with_devfs(cell); + dm_get(md); + up_write(&_hash_lock); + + return 0; + + bad: + up_write(&_hash_lock); + free_cell(cell); + return -EBUSY; +} + +void __hash_remove(struct hash_cell *hc) +{ + /* remove from the dev hash */ + list_del(&hc->uuid_list); + list_del(&hc->name_list); + unregister_with_devfs(hc); + dm_put(hc->md); + if (hc->new_map) + dm_table_put(hc->new_map); + free_cell(hc); +} + +void dm_hash_remove_all(void) +{ + int i; + struct hash_cell *hc; + struct list_head *tmp, *n; + + down_write(&_hash_lock); + for (i = 0; i < NUM_BUCKETS; i++) { + list_for_each_safe (tmp, n, _name_buckets + i) { + hc = list_entry(tmp, struct hash_cell, name_list); + __hash_remove(hc); + } + } + up_write(&_hash_lock); +} + +int dm_hash_rename(const char *old, const char *new) +{ + char *new_name, *old_name; + struct hash_cell *hc; + + /* + * duplicate new. + */ + new_name = kstrdup(new); + if (!new_name) + return -ENOMEM; + + down_write(&_hash_lock); + + /* + * Is new free ? + */ + hc = __get_name_cell(new); + if (hc) { + DMWARN("asked to rename to an already existing name %s -> %s", + old, new); + up_write(&_hash_lock); + kfree(new_name); + return -EBUSY; + } + + /* + * Is there such a device as 'old' ? + */ + hc = __get_name_cell(old); + if (!hc) { + DMWARN("asked to rename a non existent device %s -> %s", + old, new); + up_write(&_hash_lock); + kfree(new_name); + return -ENXIO; + } + + /* + * rename and move the name cell. + */ + unregister_with_devfs(hc); + + list_del(&hc->name_list); + old_name = hc->name; + hc->name = new_name; + list_add(&hc->name_list, _name_buckets + hash_str(new_name)); + + /* rename the device node in devfs */ + register_with_devfs(hc); + + up_write(&_hash_lock); + kfree(old_name); + return 0; +} + +/*----------------------------------------------------------------- + * Implementation of the ioctl commands + *---------------------------------------------------------------*/ +/* + * All the ioctl commands get dispatched to functions with this + * prototype. + */ +typedef int (*ioctl_fn)(struct dm_ioctl *param, size_t param_size); + +static int remove_all(struct dm_ioctl *param, size_t param_size) +{ + dm_hash_remove_all(); + param->data_size = 0; + return 0; +} + +/* + * Round up the ptr to an 8-byte boundary. + */ +#define ALIGN_MASK 7 +static inline void *align_ptr(void *ptr) +{ + return (void *) (((size_t) (ptr + ALIGN_MASK)) & ~ALIGN_MASK); +} + +/* + * Retrieves the data payload buffer from an already allocated + * struct dm_ioctl. + */ +static void *get_result_buffer(struct dm_ioctl *param, size_t param_size, + size_t *len) +{ + param->data_start = align_ptr(param + 1) - (void *) param; + + if (param->data_start < param_size) + *len = param_size - param->data_start; + else + *len = 0; + + return ((void *) param) + param->data_start; +} + +static int list_devices(struct dm_ioctl *param, size_t param_size) +{ + unsigned int i; + struct hash_cell *hc; + size_t len, needed = 0; + struct gendisk *disk; + struct dm_name_list *nl, *old_nl = NULL; + + down_write(&_hash_lock); + + /* + * Loop through all the devices working out how much + * space we need. + */ + for (i = 0; i < NUM_BUCKETS; i++) { + list_for_each_entry (hc, _name_buckets + i, name_list) { + needed += sizeof(struct dm_name_list); + needed += strlen(hc->name); + needed += ALIGN_MASK; + } + } + + /* + * Grab our output buffer. + */ + nl = get_result_buffer(param, param_size, &len); + if (len < needed) { + param->flags |= DM_BUFFER_FULL_FLAG; + goto out; + } + param->data_size = param->data_start + needed; + + nl->dev = 0; /* Flags no data */ + + /* + * Now loop through filling out the names. + */ + for (i = 0; i < NUM_BUCKETS; i++) { + list_for_each_entry (hc, _name_buckets + i, name_list) { + if (old_nl) + old_nl->next = (uint32_t) ((void *) nl - + (void *) old_nl); + disk = dm_disk(hc->md); + nl->dev = MKDEV(disk->major, disk->first_minor); + nl->next = 0; + strcpy(nl->name, hc->name); + + old_nl = nl; + nl = align_ptr(((void *) ++nl) + strlen(hc->name) + 1); + } + } + + out: + up_write(&_hash_lock); + return 0; +} + +static int check_name(const char *name) +{ + if (strchr(name, '/')) { + DMWARN("invalid device name"); + return -EINVAL; + } + + return 0; +} + +/* + * Fills in a dm_ioctl structure, ready for sending back to + * userland. + */ +static int __dev_status(struct mapped_device *md, struct dm_ioctl *param) +{ + struct gendisk *disk = dm_disk(md); + struct dm_table *table; + struct block_device *bdev; + + param->flags &= ~(DM_SUSPEND_FLAG | DM_READONLY_FLAG | + DM_ACTIVE_PRESENT_FLAG); + + if (dm_suspended(md)) + param->flags |= DM_SUSPEND_FLAG; + + bdev = bdget_disk(disk, 0); + if (!bdev) + return -ENXIO; + + param->dev = MKDEV(disk->major, disk->first_minor); + + /* + * Yes, this will be out of date by the time it gets back + * to userland, but it is still very useful ofr + * debugging. + */ + param->open_count = bdev->bd_openers; + bdput(bdev); + + if (disk->policy) + param->flags |= DM_READONLY_FLAG; + + param->event_nr = dm_get_event_nr(md); + + table = dm_get_table(md); + if (table) { + param->flags |= DM_ACTIVE_PRESENT_FLAG; + param->target_count = dm_table_get_num_targets(table); + dm_table_put(table); + } else + param->target_count = 0; + + return 0; +} + +static int dev_create(struct dm_ioctl *param, size_t param_size) +{ + int r; + struct mapped_device *md; + + r = check_name(param->name); + if (r) + return r; + + if (param->flags & DM_PERSISTENT_DEV_FLAG) + r = dm_create_with_minor(minor(to_kdev_t(param->dev)), &md); + else + r = dm_create(&md); + + if (r) + return r; + + r = dm_hash_insert(param->name, *param->uuid ? param->uuid : NULL, md); + if (r) { + dm_put(md); + return r; + } + + param->flags &= ~DM_INACTIVE_PRESENT_FLAG; + + r = __dev_status(md, param); + dm_put(md); + + return r; +} + +/* + * Always use UUID for lookups if it's present, otherwise use name. + */ +static inline struct hash_cell *__find_device_hash_cell(struct dm_ioctl *param) +{ + return *param->uuid ? + __get_uuid_cell(param->uuid) : __get_name_cell(param->name); +} + +static inline struct mapped_device *find_device(struct dm_ioctl *param) +{ + struct hash_cell *hc; + struct mapped_device *md = NULL; + + down_read(&_hash_lock); + hc = __find_device_hash_cell(param); + if (hc) { + md = hc->md; + + /* + * Sneakily write in both the name and the uuid + * while we have the cell. + */ + strncpy(param->name, hc->name, sizeof(param->name)); + if (hc->uuid) + strncpy(param->uuid, hc->uuid, sizeof(param->uuid)-1); + else + param->uuid[0] = '\0'; + + if (hc->new_map) + param->flags |= DM_INACTIVE_PRESENT_FLAG; + else + param->flags &= ~DM_INACTIVE_PRESENT_FLAG; + + dm_get(md); + } + up_read(&_hash_lock); + + return md; +} + +static int dev_remove(struct dm_ioctl *param, size_t param_size) +{ + struct hash_cell *hc; + + down_write(&_hash_lock); + hc = __find_device_hash_cell(param); + + if (!hc) { + DMWARN("device doesn't appear to be in the dev hash table."); + up_write(&_hash_lock); + return -ENXIO; + } + + __hash_remove(hc); + up_write(&_hash_lock); + param->data_size = 0; + return 0; +} + +/* + * Check a string doesn't overrun the chunk of + * memory we copied from userland. + */ +static int invalid_str(char *str, void *end) +{ + while ((void *) str < end) + if (!*str++) + return 0; + + return -EINVAL; +} + +static int dev_rename(struct dm_ioctl *param, size_t param_size) +{ + int r; + char *new_name = (char *) param + param->data_start; + + if (new_name < (char *) (param + 1) || + invalid_str(new_name, (void *) param + param_size)) { + DMWARN("Invalid new logical volume name supplied."); + return -EINVAL; + } + + r = check_name(new_name); + if (r) + return r; + + param->data_size = 0; + return dm_hash_rename(param->name, new_name); +} + +static int suspend(struct dm_ioctl *param) +{ + int r = 0; + struct mapped_device *md; + + md = find_device(param); + if (!md) + return -ENXIO; + + if (!dm_suspended(md)) + r = dm_suspend(md); + + if (!r) + r = __dev_status(md, param); + + dm_put(md); + return r; +} + +static int resume(struct dm_ioctl *param) +{ + int r = 0; + struct hash_cell *hc; + struct mapped_device *md; + struct dm_table *new_map; + + down_write(&_hash_lock); + + hc = __find_device_hash_cell(param); + if (!hc) { + DMWARN("device doesn't appear to be in the dev hash table."); + up_write(&_hash_lock); + return -ENXIO; + } + + md = hc->md; + dm_get(md); + + new_map = hc->new_map; + hc->new_map = NULL; + param->flags &= ~DM_INACTIVE_PRESENT_FLAG; + + up_write(&_hash_lock); + + /* Do we need to load a new map ? */ + if (new_map) { + /* Suspend if it isn't already suspended */ + if (!dm_suspended(md)) + dm_suspend(md); + + r = dm_swap_table(md, new_map); + if (r) { + dm_put(md); + dm_table_put(new_map); + return r; + } + + if (dm_table_get_mode(new_map) & FMODE_WRITE) + set_disk_ro(dm_disk(md), 0); + else + set_disk_ro(dm_disk(md), 1); + + dm_table_put(new_map); + } + + if (dm_suspended(md)) + r = dm_resume(md); + + if (!r) + r = __dev_status(md, param); + + dm_put(md); + return r; +} + +/* + * Set or unset the suspension state of a device. + * If the device already is in the requested state we just return its status. + */ +static int dev_suspend(struct dm_ioctl *param, size_t param_size) +{ + if (param->flags & DM_SUSPEND_FLAG) + return suspend(param); + + return resume(param); +} + +/* + * Copies device info back to user space, used by + * the create and info ioctls. + */ +static int dev_status(struct dm_ioctl *param, size_t param_size) +{ + int r; + struct mapped_device *md; + + md = find_device(param); + if (!md) + return -ENXIO; + + r = __dev_status(md, param); + dm_put(md); + return r; +} + +/* + * Wait for a device to report an event + */ +static int dev_wait(struct dm_ioctl *param, size_t param_size) +{ + int r; + struct mapped_device *md; + DECLARE_WAITQUEUE(wq, current); + + md = find_device(param); + if (!md) + return -ENXIO; + + /* + * Wait for a notification event + */ + set_current_state(TASK_INTERRUPTIBLE); + if (!dm_add_wait_queue(md, &wq, param->event_nr)) { + schedule(); + dm_remove_wait_queue(md, &wq); + } + set_current_state(TASK_RUNNING); + + /* + * The userland program is going to want to know what + * changed to trigger the event, so we may as well tell + * him and save an ioctl. + */ + r = __dev_status(md, param); + + dm_put(md); + return r; +} + +static inline int get_mode(struct dm_ioctl *param) +{ + int mode = FMODE_READ | FMODE_WRITE; + + if (param->flags & DM_READONLY_FLAG) + mode = FMODE_READ; + + return mode; +} + +static int next_target(struct dm_target_spec *last, uint32_t next, void *end, + struct dm_target_spec **spec, char **target_params) +{ + *spec = (struct dm_target_spec *) ((unsigned char *) last + next); + *target_params = (char *) (*spec + 1); + + if (*spec < (last + 1)) + return -EINVAL; + + return invalid_str(*target_params, end); +} + +static int populate_table(struct dm_table *table, + struct dm_ioctl *param, size_t param_size) +{ + int r; + unsigned int i = 0; + struct dm_target_spec *spec = (struct dm_target_spec *) param; + uint32_t next = param->data_start; + void *end = (void *) param + param_size; + char *target_params; + + if (!param->target_count) { + DMWARN("populate_table: no targets specified"); + return -EINVAL; + } + + for (i = 0; i < param->target_count; i++) { + + r = next_target(spec, next, end, &spec, &target_params); + if (r) { + DMWARN("unable to find target"); + return r; + } + + r = dm_table_add_target(table, spec->target_type, + (sector_t) spec->sector_start, + (sector_t) spec->length, + target_params); + if (r) { + DMWARN("error adding target to table"); + return r; + } + + next = spec->next; + } + + return dm_table_complete(table); +} + +static int table_load(struct dm_ioctl *param, size_t param_size) +{ + int r; + struct hash_cell *hc; + struct dm_table *t; + + r = dm_table_create(&t, get_mode(param)); + if (r) + return r; + + r = populate_table(t, param, param_size); + if (r) { + dm_table_put(t); + return r; + } + + down_write(&_hash_lock); + hc = __find_device_hash_cell(param); + if (!hc) { + DMWARN("device doesn't appear to be in the dev hash table."); + up_write(&_hash_lock); + return -ENXIO; + } + + hc->new_map = t; + param->flags |= DM_INACTIVE_PRESENT_FLAG; + + r = __dev_status(hc->md, param); + up_write(&_hash_lock); + return r; +} + +static int table_clear(struct dm_ioctl *param, size_t param_size) +{ + int r; + struct hash_cell *hc; + + down_write(&_hash_lock); + + hc = __find_device_hash_cell(param); + if (!hc) { + DMWARN("device doesn't appear to be in the dev hash table."); + up_write(&_hash_lock); + return -ENXIO; + } + + if (hc->new_map) { + dm_table_put(hc->new_map); + hc->new_map = NULL; + } + + param->flags &= ~DM_INACTIVE_PRESENT_FLAG; + + r = __dev_status(hc->md, param); + up_write(&_hash_lock); + return r; +} + +/* + * Retrieves a list of devices used by a particular dm device. + */ +static void retrieve_deps(struct dm_table *table, + struct dm_ioctl *param, size_t param_size) +{ + unsigned int count = 0; + struct list_head *tmp; + size_t len, needed; + struct dm_target_deps *deps; + + deps = get_result_buffer(param, param_size, &len); + + /* + * Count the devices. + */ + list_for_each(tmp, dm_table_get_devices(table)) + count++; + + /* + * Check we have enough space. + */ + needed = sizeof(*deps) + (sizeof(*deps->dev) * count); + if (len < needed) { + param->flags |= DM_BUFFER_FULL_FLAG; + return; + } + + /* + * Fill in the devices. + */ + deps->count = count; + count = 0; + list_for_each(tmp, dm_table_get_devices(table)) { + struct dm_dev *dd = list_entry(tmp, struct dm_dev, list); + deps->dev[count++] = dd->bdev->bd_dev; + } + + param->data_size = param->data_start + needed; +} + +static int table_deps(struct dm_ioctl *param, size_t param_size) +{ + int r = 0; + struct mapped_device *md; + struct dm_table *table; + + md = find_device(param); + if (!md) + return -ENXIO; + + r = __dev_status(md, param); + if (r) + goto out; + + table = dm_get_table(md); + if (table) { + retrieve_deps(table, param, param_size); + dm_table_put(table); + } + + out: + dm_put(md); + return r; +} + +/* + * Build up the status struct for each target + */ +static void retrieve_status(struct dm_table *table, + struct dm_ioctl *param, size_t param_size) +{ + unsigned int i, num_targets; + struct dm_target_spec *spec; + char *outbuf, *outptr; + status_type_t type; + size_t remaining, len, used = 0; + + outptr = outbuf = get_result_buffer(param, param_size, &len); + + if (param->flags & DM_STATUS_TABLE_FLAG) + type = STATUSTYPE_TABLE; + else + type = STATUSTYPE_INFO; + + /* Get all the target info */ + num_targets = dm_table_get_num_targets(table); + for (i = 0; i < num_targets; i++) { + struct dm_target *ti = dm_table_get_target(table, i); + + remaining = len - (outptr - outbuf); + if (remaining < sizeof(struct dm_target_spec)) { + param->flags |= DM_BUFFER_FULL_FLAG; + break; + } + + spec = (struct dm_target_spec *) outptr; + + spec->status = 0; + spec->sector_start = ti->begin; + spec->length = ti->len; + strncpy(spec->target_type, ti->type->name, + sizeof(spec->target_type)); + + outptr += sizeof(struct dm_target_spec); + remaining = len - (outptr - outbuf); + + /* Get the status/table string from the target driver */ + if (ti->type->status) { + if (ti->type->status(ti, type, outptr, remaining)) { + param->flags |= DM_BUFFER_FULL_FLAG; + break; + } + } else + outptr[0] = '\0'; + + outptr += strlen(outptr) + 1; + used = param->data_start + (outptr - outbuf); + + align_ptr(outptr); + spec->next = outptr - outbuf; + } + + if (used) + param->data_size = used; + + param->target_count = num_targets; +} + +/* + * Return the status of a device as a text string for each + * target. + */ +static int table_status(struct dm_ioctl *param, size_t param_size) +{ + int r; + struct mapped_device *md; + struct dm_table *table; + + md = find_device(param); + if (!md) + return -ENXIO; + + r = __dev_status(md, param); + if (r) + goto out; + + table = dm_get_table(md); + if (table) { + retrieve_status(table, param, param_size); + dm_table_put(table); + } + + out: + dm_put(md); + return r; +} + +/*----------------------------------------------------------------- + * Implementation of open/close/ioctl on the special char + * device. + *---------------------------------------------------------------*/ +static ioctl_fn lookup_ioctl(unsigned int cmd) +{ + static struct { + int cmd; + ioctl_fn fn; + } _ioctls[] = { + {DM_VERSION_CMD, NULL}, /* version is dealt with elsewhere */ + {DM_REMOVE_ALL_CMD, remove_all}, + {DM_LIST_DEVICES_CMD, list_devices}, + + {DM_DEV_CREATE_CMD, dev_create}, + {DM_DEV_REMOVE_CMD, dev_remove}, + {DM_DEV_RENAME_CMD, dev_rename}, + {DM_DEV_SUSPEND_CMD, dev_suspend}, + {DM_DEV_STATUS_CMD, dev_status}, + {DM_DEV_WAIT_CMD, dev_wait}, + + {DM_TABLE_LOAD_CMD, table_load}, + {DM_TABLE_CLEAR_CMD, table_clear}, + {DM_TABLE_DEPS_CMD, table_deps}, + {DM_TABLE_STATUS_CMD, table_status} + }; + + return (cmd >= ARRAY_SIZE(_ioctls)) ? NULL : _ioctls[cmd].fn; +} + +/* + * As well as checking the version compatibility this always + * copies the kernel interface version out. + */ +static int check_version(unsigned int cmd, struct dm_ioctl *user) +{ + uint32_t version[3]; + int r = 0; + + if (copy_from_user(version, user->version, sizeof(version))) + return -EFAULT; + + if ((DM_VERSION_MAJOR != version[0]) || + (DM_VERSION_MINOR < version[1])) { + DMWARN("ioctl interface mismatch: " + "kernel(%u.%u.%u), user(%u.%u.%u), cmd(%d)", + DM_VERSION_MAJOR, DM_VERSION_MINOR, + DM_VERSION_PATCHLEVEL, + version[0], version[1], version[2], cmd); + r = -EINVAL; + } + + /* + * Fill in the kernel version. + */ + version[0] = DM_VERSION_MAJOR; + version[1] = DM_VERSION_MINOR; + version[2] = DM_VERSION_PATCHLEVEL; + if (copy_to_user(user->version, version, sizeof(version))) + return -EFAULT; + + return r; +} + +static void free_params(struct dm_ioctl *param) +{ + vfree(param); +} + +static int copy_params(struct dm_ioctl *user, struct dm_ioctl **param) +{ + struct dm_ioctl tmp, *dmi; + + if (copy_from_user(&tmp, user, sizeof(tmp))) + return -EFAULT; + + if (tmp.data_size < sizeof(tmp)) + return -EINVAL; + + dmi = (struct dm_ioctl *) vmalloc(tmp.data_size); + if (!dmi) + return -ENOMEM; + + if (copy_from_user(dmi, user, tmp.data_size)) { + vfree(dmi); + return -EFAULT; + } + + *param = dmi; + return 0; +} + +static int validate_params(uint cmd, struct dm_ioctl *param) +{ + /* Always clear this flag */ + param->flags &= ~DM_BUFFER_FULL_FLAG; + + /* Ignores parameters */ + if (cmd == DM_REMOVE_ALL_CMD || cmd == DM_LIST_DEVICES_CMD) + return 0; + + /* Unless creating, either name or uuid but not both */ + if (cmd != DM_DEV_CREATE_CMD) { + if ((!*param->uuid && !*param->name) || + (*param->uuid && *param->name)) { + DMWARN("one of name or uuid must be supplied, cmd(%u)", + cmd); + return -EINVAL; + } + } + + /* Ensure strings are terminated */ + param->name[DM_NAME_LEN - 1] = '\0'; + param->uuid[DM_UUID_LEN - 1] = '\0'; + + return 0; +} + +static int ctl_ioctl(struct inode *inode, struct file *file, + uint command, ulong u) +{ + int r = 0; + unsigned int cmd; + struct dm_ioctl *param; + struct dm_ioctl *user = (struct dm_ioctl *) u; + ioctl_fn fn = NULL; + size_t param_size; + + /* only root can play with this */ + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + if (_IOC_TYPE(command) != DM_IOCTL) + return -ENOTTY; + + cmd = _IOC_NR(command); + + /* + * Check the interface version passed in. This also + * writes out the kernel's interface version. + */ + r = check_version(cmd, user); + if (r) + return r; + + /* + * Nothing more to do for the version command. + */ + if (cmd == DM_VERSION_CMD) + return 0; + + fn = lookup_ioctl(cmd); + if (!fn) { + DMWARN("dm_ctl_ioctl: unknown command 0x%x", command); + return -ENOTTY; + } + + /* + * Trying to avoid low memory issues when a device is + * suspended. + */ + current->flags |= PF_MEMALLOC; + + /* + * Copy the parameters into kernel space. + */ + r = copy_params(user, ¶m); + if (r) { + current->flags &= ~PF_MEMALLOC; + return r; + } + + /* + * FIXME: eventually we will remove the PF_MEMALLOC flag + * here. However the tools still do nasty things like + * 'load' while a device is suspended. + */ + + r = validate_params(cmd, param); + if (r) + goto out; + + param_size = param->data_size; + param->data_size = sizeof(*param); + r = fn(param, param_size); + + /* + * Copy the results back to userland. + */ + if (!r && copy_to_user(user, param, param->data_size)) + r = -EFAULT; + + out: + free_params(param); + current->flags &= ~PF_MEMALLOC; + return r; +} + +static struct file_operations _ctl_fops = { + .ioctl = ctl_ioctl, + .owner = THIS_MODULE, +}; + +static struct miscdevice _dm_misc = { + .minor = MISC_DYNAMIC_MINOR, + .name = DM_NAME, + .devfs_name = "mapper/control", + .fops = &_ctl_fops +}; + +/* + * Create misc character device and link to DM_DIR/control. + */ +int __init dm_interface_init(void) +{ + int r; + + r = dm_hash_init(); + if (r) + return r; + + r = misc_register(&_dm_misc); + if (r) { + DMERR("misc_register failed for control device"); + dm_hash_exit(); + return r; + } + + DMINFO("%d.%d.%d%s initialised: %s", DM_VERSION_MAJOR, + DM_VERSION_MINOR, DM_VERSION_PATCHLEVEL, DM_VERSION_EXTRA, + DM_DRIVER_EMAIL); + return 0; +} + +void dm_interface_exit(void) +{ + if (misc_deregister(&_dm_misc) < 0) + DMERR("misc_deregister failed for control device"); + + dm_hash_exit(); +} diff -Nru a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c --- a/drivers/md/dm-ioctl.c Sun Jul 27 10:13:43 2003 +++ b/drivers/md/dm-ioctl.c Sun Jul 27 10:13:43 2003 @@ -1,1134 +1,13 @@ /* - * Copyright (C) 2001, 2002 Sistina Software (UK) Limited. + * Copyright (C) 2003 Sistina Software (UK) Limited. * * This file is released under the GPL. */ -#include "dm.h" - -#include -#include -#include #include -#include -#include -#include -#include -#include - -#include - -#define DM_DRIVER_EMAIL "dm@uk.sistina.com" - -/*----------------------------------------------------------------- - * The ioctl interface needs to be able to look up devices by - * name or uuid. - *---------------------------------------------------------------*/ -struct hash_cell { - struct list_head name_list; - struct list_head uuid_list; - - char *name; - char *uuid; - struct mapped_device *md; -}; - -#define NUM_BUCKETS 64 -#define MASK_BUCKETS (NUM_BUCKETS - 1) -static struct list_head _name_buckets[NUM_BUCKETS]; -static struct list_head _uuid_buckets[NUM_BUCKETS]; - -void dm_hash_remove_all(void); - -/* - * Guards access to all three tables. - */ -static DECLARE_RWSEM(_hash_lock); - -static void init_buckets(struct list_head *buckets) -{ - unsigned int i; - - for (i = 0; i < NUM_BUCKETS; i++) - INIT_LIST_HEAD(buckets + i); -} - -int dm_hash_init(void) -{ - init_buckets(_name_buckets); - init_buckets(_uuid_buckets); - devfs_mk_dir(DM_DIR); - return 0; -} - -void dm_hash_exit(void) -{ - dm_hash_remove_all(); - devfs_remove(DM_DIR); -} - -/*----------------------------------------------------------------- - * Hash function: - * We're not really concerned with the str hash function being - * fast since it's only used by the ioctl interface. - *---------------------------------------------------------------*/ -static unsigned int hash_str(const char *str) -{ - const unsigned int hash_mult = 2654435387U; - unsigned int h = 0; - - while (*str) - h = (h + (unsigned int) *str++) * hash_mult; - - return h & MASK_BUCKETS; -} - -/*----------------------------------------------------------------- - * Code for looking up a device by name - *---------------------------------------------------------------*/ -static struct hash_cell *__get_name_cell(const char *str) -{ - struct list_head *tmp; - struct hash_cell *hc; - unsigned int h = hash_str(str); - - list_for_each (tmp, _name_buckets + h) { - hc = list_entry(tmp, struct hash_cell, name_list); - if (!strcmp(hc->name, str)) - return hc; - } - - return NULL; -} - -static struct hash_cell *__get_uuid_cell(const char *str) -{ - struct list_head *tmp; - struct hash_cell *hc; - unsigned int h = hash_str(str); - - list_for_each (tmp, _uuid_buckets + h) { - hc = list_entry(tmp, struct hash_cell, uuid_list); - if (!strcmp(hc->uuid, str)) - return hc; - } - - return NULL; -} - -/*----------------------------------------------------------------- - * Inserting, removing and renaming a device. - *---------------------------------------------------------------*/ -static inline char *kstrdup(const char *str) -{ - char *r = kmalloc(strlen(str) + 1, GFP_KERNEL); - if (r) - strcpy(r, str); - return r; -} - -static struct hash_cell *alloc_cell(const char *name, const char *uuid, - struct mapped_device *md) -{ - struct hash_cell *hc; - - hc = kmalloc(sizeof(*hc), GFP_KERNEL); - if (!hc) - return NULL; - - hc->name = kstrdup(name); - if (!hc->name) { - kfree(hc); - return NULL; - } - - if (!uuid) - hc->uuid = NULL; - - else { - hc->uuid = kstrdup(uuid); - if (!hc->uuid) { - kfree(hc->name); - kfree(hc); - return NULL; - } - } - - INIT_LIST_HEAD(&hc->name_list); - INIT_LIST_HEAD(&hc->uuid_list); - hc->md = md; - return hc; -} - -static void free_cell(struct hash_cell *hc) -{ - if (hc) { - kfree(hc->name); - kfree(hc->uuid); - kfree(hc); - } -} - -/* - * devfs stuff. - */ -static int register_with_devfs(struct hash_cell *hc) -{ - struct gendisk *disk = dm_disk(hc->md); - - devfs_mk_bdev(MKDEV(disk->major, disk->first_minor), - S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP, - DM_DIR "/%s", hc->name); - return 0; -} - -static int unregister_with_devfs(struct hash_cell *hc) -{ - devfs_remove(DM_DIR"/%s", hc->name); - return 0; -} - -/* - * The kdev_t and uuid of a device can never change once it is - * initially inserted. - */ -int dm_hash_insert(const char *name, const char *uuid, struct mapped_device *md) -{ - struct hash_cell *cell; - - /* - * Allocate the new cells. - */ - cell = alloc_cell(name, uuid, md); - if (!cell) - return -ENOMEM; - - /* - * Insert the cell into all three hash tables. - */ - down_write(&_hash_lock); - if (__get_name_cell(name)) - goto bad; - - list_add(&cell->name_list, _name_buckets + hash_str(name)); - - if (uuid) { - if (__get_uuid_cell(uuid)) { - list_del(&cell->name_list); - goto bad; - } - list_add(&cell->uuid_list, _uuid_buckets + hash_str(uuid)); - } - register_with_devfs(cell); - dm_get(md); - up_write(&_hash_lock); - - return 0; - - bad: - up_write(&_hash_lock); - free_cell(cell); - return -EBUSY; -} - -void __hash_remove(struct hash_cell *hc) -{ - /* remove from the dev hash */ - list_del(&hc->uuid_list); - list_del(&hc->name_list); - unregister_with_devfs(hc); - dm_put(hc->md); - free_cell(hc); -} - -void dm_hash_remove_all(void) -{ - int i; - struct hash_cell *hc; - struct list_head *tmp, *n; - - down_write(&_hash_lock); - for (i = 0; i < NUM_BUCKETS; i++) { - list_for_each_safe (tmp, n, _name_buckets + i) { - hc = list_entry(tmp, struct hash_cell, name_list); - __hash_remove(hc); - } - } - up_write(&_hash_lock); -} - -int dm_hash_rename(const char *old, const char *new) -{ - char *new_name, *old_name; - struct hash_cell *hc; - - /* - * duplicate new. - */ - new_name = kstrdup(new); - if (!new_name) - return -ENOMEM; - - down_write(&_hash_lock); - - /* - * Is new free ? - */ - hc = __get_name_cell(new); - if (hc) { - DMWARN("asked to rename to an already existing name %s -> %s", - old, new); - up_write(&_hash_lock); - kfree(new_name); - return -EBUSY; - } - - /* - * Is there such a device as 'old' ? - */ - hc = __get_name_cell(old); - if (!hc) { - DMWARN("asked to rename a non existent device %s -> %s", - old, new); - up_write(&_hash_lock); - kfree(new_name); - return -ENXIO; - } - - /* - * rename and move the name cell. - */ - unregister_with_devfs(hc); - - list_del(&hc->name_list); - old_name = hc->name; - hc->name = new_name; - list_add(&hc->name_list, _name_buckets + hash_str(new_name)); - - /* rename the device node in devfs */ - register_with_devfs(hc); - - up_write(&_hash_lock); - kfree(old_name); - return 0; -} - - -/*----------------------------------------------------------------- - * Implementation of the ioctl commands - *---------------------------------------------------------------*/ - -/* - * All the ioctl commands get dispatched to functions with this - * prototype. - */ -typedef int (*ioctl_fn)(struct dm_ioctl *param, struct dm_ioctl *user); - -/* - * Check a string doesn't overrun the chunk of - * memory we copied from userland. - */ -static int valid_str(char *str, void *begin, void *end) -{ - while (((void *) str >= begin) && ((void *) str < end)) - if (!*str++) - return 0; - - return -EINVAL; -} - -static int next_target(struct dm_target_spec *last, uint32_t next, - void *begin, void *end, - struct dm_target_spec **spec, char **params) -{ - *spec = (struct dm_target_spec *) - ((unsigned char *) last + next); - *params = (char *) (*spec + 1); - - if (*spec < (last + 1) || ((void *) *spec > end)) - return -EINVAL; - - return valid_str(*params, begin, end); -} - -static int populate_table(struct dm_table *table, struct dm_ioctl *args) -{ - int r, first = 1; - unsigned int i = 0; - struct dm_target_spec *spec; - char *params; - void *begin, *end; - - if (!args->target_count) { - DMWARN("populate_table: no targets specified"); - return -EINVAL; - } - - begin = (void *) args; - end = begin + args->data_size; - - for (i = 0; i < args->target_count; i++) { - - if (first) - r = next_target((struct dm_target_spec *) args, - args->data_start, - begin, end, &spec, ¶ms); - else - r = next_target(spec, spec->next, begin, end, - &spec, ¶ms); - - if (r) { - DMWARN("unable to find target"); - return -EINVAL; - } - - r = dm_table_add_target(table, spec->target_type, - (sector_t) spec->sector_start, - (sector_t) spec->length, - params); - if (r) { - DMWARN("internal error adding target to table"); - return -EINVAL; - } - - first = 0; - } - - return dm_table_complete(table); -} - -/* - * Round up the ptr to the next 'align' boundary. Obviously - * 'align' must be a power of 2. - */ -static inline void *align_ptr(void *ptr, unsigned int align) -{ - align--; - return (void *) (((unsigned long) (ptr + align)) & ~align); -} - -/* - * Copies a dm_ioctl and an optional additional payload to - * userland. - */ -static int results_to_user(struct dm_ioctl *user, struct dm_ioctl *param, - void *data, uint32_t len) -{ - int r; - void *ptr = NULL; - - if (data) { - ptr = align_ptr(user + 1, sizeof(unsigned long)); - param->data_start = ptr - (void *) user; - } - - /* - * The version number has already been filled in, so we - * just copy later fields. - */ - r = copy_to_user(&user->data_size, ¶m->data_size, - sizeof(*param) - sizeof(param->version)); - if (r) - return -EFAULT; - - if (data) { - if (param->data_start + len > param->data_size) - return -ENOSPC; - - if (copy_to_user(ptr, data, len)) - r = -EFAULT; - } - - return r; -} - -/* - * Fills in a dm_ioctl structure, ready for sending back to - * userland. - */ -static int __info(struct mapped_device *md, struct dm_ioctl *param) -{ - struct dm_table *table; - struct block_device *bdev; - struct gendisk *disk = dm_disk(md); - - param->flags = DM_EXISTS_FLAG; - if (dm_suspended(md)) - param->flags |= DM_SUSPEND_FLAG; - - bdev = bdget_disk(disk, 0); - if (!bdev) - return -ENXIO; - - param->dev = bdev->bd_dev; - param->open_count = bdev->bd_openers; - bdput(bdev); - - if (disk->policy) - param->flags |= DM_READONLY_FLAG; - - table = dm_get_table(md); - param->target_count = dm_table_get_num_targets(table); - dm_table_put(table); - - return 0; -} - -/* - * Always use UUID for lookups if it's present, otherwise use name. - */ -static inline struct mapped_device *find_device(struct dm_ioctl *param) -{ - struct hash_cell *hc; - struct mapped_device *md = NULL; - - down_read(&_hash_lock); - hc = *param->uuid ? __get_uuid_cell(param->uuid) : - __get_name_cell(param->name); - if (hc) { - md = hc->md; - - /* - * Sneakily write in both the name and the uuid - * while we have the cell. - */ - strlcpy(param->name, hc->name, sizeof(param->name)); - if (hc->uuid) - strlcpy(param->uuid, hc->uuid, sizeof(param->uuid)); - else - param->uuid[0] = '\0'; - - dm_get(md); - } - up_read(&_hash_lock); - - return md; -} - -#define ALIGNMENT sizeof(int) -static void *_align(void *ptr, unsigned int a) -{ - register unsigned long align = --a; - - return (void *) (((unsigned long) ptr + align) & ~align); -} - -/* - * Copies device info back to user space, used by - * the create and info ioctls. - */ -static int info(struct dm_ioctl *param, struct dm_ioctl *user) -{ - struct mapped_device *md; - - param->flags = 0; - - md = find_device(param); - if (!md) - /* - * Device not found - returns cleared exists flag. - */ - goto out; - - __info(md, param); - dm_put(md); - - out: - return results_to_user(user, param, NULL, 0); -} - -static inline int get_mode(struct dm_ioctl *param) -{ - int mode = FMODE_READ | FMODE_WRITE; - - if (param->flags & DM_READONLY_FLAG) - mode = FMODE_READ; - - return mode; -} - -static int check_name(const char *name) -{ - if (name[0] == '/') { - DMWARN("invalid device name"); - return -EINVAL; - } - - return 0; -} - -static int create(struct dm_ioctl *param, struct dm_ioctl *user) -{ - int r; - struct dm_table *t; - struct mapped_device *md; - - r = check_name(param->name); - if (r) - return r; - - r = dm_table_create(&t, get_mode(param)); - if (r) - return r; - - r = populate_table(t, param); - if (r) { - dm_table_put(t); - return r; - } - - if (param->flags & DM_PERSISTENT_DEV_FLAG) - r = dm_create_with_minor(minor(to_kdev_t(param->dev)), t, &md); - else - r = dm_create(t, &md); - - if (r) { - dm_table_put(t); - return r; - } - dm_table_put(t); /* md will have grabbed its own reference */ - - set_disk_ro(dm_disk(md), (param->flags & DM_READONLY_FLAG) ? 1 : 0); - r = dm_hash_insert(param->name, *param->uuid ? param->uuid : NULL, md); - dm_put(md); - - return r ? r : info(param, user); -} - -/* - * Build up the status struct for each target - */ -static int __status(struct mapped_device *md, struct dm_ioctl *param, - char *outbuf, size_t *len) -{ - unsigned int i, num_targets; - struct dm_target_spec *spec; - char *outptr; - status_type_t type; - struct dm_table *table = dm_get_table(md); - - if (param->flags & DM_STATUS_TABLE_FLAG) - type = STATUSTYPE_TABLE; - else - type = STATUSTYPE_INFO; - - outptr = outbuf; - - /* Get all the target info */ - num_targets = dm_table_get_num_targets(table); - for (i = 0; i < num_targets; i++) { - struct dm_target *ti = dm_table_get_target(table, i); - - if (outptr - outbuf + - sizeof(struct dm_target_spec) > param->data_size) { - dm_table_put(table); - return -ENOMEM; - } - - spec = (struct dm_target_spec *) outptr; - - spec->status = 0; - spec->sector_start = ti->begin; - spec->length = ti->len; - strlcpy(spec->target_type, ti->type->name, - sizeof(spec->target_type)); - - outptr += sizeof(struct dm_target_spec); - - /* Get the status/table string from the target driver */ - if (ti->type->status) - ti->type->status(ti, type, outptr, - outbuf + param->data_size - outptr); - else - outptr[0] = '\0'; - - outptr += strlen(outptr) + 1; - _align(outptr, ALIGNMENT); - spec->next = outptr - outbuf; - } - - param->target_count = num_targets; - *len = outptr - outbuf; - dm_table_put(table); - - return 0; -} - -/* - * Return the status of a device as a text string for each - * target. - */ -static int get_status(struct dm_ioctl *param, struct dm_ioctl *user) -{ - struct mapped_device *md; - size_t len = 0; - int ret; - char *outbuf = NULL; - - md = find_device(param); - if (!md) - /* - * Device not found - returns cleared exists flag. - */ - goto out; - - /* We haven't a clue how long the resultant data will be so - just allocate as much as userland has allowed us and make sure - we don't overun it */ - outbuf = kmalloc(param->data_size, GFP_KERNEL); - if (!outbuf) - goto out; - /* - * Get the status of all targets - */ - __status(md, param, outbuf, &len); - - /* - * Setup the basic dm_ioctl structure. - */ - __info(md, param); - - out: - if (md) - dm_put(md); - - ret = results_to_user(user, param, outbuf, len); - - if (outbuf) - kfree(outbuf); - - return ret; -} - -/* - * Wait for a device to report an event - */ -static int wait_device_event(struct dm_ioctl *param, struct dm_ioctl *user) -{ - struct mapped_device *md; - struct dm_table *table; - DECLARE_WAITQUEUE(wq, current); - - md = find_device(param); - if (!md) - /* - * Device not found - returns cleared exists flag. - */ - goto out; - - /* - * Setup the basic dm_ioctl structure. - */ - __info(md, param); - - /* - * Wait for a notification event - */ - set_current_state(TASK_INTERRUPTIBLE); - table = dm_get_table(md); - dm_table_add_wait_queue(table, &wq); - dm_table_put(table); - dm_put(md); - - schedule(); - - out: - return results_to_user(user, param, NULL, 0); -} - -/* - * Retrieves a list of devices used by a particular dm device. - */ -static int dep(struct dm_ioctl *param, struct dm_ioctl *user) -{ - int r; - unsigned int count; - struct mapped_device *md; - struct list_head *tmp; - size_t len = 0; - struct dm_target_deps *deps = NULL; - struct dm_table *table; - - md = find_device(param); - if (!md) - goto out; - table = dm_get_table(md); - - /* - * Setup the basic dm_ioctl structure. - */ - __info(md, param); - - /* - * Count the devices. - */ - count = 0; - list_for_each(tmp, dm_table_get_devices(table)) - count++; - - /* - * Allocate a kernel space version of the dm_target_status - * struct. - */ - if (array_too_big(sizeof(*deps), sizeof(*deps->dev), count)) { - dm_table_put(table); - dm_put(md); - return -ENOMEM; - } - - len = sizeof(*deps) + (sizeof(*deps->dev) * count); - deps = kmalloc(len, GFP_KERNEL); - if (!deps) { - dm_table_put(table); - dm_put(md); - return -ENOMEM; - } - - /* - * Fill in the devices. - */ - deps->count = count; - count = 0; - list_for_each(tmp, dm_table_get_devices(table)) { - struct dm_dev *dd = list_entry(tmp, struct dm_dev, list); - deps->dev[count++] = dd->bdev->bd_dev; - } - dm_table_put(table); - dm_put(md); - - out: - r = results_to_user(user, param, deps, len); - - kfree(deps); - return r; -} - -static int remove(struct dm_ioctl *param, struct dm_ioctl *user) -{ - struct hash_cell *hc; - - down_write(&_hash_lock); - hc = *param->uuid ? __get_uuid_cell(param->uuid) : - __get_name_cell(param->name); - if (!hc) { - DMWARN("device doesn't appear to be in the dev hash table."); - up_write(&_hash_lock); - return -EINVAL; - } - - /* - * You may ask the interface to drop its reference to an - * in use device. This is no different to unlinking a - * file that someone still has open. The device will not - * actually be destroyed until the last opener closes it. - * The name and uuid of the device (both are interface - * properties) will be available for reuse immediately. - * - * You don't want to drop a _suspended_ device from the - * interface, since that will leave you with no way of - * resuming it. - */ - if (dm_suspended(hc->md)) { - DMWARN("refusing to remove a suspended device."); - up_write(&_hash_lock); - return -EPERM; - } - - __hash_remove(hc); - up_write(&_hash_lock); - return 0; -} - -static int remove_all(struct dm_ioctl *param, struct dm_ioctl *user) -{ - dm_hash_remove_all(); - return 0; -} - -static int suspend(struct dm_ioctl *param, struct dm_ioctl *user) -{ - int r; - struct mapped_device *md; - - md = find_device(param); - if (!md) - return -ENXIO; - - if (param->flags & DM_SUSPEND_FLAG) - r = dm_suspend(md); - else - r = dm_resume(md); - - dm_put(md); - return r; -} - -static int reload(struct dm_ioctl *param, struct dm_ioctl *user) -{ - int r; - struct mapped_device *md; - struct dm_table *t; - - r = dm_table_create(&t, get_mode(param)); - if (r) - return r; - - r = populate_table(t, param); - if (r) { - dm_table_put(t); - return r; - } - - md = find_device(param); - if (!md) { - dm_table_put(t); - return -ENXIO; - } - - r = dm_swap_table(md, t); - if (r) { - dm_put(md); - dm_table_put(t); - return r; - } - dm_table_put(t); /* md will have taken its own reference */ - - set_disk_ro(dm_disk(md), (param->flags & DM_READONLY_FLAG) ? 1 : 0); - dm_put(md); - - r = info(param, user); - return r; -} - -static int rename(struct dm_ioctl *param, struct dm_ioctl *user) -{ - int r; - char *new_name = (char *) param + param->data_start; - - if (valid_str(new_name, (void *) param, - (void *) param + param->data_size)) { - DMWARN("Invalid new logical volume name supplied."); - return -EINVAL; - } - - r = check_name(new_name); - if (r) - return r; - - return dm_hash_rename(param->name, new_name); -} - - -/*----------------------------------------------------------------- - * Implementation of open/close/ioctl on the special char - * device. - *---------------------------------------------------------------*/ -static ioctl_fn lookup_ioctl(unsigned int cmd) -{ - static struct { - int cmd; - ioctl_fn fn; - } _ioctls[] = { - {DM_VERSION_CMD, NULL}, /* version is dealt with elsewhere */ - {DM_REMOVE_ALL_CMD, remove_all}, - {DM_DEV_CREATE_CMD, create}, - {DM_DEV_REMOVE_CMD, remove}, - {DM_DEV_RELOAD_CMD, reload}, - {DM_DEV_RENAME_CMD, rename}, - {DM_DEV_SUSPEND_CMD, suspend}, - {DM_DEV_DEPS_CMD, dep}, - {DM_DEV_STATUS_CMD, info}, - {DM_TARGET_STATUS_CMD, get_status}, - {DM_TARGET_WAIT_CMD, wait_device_event}, - }; - - return (cmd >= ARRAY_SIZE(_ioctls)) ? NULL : _ioctls[cmd].fn; -} - -/* - * As well as checking the version compatibility this always - * copies the kernel interface version out. - */ -static int check_version(unsigned int cmd, struct dm_ioctl *user) -{ - uint32_t version[3]; - int r = 0; - - if (copy_from_user(version, user->version, sizeof(version))) - return -EFAULT; - - if ((DM_VERSION_MAJOR != version[0]) || - (DM_VERSION_MINOR < version[1])) { - DMWARN("ioctl interface mismatch: " - "kernel(%u.%u.%u), user(%u.%u.%u), cmd(%d)", - DM_VERSION_MAJOR, DM_VERSION_MINOR, - DM_VERSION_PATCHLEVEL, - version[0], version[1], version[2], cmd); - r = -EINVAL; - } - - /* - * Fill in the kernel version. - */ - version[0] = DM_VERSION_MAJOR; - version[1] = DM_VERSION_MINOR; - version[2] = DM_VERSION_PATCHLEVEL; - if (copy_to_user(user->version, version, sizeof(version))) - return -EFAULT; - - return r; -} - -static void free_params(struct dm_ioctl *param) -{ - vfree(param); -} - -static int copy_params(struct dm_ioctl *user, struct dm_ioctl **param) -{ - struct dm_ioctl tmp, *dmi; - - if (copy_from_user(&tmp, user, sizeof(tmp))) - return -EFAULT; - - if (tmp.data_size < sizeof(tmp)) - return -EINVAL; - - dmi = (struct dm_ioctl *) vmalloc(tmp.data_size); - if (!dmi) - return -ENOMEM; - - if (copy_from_user(dmi, user, tmp.data_size)) { - vfree(dmi); - return -EFAULT; - } - - *param = dmi; - return 0; -} - -static int validate_params(uint cmd, struct dm_ioctl *param) -{ - /* Ignores parameters */ - if (cmd == DM_REMOVE_ALL_CMD) - return 0; - - /* Unless creating, either name of uuid but not both */ - if (cmd != DM_DEV_CREATE_CMD) { - if ((!*param->uuid && !*param->name) || - (*param->uuid && *param->name)) { - DMWARN("one of name or uuid must be supplied"); - return -EINVAL; - } - } - - /* Ensure strings are terminated */ - param->name[DM_NAME_LEN - 1] = '\0'; - param->uuid[DM_UUID_LEN - 1] = '\0'; - - return 0; -} - -static int ctl_ioctl(struct inode *inode, struct file *file, - uint command, ulong u) -{ - int r = 0; - unsigned int cmd; - struct dm_ioctl *param; - struct dm_ioctl *user = (struct dm_ioctl *) u; - ioctl_fn fn = NULL; - - /* only root can play with this */ - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - - if (_IOC_TYPE(command) != DM_IOCTL) - return -ENOTTY; - - cmd = _IOC_NR(command); - - /* - * Check the interface version passed in. This also - * writes out the kernels interface version. - */ - r = check_version(cmd, user); - if (r) - return r; - - /* - * Nothing more to do for the version command. - */ - if (cmd == DM_VERSION_CMD) - return 0; - - fn = lookup_ioctl(cmd); - if (!fn) { - DMWARN("dm_ctl_ioctl: unknown command 0x%x", command); - return -ENOTTY; - } - - /* - * Copy the parameters into kernel space. - */ - r = copy_params(user, ¶m); - if (r) - return r; - - r = validate_params(cmd, param); - if (r) { - free_params(param); - return r; - } - - r = fn(param, user); - free_params(param); - return r; -} - -static struct file_operations _ctl_fops = { - .ioctl = ctl_ioctl, - .owner = THIS_MODULE, -}; - -static struct miscdevice _dm_misc = { - .minor = MISC_DYNAMIC_MINOR, - .name = DM_NAME, - .devfs_name = "mapper/control", - .fops = &_ctl_fops -}; - -/* - * Create misc character device and link to DM_DIR/control. - */ -int __init dm_interface_init(void) -{ - int r; - - r = dm_hash_init(); - if (r) - return r; - - r = misc_register(&_dm_misc); - if (r) { - DMERR("misc_register failed for control device"); - dm_hash_exit(); - return r; - } - - DMINFO("%d.%d.%d%s initialised: %s", DM_VERSION_MAJOR, - DM_VERSION_MINOR, DM_VERSION_PATCHLEVEL, DM_VERSION_EXTRA, - DM_DRIVER_EMAIL); - return 0; - - if (misc_deregister(&_dm_misc) < 0) - DMERR("misc_deregister failed for control device"); - dm_hash_exit(); - return r; -} -void dm_interface_exit(void) -{ - if (misc_deregister(&_dm_misc) < 0) - DMERR("misc_deregister failed for control device"); - dm_hash_exit(); -} +#ifdef CONFIG_DM_IOCTL_V4 +#include "dm-ioctl-v4.c" +#else +#include "dm-ioctl-v1.c" +#endif diff -Nru a/drivers/md/dm-table.c b/drivers/md/dm-table.c --- a/drivers/md/dm-table.c Sun Jul 27 10:13:52 2003 +++ b/drivers/md/dm-table.c Sun Jul 27 10:13:52 2003 @@ -48,11 +48,9 @@ */ struct io_restrictions limits; - /* - * A waitqueue for processes waiting for something - * interesting to happen to this table. - */ - wait_queue_head_t eventq; + /* events get handed up using this callback */ + void (*event_fn)(void *); + void *event_context; }; /* @@ -222,7 +220,6 @@ return -ENOMEM; } - init_waitqueue_head(&t->eventq); t->mode = mode; *result = t; return 0; @@ -243,9 +240,6 @@ { unsigned int i; - /* destroying the table counts as an event */ - dm_table_event(t); - /* free the indexes (see dm_table_complete) */ if (t->depth >= 2) vfree(t->index[t->depth - 2]); @@ -694,9 +688,22 @@ return r; } +static spinlock_t _event_lock = SPIN_LOCK_UNLOCKED; +void dm_table_event_callback(struct dm_table *t, + void (*fn)(void *), void *context) +{ + spin_lock_irq(&_event_lock); + t->event_fn = fn; + t->event_context = context; + spin_unlock_irq(&_event_lock); +} + void dm_table_event(struct dm_table *t) { - wake_up_interruptible(&t->eventq); + spin_lock(&_event_lock); + if (t->event_fn) + t->event_fn(t->event_context); + spin_unlock(&_event_lock); } sector_t dm_table_get_size(struct dm_table *t) @@ -759,11 +766,6 @@ int dm_table_get_mode(struct dm_table *t) { return t->mode; -} - -void dm_table_add_wait_queue(struct dm_table *t, wait_queue_t *wq) -{ - add_wait_queue(&t->eventq, wq); } void dm_table_suspend_targets(struct dm_table *t) diff -Nru a/drivers/md/dm.c b/drivers/md/dm.c --- a/drivers/md/dm.c Sun Jul 27 10:13:50 2003 +++ b/drivers/md/dm.c Sun Jul 27 10:13:50 2003 @@ -8,7 +8,6 @@ #include #include -#include #include #include #include @@ -63,6 +62,12 @@ * io objects are allocated from here. */ mempool_t *io_pool; + + /* + * Event handling. + */ + uint32_t event_nr; + wait_queue_head_t eventq; }; #define MIN_IOS 256 @@ -510,6 +515,11 @@ down_read(&md->lock); } + if (!md->map) { + bio_io_error(bio, bio->bi_size); + return 0; + } + __split_bio(md, bio); up_read(&md->lock); return 0; @@ -619,6 +629,8 @@ atomic_set(&md->pending, 0); init_waitqueue_head(&md->wait); + init_waitqueue_head(&md->eventq); + return md; } @@ -634,6 +646,16 @@ /* * Bind a table to the device. */ +static void event_callback(void *context) +{ + struct mapped_device *md = (struct mapped_device *) context; + + down_write(&md->lock); + md->event_nr++; + wake_up_interruptible(&md->eventq); + up_write(&md->lock); +} + static int __bind(struct mapped_device *md, struct dm_table *t) { request_queue_t *q = &md->queue; @@ -645,6 +667,8 @@ if (size == 0) return 0; + dm_table_event_callback(md->map, event_callback, md); + dm_table_get(t); dm_table_set_restrictions(t, q); return 0; @@ -652,6 +676,10 @@ static void __unbind(struct mapped_device *md) { + if (!md->map) + return; + + dm_table_event_callback(md->map, NULL, NULL); dm_table_put(md->map); md->map = NULL; set_capacity(md->disk, 0); @@ -661,35 +689,26 @@ * Constructor for a new device. */ static int create_aux(unsigned int minor, int persistent, - struct dm_table *table, struct mapped_device **result) + struct mapped_device **result) { - int r; struct mapped_device *md; md = alloc_dev(minor, persistent); if (!md) return -ENXIO; - r = __bind(md, table); - if (r) { - free_dev(md); - return r; - } - dm_table_resume_targets(md->map); - *result = md; return 0; } -int dm_create(struct dm_table *table, struct mapped_device **result) +int dm_create(struct mapped_device **result) { - return create_aux(0, 0, table, result); + return create_aux(0, 0, result); } -int dm_create_with_minor(unsigned int minor, - struct dm_table *table, struct mapped_device **result) +int dm_create_with_minor(unsigned int minor, struct mapped_device **result) { - return create_aux(minor, 1, table, result); + return create_aux(minor, 1, result); } void dm_get(struct mapped_device *md) @@ -700,7 +719,7 @@ void dm_put(struct mapped_device *md) { if (atomic_dec_and_test(&md->holders)) { - if (!test_bit(DMF_SUSPENDED, &md->flags)) + if (!test_bit(DMF_SUSPENDED, &md->flags) && md->map) dm_table_suspend_targets(md->map); __unbind(md); free_dev(md); @@ -790,7 +809,8 @@ down_write(&md->lock); remove_wait_queue(&md->wait, &wait); set_bit(DMF_SUSPENDED, &md->flags); - dm_table_suspend_targets(md->map); + if (md->map) + dm_table_suspend_targets(md->map); up_write(&md->lock); return 0; @@ -801,7 +821,8 @@ struct deferred_io *def; down_write(&md->lock); - if (!test_bit(DMF_SUSPENDED, &md->flags) || + if (!md->map || + !test_bit(DMF_SUSPENDED, &md->flags) || !dm_table_get_size(md->map)) { up_write(&md->lock); return -EINVAL; @@ -820,6 +841,42 @@ return 0; } +/*----------------------------------------------------------------- + * Event notification. + *---------------------------------------------------------------*/ +uint32_t dm_get_event_nr(struct mapped_device *md) +{ + uint32_t r; + + down_read(&md->lock); + r = md->event_nr; + up_read(&md->lock); + + return r; +} + +int dm_add_wait_queue(struct mapped_device *md, wait_queue_t *wq, + uint32_t event_nr) +{ + down_write(&md->lock); + if (event_nr != md->event_nr) { + up_write(&md->lock); + return 1; + } + + add_wait_queue(&md->eventq, wq); + up_write(&md->lock); + + return 0; +} + +void dm_remove_wait_queue(struct mapped_device *md, wait_queue_t *wq) +{ + down_write(&md->lock); + remove_wait_queue(&md->eventq, wq); + up_write(&md->lock); +} + /* * The gendisk is only valid as long as you have a reference * count on 'md'. @@ -835,7 +892,8 @@ down_read(&md->lock); t = md->map; - dm_table_get(t); + if (t) + dm_table_get(t); up_read(&md->lock); return t; diff -Nru a/drivers/md/dm.h b/drivers/md/dm.h --- a/drivers/md/dm.h Sun Jul 27 10:13:45 2003 +++ b/drivers/md/dm.h Sun Jul 27 10:13:45 2003 @@ -51,9 +51,8 @@ * Functions for manipulating a struct mapped_device. * Drop the reference with dm_put when you finish with the object. *---------------------------------------------------------------*/ -int dm_create(struct dm_table *table, struct mapped_device **md); -int dm_create_with_minor(unsigned int minor, struct dm_table *table, - struct mapped_device **md); +int dm_create(struct mapped_device **md); +int dm_create_with_minor(unsigned int minor, struct mapped_device **md); /* * Reference counting for md. @@ -79,6 +78,14 @@ struct dm_table *dm_get_table(struct mapped_device *md); /* + * Event functions. + */ +uint32_t dm_get_event_nr(struct mapped_device *md); +int dm_add_wait_queue(struct mapped_device *md, wait_queue_t *wq, + uint32_t event_nr); +void dm_remove_wait_queue(struct mapped_device *md, wait_queue_t *wq); + +/* * Info functions. */ struct gendisk *dm_disk(struct mapped_device *md); @@ -96,6 +103,8 @@ int dm_table_add_target(struct dm_table *t, const char *type, sector_t start, sector_t len, char *params); int dm_table_complete(struct dm_table *t); +void dm_table_event_callback(struct dm_table *t, + void (*fn)(void *), void *context); void dm_table_event(struct dm_table *t); sector_t dm_table_get_size(struct dm_table *t); struct dm_target *dm_table_get_target(struct dm_table *t, unsigned int index); @@ -104,7 +113,6 @@ unsigned int dm_table_get_num_targets(struct dm_table *t); struct list_head *dm_table_get_devices(struct dm_table *t); int dm_table_get_mode(struct dm_table *t); -void dm_table_add_wait_queue(struct dm_table *t, wait_queue_t *wq); void dm_table_suspend_targets(struct dm_table *t); void dm_table_resume_targets(struct dm_table *t); diff -Nru a/drivers/md/md.c b/drivers/md/md.c --- a/drivers/md/md.c Sun Jul 27 10:13:43 2003 +++ b/drivers/md/md.c Sun Jul 27 10:13:43 2003 @@ -52,8 +52,6 @@ #define MD_DRIVER #define DEVICE_NR(device) (minor(device)) -#include - #define DEBUG 0 #define dprintk(x...) ((void)(DEBUG && printk(x))) diff -Nru a/drivers/md/multipath.c b/drivers/md/multipath.c --- a/drivers/md/multipath.c Sun Jul 27 10:13:45 2003 +++ b/drivers/md/multipath.c Sun Jul 27 10:13:45 2003 @@ -179,6 +179,7 @@ mp_bh->bio = *bio; mp_bh->bio.bi_bdev = multipath->rdev->bdev; + mp_bh->bio.bi_flags |= (1 << BIO_RW_FAILFAST); mp_bh->bio.bi_end_io = multipath_end_request; mp_bh->bio.bi_private = mp_bh; generic_make_request(&mp_bh->bio); diff -Nru a/drivers/media/common/Makefile b/drivers/media/common/Makefile --- a/drivers/media/common/Makefile Sun Jul 27 10:13:50 2003 +++ b/drivers/media/common/Makefile Sun Jul 27 10:13:50 2003 @@ -1,5 +1,5 @@ saa7146-objs := saa7146_i2c.o saa7146_core.o -saa7146_vv-objs := saa7146_fops.o saa7146_video.o saa7146_hlp.o saa7146_vbi.o +saa7146_vv-objs := saa7146_vv_ksyms.o saa7146_fops.o saa7146_video.o saa7146_hlp.o saa7146_vbi.o obj-$(CONFIG_VIDEO_SAA7146) += saa7146.o saa7146_vv.o diff -Nru a/drivers/media/common/saa7146_core.c b/drivers/media/common/saa7146_core.c --- a/drivers/media/common/saa7146_core.c Sun Jul 27 10:13:49 2003 +++ b/drivers/media/common/saa7146_core.c Sun Jul 27 10:13:49 2003 @@ -373,6 +373,9 @@ dev->module = THIS_MODULE; init_waitqueue_head(&dev->i2c_wq); + /* set some default values */ + saa7146_write(dev, BCS_CTRL, 0x80400040); + if( 0 != ext->probe) { if( 0 != ext->probe(dev) ) { DEB_D(("ext->probe() failed for %p. skipping device.\n",dev)); @@ -390,9 +393,6 @@ INIT_LIST_HEAD(&dev->item); list_add_tail(&dev->item,&saa7146_devices); saa7146_num++; - - /* set some default values */ - saa7146_write(dev, BCS_CTRL, 0x80400040); err = 0; goto out; diff -Nru a/drivers/media/common/saa7146_fops.c b/drivers/media/common/saa7146_fops.c --- a/drivers/media/common/saa7146_fops.c Sun Jul 27 10:13:45 2003 +++ b/drivers/media/common/saa7146_fops.c Sun Jul 27 10:13:45 2003 @@ -106,10 +106,21 @@ // fixme: fix this for vflip != 0 saa7146_write(dev, PROT_ADDR1, 0); + saa7146_write(dev, MC2, (MASK_02|MASK_18)); + /* write the address of the rps-program */ saa7146_write(dev, RPS_ADDR0, dev->d_rps0.dma_handle); /* turn on rps */ saa7146_write(dev, MC1, (MASK_12 | MASK_28)); + +/* + printk("vdma%d.base_even: 0x%08x\n", 1,saa7146_read(dev,BASE_EVEN1)); + printk("vdma%d.base_odd: 0x%08x\n", 1,saa7146_read(dev,BASE_ODD1)); + printk("vdma%d.prot_addr: 0x%08x\n", 1,saa7146_read(dev,PROT_ADDR1)); + printk("vdma%d.base_page: 0x%08x\n", 1,saa7146_read(dev,BASE_PAGE1)); + printk("vdma%d.pitch: 0x%08x\n", 1,saa7146_read(dev,PITCH1)); + printk("vdma%d.num_line_byte: 0x%08x\n", 1,saa7146_read(dev,NUM_LINE_BYTE1)); +*/ } del_timer(&q->timeout); } @@ -374,7 +385,7 @@ .minor = -1, }; -int saa7146_vv_init(struct saa7146_dev* dev) +int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv) { struct saa7146_vv *vv = kmalloc (sizeof(struct saa7146_vv),GFP_KERNEL); if( NULL == vv ) { @@ -385,6 +396,11 @@ DEB_EE(("dev:%p\n",dev)); + /* save per-device extension data (one extension can + handle different devices that might need different + configuration data) */ + dev->ext_vv_data = ext_vv; + vv->video_minor = -1; vv->vbi_minor = -1; @@ -474,13 +490,6 @@ module_init(saa7146_vv_init_module); module_exit(saa7146_vv_cleanup_module); - -EXPORT_SYMBOL_GPL(saa7146_set_hps_source_and_sync); -EXPORT_SYMBOL_GPL(saa7146_register_device); -EXPORT_SYMBOL_GPL(saa7146_unregister_device); - -EXPORT_SYMBOL_GPL(saa7146_vv_init); -EXPORT_SYMBOL_GPL(saa7146_vv_release); MODULE_AUTHOR("Michael Hunold "); MODULE_DESCRIPTION("video4linux driver for saa7146-based hardware"); diff -Nru a/drivers/media/common/saa7146_hlp.c b/drivers/media/common/saa7146_hlp.c --- a/drivers/media/common/saa7146_hlp.c Sun Jul 27 10:13:47 2003 +++ b/drivers/media/common/saa7146_hlp.c Sun Jul 27 10:13:47 2003 @@ -242,7 +242,9 @@ if( 2*out_y >= in_y) { lpi = 1; } - } else if (field == V4L2_FIELD_TOP || field == V4L2_FIELD_BOTTOM) { + } else if (field == V4L2_FIELD_TOP + || field == V4L2_FIELD_ALTERNATE + || field == V4L2_FIELD_BOTTOM) { if( 4*out_y >= in_y ) { lpi = 1; } @@ -468,9 +470,7 @@ *clip_format &= 0xfffffff7; if (V4L2_FIELD_HAS_BOTH(field)) { *clip_format |= 0x00000008; - } else if (field == V4L2_FIELD_TOP) { - *clip_format |= 0x00000000; - } else if (field == V4L2_FIELD_BOTTOM) { + } else { *clip_format |= 0x00000000; } } @@ -593,6 +593,10 @@ } if (V4L2_FIELD_HAS_BOTH(field)) { + } else if (field == V4L2_FIELD_ALTERNATE) { + /* fixme */ + vdma1.base_odd = vdma1.prot_addr; + vdma1.pitch /= 2; } else if (field == V4L2_FIELD_TOP) { vdma1.base_odd = vdma1.prot_addr; vdma1.pitch /= 2; @@ -706,7 +710,7 @@ /* calculate starting address */ where = (which-1)*0x18; - if( 0 != (dev->ext->ext_vv_data->flags & SAA7146_EXT_SWAP_ODD_EVEN)) { + if( 0 != (dev->ext_vv_data->flags & SAA7146_EXT_SWAP_ODD_EVEN)) { saa7146_write(dev, where, vdma->base_even); saa7146_write(dev, where+0x04, vdma->base_odd); } else { @@ -760,6 +764,16 @@ } if (V4L2_FIELD_HAS_BOTH(field)) { + } else if (field == V4L2_FIELD_ALTERNATE) { + /* fixme */ + if ( vv->last_field == V4L2_FIELD_TOP ) { + vdma1.base_odd = vdma1.prot_addr; + vdma1.pitch /= 2; + } else if ( vv->last_field == V4L2_FIELD_BOTTOM ) { + vdma1.base_odd = vdma1.base_even; + vdma1.base_even = vdma1.prot_addr; + vdma1.pitch /= 2; + } } else if (field == V4L2_FIELD_TOP) { vdma1.base_odd = vdma1.prot_addr; vdma1.pitch /= 2; @@ -896,6 +910,14 @@ } if (V4L2_FIELD_HAS_BOTH(field)) { + } else if (field == V4L2_FIELD_ALTERNATE) { + /* fixme */ + vdma1.base_odd = vdma1.prot_addr; + vdma1.pitch /= 2; + vdma2.base_odd = vdma2.prot_addr; + vdma2.pitch /= 2; + vdma3.base_odd = vdma3.prot_addr; + vdma3.pitch /= 2; } else if (field == V4L2_FIELD_TOP) { vdma1.base_odd = vdma1.prot_addr; vdma1.pitch /= 2; @@ -935,21 +957,22 @@ static void program_capture_engine(struct saa7146_dev *dev, int planar) { struct saa7146_vv *vv = dev->vv_data; + int count = 0; unsigned long e_wait = vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? CMD_E_FID_A : CMD_E_FID_B; unsigned long o_wait = vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? CMD_O_FID_A : CMD_O_FID_B; - if( 0 != (dev->ext->ext_vv_data->flags & SAA7146_EXT_SWAP_ODD_EVEN)) { + if( 0 != (dev->ext_vv_data->flags & SAA7146_EXT_SWAP_ODD_EVEN)) { unsigned long tmp = e_wait; e_wait = o_wait; o_wait = tmp; } - /* wait for o_fid_a/b / e_fid_a/b toggle only if bit 0 is not set*/ - WRITE_RPS0(CMD_PAUSE | CMD_OAN | CMD_SIG0 | e_wait); + /* wait for o_fid_a/b / e_fid_a/b toggle only if rps register 0 is not set*/ WRITE_RPS0(CMD_PAUSE | CMD_OAN | CMD_SIG0 | o_wait); + WRITE_RPS0(CMD_PAUSE | CMD_OAN | CMD_SIG0 | e_wait); - /* set bit 0 */ + /* set rps register 0 */ WRITE_RPS0(CMD_WR_REG | (1 << 8) | (MC2/4)); WRITE_RPS0(MASK_27 | MASK_11); @@ -970,8 +993,14 @@ } /* wait for o_fid_a/b / e_fid_a/b toggle */ + if ( vv->last_field == V4L2_FIELD_INTERLACED ) { + WRITE_RPS0(CMD_PAUSE | o_wait); WRITE_RPS0(CMD_PAUSE | e_wait); + } else if ( vv->last_field == V4L2_FIELD_TOP ) { WRITE_RPS0(CMD_PAUSE | o_wait); + } else if ( vv->last_field == V4L2_FIELD_BOTTOM ) { + WRITE_RPS0(CMD_PAUSE | e_wait); + } /* turn off video-dma1 */ WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4)); @@ -999,12 +1028,38 @@ void saa7146_set_capture(struct saa7146_dev *dev, struct saa7146_buf *buf, struct saa7146_buf *next) { struct saa7146_format *sfmt = format_by_fourcc(dev,buf->fmt->pixelformat); + struct saa7146_vv *vv = dev->vv_data; + u32 vdma1_prot_addr; DEB_CAP(("buf:%p, next:%p\n",buf,next)); +/* + printk("vdma%d.base_even: 0x%08x\n", 1,saa7146_read(dev,BASE_EVEN1)); + printk("vdma%d.base_odd: 0x%08x\n", 1,saa7146_read(dev,BASE_ODD1)); + printk("vdma%d.prot_addr: 0x%08x\n", 1,saa7146_read(dev,PROT_ADDR1)); + printk("vdma%d.base_page: 0x%08x\n", 1,saa7146_read(dev,BASE_PAGE1)); + printk("vdma%d.pitch: 0x%08x\n", 1,saa7146_read(dev,PITCH1)); + printk("vdma%d.num_line_byte: 0x%08x\n", 1,saa7146_read(dev,NUM_LINE_BYTE1)); + printk("vdma%d => vptr : 0x%08x\n", 1,saa7146_read(dev,PCI_VDP1)); +*/ + + vdma1_prot_addr = saa7146_read(dev, PROT_ADDR1); + if( 0 == vdma1_prot_addr ) { + /* clear out beginning of streaming bit (rps register 0)*/ + DEB_CAP(("forcing sync to new frame\n")); + saa7146_write(dev, MC2, MASK_27 ); + } + saa7146_set_window(dev, buf->fmt->width, buf->fmt->height, buf->fmt->field); saa7146_set_output_format(dev, sfmt->trans); saa7146_disable_clipping(dev); + + if ( vv->last_field == V4L2_FIELD_INTERLACED ) { + } else if ( vv->last_field == V4L2_FIELD_TOP ) { + vv->last_field = V4L2_FIELD_BOTTOM; + } else if ( vv->last_field == V4L2_FIELD_BOTTOM ) { + vv->last_field = V4L2_FIELD_TOP; + } if( 0 != IS_PLANAR(sfmt->trans)) { calculate_video_dma_grab_planar(dev, buf); diff -Nru a/drivers/media/common/saa7146_i2c.c b/drivers/media/common/saa7146_i2c.c --- a/drivers/media/common/saa7146_i2c.c Sun Jul 27 10:13:52 2003 +++ b/drivers/media/common/saa7146_i2c.c Sun Jul 27 10:13:52 2003 @@ -181,9 +181,10 @@ /* this functions writes out the data-byte 'dword' to the i2c-device. it returns 0 if ok, -1 if the transfer failed, -2 if the transfer failed badly (e.g. address error) */ -static int saa7146_i2c_writeout(struct saa7146_dev *dev, u32* dword) +static int saa7146_i2c_writeout(struct saa7146_dev *dev, u32* dword, int short_delay) { u32 status = 0, mc2 = 0; + int trial = 0; int timeout; /* write out i2c-command */ @@ -224,10 +225,13 @@ /* wait until we get a transfer done or error */ timeout = jiffies + HZ/100 + 1; /* 10ms */ while(1) { + /** + * first read usually delivers bogus results... + */ + saa7146_i2c_status(dev); status = saa7146_i2c_status(dev); - if( (0x3 == (status & 0x3)) || (0 == (status & 0x1)) ) { + if ((status & 0x3) != 1) break; - } if (jiffies > timeout) { /* this is normal when probing the bus * (no answer from nonexisistant device...) @@ -235,6 +239,9 @@ DEB_I2C(("saa7146_i2c_writeout: timed out waiting for end of xfer\n")); return -EIO; } + if ((++trial < 20) && short_delay) + udelay(10); + else my_wait(dev,1); } } @@ -277,6 +284,7 @@ u32* buffer = dev->d_i2c.cpu_addr; int err = 0; int address_err = 0; + int short_delay = 0; if (down_interruptible (&dev->i2c_lock)) return -ERESTARTSYS; @@ -292,6 +300,8 @@ goto out; } + if (count > 3) short_delay = 1; + do { /* reset the i2c-device if necessary */ err = saa7146_i2c_reset(dev); @@ -302,7 +312,7 @@ /* write out the u32s one after another */ for(i = 0; i < count; i++) { - err = saa7146_i2c_writeout(dev, &buffer[i] ); + err = saa7146_i2c_writeout(dev, &buffer[i], short_delay); if ( 0 != err) { /* this one is unsatisfying: some i2c slaves on some dvb cards don't acknowledge correctly, so the saa7146 @@ -357,7 +367,7 @@ if( 0 == dev->revision ) { u32 zero = 0; saa7146_i2c_reset(dev); - if( 0 != saa7146_i2c_writeout(dev, &zero)) { + if( 0 != saa7146_i2c_writeout(dev, &zero, short_delay)) { INFO(("revision 0 error. this should never happen.\n")); } } @@ -397,8 +407,13 @@ if( NULL != i2c_adapter ) { memset(i2c_adapter,0,sizeof(struct i2c_adapter)); +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) + strcpy(i2c_adapter->name, dev->name); + i2c_adapter->data = dev; +#else strcpy(i2c_adapter->dev.name, dev->name); i2c_set_adapdata(i2c_adapter,dev); +#endif i2c_adapter->algo = &saa7146_algo; i2c_adapter->algo_data = NULL; i2c_adapter->id = I2C_ALGO_SAA7146; diff -Nru a/drivers/media/common/saa7146_vbi.c b/drivers/media/common/saa7146_vbi.c --- a/drivers/media/common/saa7146_vbi.c Sun Jul 27 10:13:39 2003 +++ b/drivers/media/common/saa7146_vbi.c Sun Jul 27 10:13:39 2003 @@ -9,6 +9,7 @@ u32 *cpu; dma_addr_t dma_addr; + int count = 0; int i; DECLARE_WAITQUEUE(wait, current); @@ -443,5 +444,3 @@ .irq_done = vbi_irq_done, .read = vbi_read, }; - -EXPORT_SYMBOL_GPL(saa7146_vbi_uops); diff -Nru a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c --- a/drivers/media/common/saa7146_video.c Sun Jul 27 10:13:48 2003 +++ b/drivers/media/common/saa7146_video.c Sun Jul 27 10:13:48 2003 @@ -137,6 +137,7 @@ switch (field) { case V4L2_FIELD_TOP: case V4L2_FIELD_BOTTOM: + case V4L2_FIELD_ALTERNATE: maxh = maxh / 2; break; case V4L2_FIELD_INTERLACED: @@ -186,11 +187,18 @@ : V4L2_FIELD_BOTTOM; } switch (field) { + case V4L2_FIELD_ALTERNATE: { + vv->last_field = V4L2_FIELD_TOP; + maxh = maxh / 2; + break; + } case V4L2_FIELD_TOP: case V4L2_FIELD_BOTTOM: + vv->last_field = V4L2_FIELD_INTERLACED; maxh = maxh / 2; break; case V4L2_FIELD_INTERLACED: + vv->last_field = V4L2_FIELD_INTERLACED; break; default: { DEB_D(("no known field mode '%d'.\n",field)); @@ -220,7 +228,7 @@ } } -static int start_preview(struct saa7146_fh *fh) +int saa7146_start_preview(struct saa7146_fh *fh) { struct saa7146_dev *dev = fh->dev; struct saa7146_vv *vv = dev->vv_data; @@ -266,12 +274,12 @@ return 0; } -static int stop_preview(struct saa7146_fh *fh) +int saa7146_stop_preview(struct saa7146_fh *fh) { struct saa7146_dev *dev = fh->dev; struct saa7146_vv *vv = dev->vv_data; - DEB_EE(("saa7146.o: stop_preview()\n")); + DEB_EE(("saa7146.o: saa7146_stop_preview()\n")); /* check if overlay is running */ if( 0 == vv->ov_data ) { @@ -333,8 +341,8 @@ if( vv->ov_data != NULL ) { if( fh == vv->ov_data->fh) { spin_lock_irqsave(&dev->slock,flags); - stop_preview(fh); - start_preview(fh); + saa7146_stop_preview(fh); + saa7146_start_preview(fh); spin_unlock_irqrestore(&dev->slock,flags); } } @@ -522,8 +530,8 @@ if( 0 != vv->ov_data ) { if( fh == vv->ov_data->fh ) { spin_lock_irqsave(&dev->slock,flags); - stop_preview(fh); - start_preview(fh); + saa7146_stop_preview(fh); + saa7146_start_preview(fh); spin_unlock_irqrestore(&dev->slock,flags); } } @@ -561,7 +569,7 @@ m3 = ((size+(size/2)+PAGE_SIZE)/PAGE_SIZE)-1; o1 = size%PAGE_SIZE; o2 = (size+(size/4))%PAGE_SIZE; - printk("size:%d, m1:%d, m2:%d, m3:%d, o1:%d, o2:%d\n",size,m1,m2,m3,o1,o2); + DEB_CAP(("size:%d, m1:%d, m2:%d, m3:%d, o1:%d, o2:%d\n",size,m1,m2,m3,o1,o2)); break; } case 16: { @@ -571,7 +579,7 @@ m3 = ((2*size+PAGE_SIZE)/PAGE_SIZE)-1; o1 = size%PAGE_SIZE; o2 = (size+(size/2))%PAGE_SIZE; - printk("size:%d, m1:%d, m2:%d, m3:%d, o1:%d, o2:%d\n",size,m1,m2,m3,o1,o2); + DEB_CAP(("size:%d, m1:%d, m2:%d, m3:%d, o1:%d, o2:%d\n",size,m1,m2,m3,o1,o2)); break; } default: { @@ -674,7 +682,7 @@ spin_lock_irqsave(&dev->slock,flags); - /* clear out beginning of streaming bit */ + /* clear out beginning of streaming bit (rps register 0)*/ saa7146_write(dev, MC2, MASK_27 ); /* enable rps0 irqs */ @@ -740,19 +748,19 @@ struct videobuf_queue *q; /* check if extension handles the command */ - for(ee = 0; dev->ext->ext_vv_data->ioctls[ee].flags != 0; ee++) { - if( cmd == dev->ext->ext_vv_data->ioctls[ee].cmd ) + for(ee = 0; dev->ext_vv_data->ioctls[ee].flags != 0; ee++) { + if( cmd == dev->ext_vv_data->ioctls[ee].cmd ) break; } - if( 0 != (dev->ext->ext_vv_data->ioctls[ee].flags & SAA7146_EXCLUSIVE) ) { + if( 0 != (dev->ext_vv_data->ioctls[ee].flags & SAA7146_EXCLUSIVE) ) { DEB_D(("extension handles ioctl exclusive.\n")); - result = dev->ext->ext_vv_data->ioctl(dev, cmd, arg); + result = dev->ext_vv_data->ioctl(fh, cmd, arg); return result; } - if( 0 != (dev->ext->ext_vv_data->ioctls[ee].flags & SAA7146_BEFORE) ) { + if( 0 != (dev->ext_vv_data->ioctls[ee].flags & SAA7146_BEFORE) ) { DEB_D(("extension handles ioctl before.\n")); - result = dev->ext->ext_vv_data->ioctl(dev, cmd, arg); + result = dev->ext_vv_data->ioctl(fh, cmd, arg); if( -EAGAIN != result ) { return result; } @@ -793,7 +801,7 @@ V4L2_CAP_VIDEO_OVERLAY | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; - cap->capabilities |= dev->ext->ext_vv_data->capabilities; + cap->capabilities |= dev->ext_vv_data->capabilities; return 0; } case VIDIOC_G_FBUF: @@ -942,9 +950,10 @@ struct v4l2_standard *e = arg; if (e->index < 0 ) return -EINVAL; - if( e->index < dev->ext->ext_vv_data->num_stds ) { + if( e->index < dev->ext_vv_data->num_stds ) { DEB_EE(("VIDIOC_ENUMSTD: index:%d\n",e->index)); - return v4l2_video_std_construct(e, dev->ext->ext_vv_data->stds[e->index].id, dev->ext->ext_vv_data->stds[e->index].name); + v4l2_video_std_construct(e, dev->ext_vv_data->stds[e->index].id, dev->ext_vv_data->stds[e->index].name); + return 0; } return -EINVAL; } @@ -968,22 +977,22 @@ if( vv->ov_data != NULL ) { ov_fh = vv->ov_data->fh; - stop_preview(ov_fh); + saa7146_stop_preview(ov_fh); restart_overlay = 1; } - for(i = 0; i < dev->ext->ext_vv_data->num_stds; i++) - if (*id & dev->ext->ext_vv_data->stds[i].id) + for(i = 0; i < dev->ext_vv_data->num_stds; i++) + if (*id & dev->ext_vv_data->stds[i].id) break; - if (i != dev->ext->ext_vv_data->num_stds) { - vv->standard = &dev->ext->ext_vv_data->stds[i]; - if( NULL != dev->ext->ext_vv_data->std_callback ) - dev->ext->ext_vv_data->std_callback(dev, vv->standard); + if (i != dev->ext_vv_data->num_stds) { + vv->standard = &dev->ext_vv_data->stds[i]; + if( NULL != dev->ext_vv_data->std_callback ) + dev->ext_vv_data->std_callback(dev, vv->standard); found = 1; } if( 0 != restart_overlay ) { - start_preview(ov_fh); + saa7146_start_preview(ov_fh); } up(&dev->lock); @@ -1000,7 +1009,7 @@ int on = *(int *)arg; int err = 0; - if( NULL == vv->ov_fmt ) { + if( NULL == vv->ov_fmt && on != 0 ) { DEB_D(("VIDIOC_OVERLAY: no framebuffer informations. call S_FBUF first!\n")); return -EAGAIN; } @@ -1013,7 +1022,7 @@ } } spin_lock_irqsave(&dev->slock,flags); - err = start_preview(fh); + err = saa7146_start_preview(fh); spin_unlock_irqrestore(&dev->slock,flags); } else { if( vv->ov_data != NULL ) { @@ -1022,7 +1031,7 @@ } } spin_lock_irqsave(&dev->slock,flags); - err = stop_preview(fh); + err = saa7146_stop_preview(fh); spin_unlock_irqrestore(&dev->slock,flags); } return err; @@ -1036,12 +1045,18 @@ return videobuf_querybuf(q,arg); } case VIDIOC_QBUF: { - DEB_D(("VIDIOC_QBUF \n")); - return videobuf_qbuf(file,q,arg); + struct v4l2_buffer *b = arg; + int ret = 0; + ret = videobuf_qbuf(file,q,b); + DEB_D(("VIDIOC_QBUF: ret:%d, index:%d\n",ret,b->index)); + return ret; } case VIDIOC_DQBUF: { - DEB_D(("VIDIOC_DQBUF \n")); - return videobuf_dqbuf(file,q,arg); + struct v4l2_buffer *b = arg; + int ret = 0; + ret = videobuf_dqbuf(file,q,b); + DEB_D(("VIDIOC_DQBUF: ret:%d, index:%d\n",ret,b->index)); + return ret; } case VIDIOC_STREAMON: { DEB_D(("VIDIOC_STREAMON \n")); @@ -1075,7 +1090,7 @@ q = &fh->video_q; down(&q->lock); - err = videobuf_mmap_setup(file,q,gbuffers,gbufsize); + err = videobuf_mmap_setup(file,q,gbuffers,gbufsize); // ,V4L2_MEMORY_MMAP); if (err < 0) { up(&q->lock); return err; @@ -1250,7 +1265,7 @@ vv->video_q.dev = dev; /* set some default values */ - vv->standard = &dev->ext->ext_vv_data->stds[0]; + vv->standard = &dev->ext_vv_data->stds[0]; /* FIXME: what's this? */ vv->current_hps_source = SAA7146_HPS_SOURCE_PORT_A; @@ -1287,7 +1302,7 @@ if( 0 != vv->ov_data ) { if( fh == vv->ov_data->fh ) { spin_lock_irqsave(&dev->slock,flags); - stop_preview(fh); + saa7146_stop_preview(fh); spin_unlock_irqrestore(&dev->slock,flags); } } @@ -1331,7 +1346,7 @@ if( vv->ov_data != NULL ) { ov_fh = vv->ov_data->fh; - stop_preview(ov_fh); + saa7146_stop_preview(ov_fh); restart_overlay = 1; } @@ -1343,7 +1358,7 @@ /* restart overlay if it was active before */ if( 0 != restart_overlay ) { - start_preview(ov_fh); + saa7146_start_preview(ov_fh); } return ret; @@ -1358,5 +1373,3 @@ .capture_begin = video_begin, .capture_end = video_end, }; - -EXPORT_SYMBOL_GPL(saa7146_video_uops); diff -Nru a/drivers/media/common/saa7146_vv_ksyms.c b/drivers/media/common/saa7146_vv_ksyms.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/media/common/saa7146_vv_ksyms.c Sun Jul 27 10:13:53 2003 @@ -0,0 +1,15 @@ +#include +#include + +EXPORT_SYMBOL_GPL(saa7146_vbi_uops); +EXPORT_SYMBOL_GPL(saa7146_video_uops); + +EXPORT_SYMBOL_GPL(saa7146_start_preview); +EXPORT_SYMBOL_GPL(saa7146_stop_preview); + +EXPORT_SYMBOL_GPL(saa7146_set_hps_source_and_sync); +EXPORT_SYMBOL_GPL(saa7146_register_device); +EXPORT_SYMBOL_GPL(saa7146_unregister_device); + +EXPORT_SYMBOL_GPL(saa7146_vv_init); +EXPORT_SYMBOL_GPL(saa7146_vv_release); diff -Nru a/drivers/media/dvb/Kconfig b/drivers/media/dvb/Kconfig --- a/drivers/media/dvb/Kconfig Sun Jul 27 10:13:43 2003 +++ b/drivers/media/dvb/Kconfig Sun Jul 27 10:13:43 2003 @@ -33,9 +33,19 @@ source "drivers/media/dvb/frontends/Kconfig" comment "Supported SAA7146 based PCI Adapters" - depends on DVB + depends on DVB && PCI source "drivers/media/dvb/ttpci/Kconfig" + +comment "Supported USB Adapters" + depends on DVB && USB + +source "drivers/media/dvb/ttusb-budget/Kconfig" +source "drivers/media/dvb/ttusb-dec/Kconfig" + +comment "Supported FlexCopII (B2C2) Adapters" + depends on DVB && PCI +source "drivers/media/dvb/b2c2/Kconfig" endmenu diff -Nru a/drivers/media/dvb/Makefile b/drivers/media/dvb/Makefile --- a/drivers/media/dvb/Makefile Sun Jul 27 10:13:47 2003 +++ b/drivers/media/dvb/Makefile Sun Jul 27 10:13:47 2003 @@ -2,4 +2,5 @@ # Makefile for the kernel multimedia device drivers. # -obj-y := dvb-core/ frontends/ ttpci/ # ttusb-budget/ +obj-y := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ + diff -Nru a/drivers/media/dvb/b2c2/Kconfig b/drivers/media/dvb/b2c2/Kconfig --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/media/dvb/b2c2/Kconfig Sun Jul 27 10:13:53 2003 @@ -0,0 +1,8 @@ +config DVB_B2C2_SKYSTAR + tristate "Technisat Skystar2 PCI" + depends on DVB_CORE + help + Support for the Skystar2 PCI DVB card by Technisat, which + is equipped with the FlexCopII chipset by B2C2. + + Say Y if you own such a device and want to use it. diff -Nru a/drivers/media/dvb/b2c2/Makefile b/drivers/media/dvb/b2c2/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/media/dvb/b2c2/Makefile Sun Jul 27 10:13:53 2003 @@ -0,0 +1,3 @@ +obj-$(CONFIG_DVB_B2C2_SKYSTAR) += skystar2.o + +EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ diff -Nru a/drivers/media/dvb/b2c2/skystar2.c b/drivers/media/dvb/b2c2/skystar2.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/media/dvb/b2c2/skystar2.c Sun Jul 27 10:13:53 2003 @@ -0,0 +1,2506 @@ +/* + * skystar2.c - driver for the Technisat SkyStar2 PCI DVB card + * based on the FlexCopII by B2C2,Inc. + * + * Copyright (C) 2003 V.C. , skystar@moldova.cc + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#include +#include +#include + +#include "dvb_i2c.h" +#include "dvb_frontend.h" +#include "dvb_functions.h" + +#include +#include +#include "dvb_demux.h" +#include "dmxdev.h" +#include "dvb_filter.h" +#include "dvbdev.h" +#include "demux.h" +#include "dvb_net.h" + +static int debug = 0; +#define dprintk(x...) do { if (debug) printk(x); } while (0) + +#define SizeOfBufDMA1 0x3AC00 +#define SizeOfBufDMA2 0x758 + +struct dmaq { + + u32 bus_addr; + u32 head; + u32 tail; + u32 buffer_size; + u8 *buffer; +}; + +struct packet_header { + + u32 sync_byte; + u32 transport_error_indicator; + u32 payload_unit_start_indicator; + u32 transport_priority; + u32 pid; + u32 transport_scrambling_control; + u32 adaptation_field_control; + u32 continuity_counter; +}; + +struct adapter { + + struct pci_dev *pdev; + + u8 card_revision; + u32 b2c2_revision; + u32 PidFilterMax; + u32 MacFilterMax; + u32 irq; + u32 io_mem; + u32 io_port; + u8 mac_addr[8]; + u32 dwSramType; + + struct dvb_adapter *dvb_adapter; + struct dvb_demux demux; + struct dmxdev dmxdev; + struct dmx_frontend hw_frontend; + struct dmx_frontend mem_frontend; + struct dvb_i2c_bus *i2c_bus; + struct dvb_net dvbnet; + + struct semaphore i2c_sem; + + struct dmaq dmaq1; + struct dmaq dmaq2; + + u32 dma_ctrl; + u32 dma_status; + + u32 capturing; + + spinlock_t lock; + + u16 pids[0x27]; + u32 mac_filter; +}; + +#define WriteRegDW(adapter,reg,value) writel(value, adapter->io_mem + reg) +#define ReadRegDW(adapter,reg) readl(adapter->io_mem + reg) + +static void WriteRegOp(struct adapter *adapter, u32 reg, u32 operation, u32 andvalue, u32 orvalue) +{ + u32 tmp; + + tmp = ReadRegDW(adapter, reg); + + if (operation == 1) + tmp = tmp | orvalue; + if (operation == 2) + tmp = tmp & andvalue; + if (operation == 3) + tmp = (tmp & andvalue) | orvalue; + + WriteRegDW(adapter, reg, tmp); +} + +/* i2c functions */ +static int i2cMainWriteForFlex2(struct adapter * adapter, u32 command, u8 * buf, u32 retries) +{ + u32 i; + u32 value; + + WriteRegDW(adapter, 0x100, 0); + WriteRegDW(adapter, 0x100, command); + + for (i = 0; i < retries; i++) { + value = ReadRegDW(adapter, 0x100); + + if ((value & 0x40000000) == 0) { + if ((value & 0x81000000) == 0x80000000) { + if (buf != 0) + *buf = (value >> 0x10) & 0xff; + + return 1; + } + + } else { + + WriteRegDW(adapter, 0x100, 0); + WriteRegDW(adapter, 0x100, command); + } + } + + return 0; +} + +/* device = 0x10000000 for tuner, 0x20000000 for eeprom */ +static void i2cMainSetup(u32 device, u32 chip_addr, u8 op, u8 addr, u32 value, u32 len, u32 *command) +{ + *command = device | ((len - 1) << 26) | (value << 16) | (addr << 8) | chip_addr; + + if (op != 0) + *command = *command | 0x03000000; + else + *command = *command | 0x01000000; +} + +static int FlexI2cRead4(struct adapter * adapter, u32 device, u32 chip_addr, u16 addr, u8 * buf, u8 len) +{ + u32 command; + u32 value; + + int result, i; + + i2cMainSetup(device, chip_addr, 1, addr, 0, len, &command); + + result = i2cMainWriteForFlex2(adapter, command, buf, 100000); + + if ((result & 0xff) != 0) { + if (len > 1) { + value = ReadRegDW(adapter, 0x104); + + for (i = 1; i < len; i++) { + buf[i] = value & 0xff; + value = value >> 8; + } + } + } + + return result; +} + +static int FlexI2cWrite4(struct adapter * adapter, u32 device, u32 chip_addr, u32 addr, u8 * buf, u8 len) +{ + u32 command; + u32 value; + int i; + + if (len > 1) { + value = 0; + + for (i = len; i > 1; i--) { + value = value << 8; + value = value | buf[i - 1]; + } + + WriteRegDW(adapter, 0x104, value); + } + + i2cMainSetup(device, chip_addr, 0, addr, buf[0], len, &command); + + return i2cMainWriteForFlex2(adapter, command, 0, 100000); +} + +static void fixchipaddr(u32 device, u32 bus, u32 addr, u32 *ret) +{ + if (device == 0x20000000) + *ret = bus | ((addr >> 8) & 3); + + *ret = bus; +} + +static u32 FLEXI2C_read(struct adapter * adapter, u32 device, u32 bus, u32 addr, u8 * buf, u32 len) +{ + u32 chipaddr; + u32 bytes_to_transfer; + u8 *start; + +// dprintk("%s:\n", __FUNCTION__); + + start = buf; + + while (len != 0) { + bytes_to_transfer = len; + + if (bytes_to_transfer > 4) + bytes_to_transfer = 4; + + fixchipaddr(device, bus, addr, &chipaddr); + + if (FlexI2cRead4(adapter, device, chipaddr, addr, buf, bytes_to_transfer) == 0) + return buf - start; + + buf = buf + bytes_to_transfer; + addr = addr + bytes_to_transfer; + len = len - bytes_to_transfer; + }; + + return buf - start; +} + +static u32 FLEXI2C_write(struct adapter * adapter, u32 device, u32 bus, u32 addr, u8 * buf, u32 len) +{ + u32 chipaddr; + u32 bytes_to_transfer; + u8 *start; + +// dprintk("%s:\n", __FUNCTION__); + + start = buf; + + while (len != 0) { + bytes_to_transfer = len; + + if (bytes_to_transfer > 4) + bytes_to_transfer = 4; + + fixchipaddr(device, bus, addr, &chipaddr); + + if (FlexI2cWrite4(adapter, device, chipaddr, addr, buf, bytes_to_transfer) == 0) + return buf - start; + + buf = buf + bytes_to_transfer; + addr = addr + bytes_to_transfer; + len = len - bytes_to_transfer; + } + + return buf - start; +} + +static int master_xfer(struct dvb_i2c_bus *i2c, const struct i2c_msg *msgs, int num) +{ + struct adapter *tmp = i2c->data; + int i, ret = 0; + + if (down_interruptible(&tmp->i2c_sem)) + return -ERESTARTSYS; + + if (0) { + dprintk("%s:\n", __FUNCTION__); + + for (i = 0; i < num; i++) { + printk("message %d: flags=%x, addr=0x%04x, buf=%x, len=%d \n", i, msgs[i].flags, msgs[i].addr, (u32) msgs[i].buf, msgs[i].len); + } + } + + /* allow only the vp310 frontend to access the bus */ + if ((msgs[0].addr != 0x0E) && (msgs[0].addr != 0x61)) { + up(&tmp->i2c_sem); + + return -EREMOTEIO; + } + + if ((num == 1) && (msgs[0].buf != NULL)) { + if (msgs[0].flags == I2C_M_RD) { + ret = -EINVAL; + + } else { + + // single writes do have the reg addr in buf[0] and data in buf[1] to buf[n] + ret = FLEXI2C_write(tmp, 0x10000000, msgs[0].addr, msgs[0].buf[0], &msgs[0].buf[1], msgs[0].len - 1); + + if (ret != msgs[0].len - 1) + ret = -EREMOTEIO; + else + ret = num; + } + + } else if ((num == 2) && (msgs[1].buf != NULL)) { + + // i2c reads consist of a reg addr _write_ followed by a data read, so msg[1].flags has to be examined + if (msgs[1].flags == I2C_M_RD) { + ret = FLEXI2C_read(tmp, 0x10000000, msgs[0].addr, msgs[0].buf[0], msgs[1].buf, msgs[1].len); + + } else { + + ret = FLEXI2C_write(tmp, 0x10000000, msgs[0].addr, msgs[0].buf[0], msgs[1].buf, msgs[1].len); + } + + if (ret != msgs[1].len) + ret = -EREMOTEIO; + else + ret = num; + } + + up(&tmp->i2c_sem); + + /* master xfer functions always return the number of successfully + transmitted messages, not the number of transmitted bytes. + return -EREMOTEIO in case of failure. */ + return ret; +} + +/* SRAM (Skystar2 rev2.3 has one "ISSI IS61LV256" chip on board, + but it seems that FlexCopII can work with more than one chip) */ +static void SRAMSetNetDest(struct adapter * adapter, u8 dest) +{ + u32 tmp; + + udelay(1000); + + tmp = (ReadRegDW(adapter, 0x714) & 0xFFFFFFFC) | (dest & 3); + + udelay(1000); + + WriteRegDW(adapter, 0x714, tmp); + WriteRegDW(adapter, 0x714, tmp); + + udelay(1000); + + /* return value is never used? */ +/* return tmp; */ +} + +static void SRAMSetCaiDest(struct adapter * adapter, u8 dest) +{ + u32 tmp; + + udelay(1000); + + tmp = (ReadRegDW(adapter, 0x714) & 0xFFFFFFF3) | ((dest & 3) << 2); + + udelay(1000); + udelay(1000); + + WriteRegDW(adapter, 0x714, tmp); + WriteRegDW(adapter, 0x714, tmp); + + udelay(1000); + + /* return value is never used? */ +/* return tmp; */ +} + +static void SRAMSetCaoDest(struct adapter * adapter, u8 dest) +{ + u32 tmp; + + udelay(1000); + + tmp = (ReadRegDW(adapter, 0x714) & 0xFFFFFFCF) | ((dest & 3) << 4); + + udelay(1000); + udelay(1000); + + WriteRegDW(adapter, 0x714, tmp); + WriteRegDW(adapter, 0x714, tmp); + + udelay(1000); + + /* return value is never used? */ +/* return tmp; */ +} + +static void SRAMSetMediaDest(struct adapter * adapter, u8 dest) +{ + u32 tmp; + + udelay(1000); + + tmp = (ReadRegDW(adapter, 0x714) & 0xFFFFFF3F) | ((dest & 3) << 6); + + udelay(1000); + udelay(1000); + + WriteRegDW(adapter, 0x714, tmp); + WriteRegDW(adapter, 0x714, tmp); + + udelay(1000); + + /* return value is never used? */ +/* return tmp; */ +} + +/* SRAM memory is accessed through a buffer register in the FlexCop + chip (0x700). This register has the following structure: + bits 0-14 : address + bit 15 : read/write flag + bits 16-23 : 8-bit word to write + bits 24-27 : = 4 + bits 28-29 : memory bank selector + bit 31 : busy flag +*/ +static void FlexSramWrite(struct adapter *adapter, u32 bank, u32 addr, u8 * buf, u32 len) +{ + u32 i, command, retries; + + for (i = 0; i < len; i++) { + command = bank | addr | 0x04000000 | (*buf << 0x10); + + retries = 2; + + while (((ReadRegDW(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) { + mdelay(1); + retries--; + }; + + if (retries == 0) + printk("%s: SRAM timeout\n", __FUNCTION__); + + WriteRegDW(adapter, 0x700, command); + + buf++; + addr++; + } +} + +static void FlexSramRead(struct adapter *adapter, u32 bank, u32 addr, u8 * buf, u32 len) +{ + u32 i, command, value, retries; + + for (i = 0; i < len; i++) { + command = bank | addr | 0x04008000; + + retries = 10000; + + while (((ReadRegDW(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) { + mdelay(1); + retries--; + }; + + if (retries == 0) + printk("%s: SRAM timeout\n", __FUNCTION__); + + WriteRegDW(adapter, 0x700, command); + + retries = 10000; + + while (((ReadRegDW(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) { + mdelay(1); + retries--; + }; + + if (retries == 0) + printk("%s: SRAM timeout\n", __FUNCTION__); + + value = ReadRegDW(adapter, 0x700) >> 0x10; + + *buf = (value & 0xff); + + addr++; + buf++; + } +} + +static void SRAM_writeChunk(struct adapter *adapter, u32 addr, u8 * buf, u16 len) +{ + u32 bank; + + bank = 0; + + if (adapter->dwSramType == 0x20000) { + bank = (addr & 0x18000) << 0x0D; + } + + if (adapter->dwSramType == 0x00000) { + if ((addr >> 0x0F) == 0) + bank = 0x20000000; + else + bank = 0x10000000; + } + + FlexSramWrite(adapter, bank, addr & 0x7FFF, buf, len); +} + +static void SRAM_readChunk(struct adapter *adapter, u32 addr, u8 * buf, u16 len) +{ + u32 bank; + + bank = 0; + + if (adapter->dwSramType == 0x20000) { + bank = (addr & 0x18000) << 0x0D; + } + + if (adapter->dwSramType == 0x00000) { + if ((addr >> 0x0F) == 0) + bank = 0x20000000; + else + bank = 0x10000000; + } + + FlexSramRead(adapter, bank, addr & 0x7FFF, buf, len); +} + +static void SRAM_read(struct adapter *adapter, u32 addr, u8 * buf, u32 len) +{ + u32 length; + + while (len != 0) { + length = len; + + // check if the address range belongs to the same + // 32K memory chip. If not, the data is read from + // one chip at a time. + if ((addr >> 0x0F) != ((addr + len - 1) >> 0x0F)) { + length = (((addr >> 0x0F) + 1) << 0x0F) - addr; + } + + SRAM_readChunk(adapter, addr, buf, length); + + addr = addr + length; + buf = buf + length; + len = len - length; + } +} + +static void SRAM_write(struct adapter *adapter, u32 addr, u8 * buf, u32 len) +{ + u32 length; + + while (len != 0) { + length = len; + + // check if the address range belongs to the same + // 32K memory chip. If not, the data is written to + // one chip at a time. + if ((addr >> 0x0F) != ((addr + len - 1) >> 0x0F)) { + length = (((addr >> 0x0F) + 1) << 0x0F) - addr; + } + + SRAM_writeChunk(adapter, addr, buf, length); + + addr = addr + length; + buf = buf + length; + len = len - length; + } +} + +static void SRAM_setSize(struct adapter *adapter, u32 mask) +{ + WriteRegDW(adapter, 0x71C, (mask | (~0x30000 & ReadRegDW(adapter, 0x71C)))); +} + +static void SRAM_init(struct adapter *adapter) +{ + u32 tmp; + + tmp = ReadRegDW(adapter, 0x71C); + + WriteRegDW(adapter, 0x71C, 1); + + if (ReadRegDW(adapter, 0x71C) != 0) { + WriteRegDW(adapter, 0x71C, tmp); + + adapter->dwSramType = tmp & 0x30000; + + dprintk("%s: dwSramType = %x\n", __FUNCTION__, adapter->dwSramType); + + } else { + + adapter->dwSramType = 0x10000; + + dprintk("%s: dwSramType = %x\n", __FUNCTION__, adapter->dwSramType); + } + + /* return value is never used? */ +/* return adapter->dwSramType; */ +} + +static int SRAM_testLocation(struct adapter *adapter, u32 mask, u32 addr) +{ + u8 tmp1, tmp2; + + dprintk("%s: mask = %x, addr = %x\n", __FUNCTION__, mask, addr); + + SRAM_setSize(adapter, mask); + SRAM_init(adapter); + + tmp2 = 0xA5; + tmp1 = 0x4F; + + SRAM_write(adapter, addr, &tmp2, 1); + SRAM_write(adapter, addr + 4, &tmp1, 1); + + tmp2 = 0; + + mdelay(20); + + SRAM_read(adapter, addr, &tmp2, 1); + SRAM_read(adapter, addr, &tmp2, 1); + + dprintk("%s: wrote 0xA5, read 0x%2x\n", __FUNCTION__, tmp2); + + if (tmp2 != 0xA5) + return 0; + + tmp2 = 0x5A; + tmp1 = 0xF4; + + SRAM_write(adapter, addr, &tmp2, 1); + SRAM_write(adapter, addr + 4, &tmp1, 1); + + tmp2 = 0; + + mdelay(20); + + SRAM_read(adapter, addr, &tmp2, 1); + SRAM_read(adapter, addr, &tmp2, 1); + + dprintk("%s: wrote 0x5A, read 0x%2x\n", __FUNCTION__, tmp2); + + if (tmp2 != 0x5A) + return 0; + + return 1; +} + +static u32 SRAM_length(struct adapter * adapter) +{ + if (adapter->dwSramType == 0x10000) + return 32768; // 32K + if (adapter->dwSramType == 0x00000) + return 65536; // 64K + if (adapter->dwSramType == 0x20000) + return 131072; // 128K + + return 32768; // 32K +} + +/* FlexcopII can work with 32K, 64K or 128K of external SRAM memory. + - for 128K there are 4x32K chips at bank 0,1,2,3. + - for 64K there are 2x32K chips at bank 1,2. + - for 32K there is one 32K chip at bank 0. + + FlexCop works only with one bank at a time. The bank is selected + by bits 28-29 of the 0x700 register. + + bank 0 covers addresses 0x00000-0x07FFF + bank 1 covers addresses 0x08000-0x0FFFF + bank 2 covers addresses 0x10000-0x17FFF + bank 3 covers addresses 0x18000-0x1FFFF +*/ +static int SramDetectForFlex2(struct adapter *adapter) +{ + u32 tmp, tmp2, tmp3; + + dprintk("%s:\n", __FUNCTION__); + + tmp = ReadRegDW(adapter, 0x208); + WriteRegDW(adapter, 0x208, 0); + + tmp2 = ReadRegDW(adapter, 0x71C); + + dprintk("%s: tmp2 = %x\n", __FUNCTION__, tmp2); + + WriteRegDW(adapter, 0x71C, 1); + + tmp3 = ReadRegDW(adapter, 0x71C); + + dprintk("%s: tmp3 = %x\n", __FUNCTION__, tmp3); + + WriteRegDW(adapter, 0x71C, tmp2); + + // check for internal SRAM ??? + tmp3--; + if (tmp3 != 0) { + SRAM_setSize(adapter, 0x10000); + SRAM_init(adapter); + WriteRegDW(adapter, 0x208, tmp); + + dprintk("%s: sram size = 32K\n", __FUNCTION__); + + return 32; + } + + if (SRAM_testLocation(adapter, 0x20000, 0x18000) != 0) { + SRAM_setSize(adapter, 0x20000); + SRAM_init(adapter); + WriteRegDW(adapter, 0x208, tmp); + + dprintk("%s: sram size = 128K\n", __FUNCTION__); + + return 128; + } + + if (SRAM_testLocation(adapter, 0x00000, 0x10000) != 0) { + SRAM_setSize(adapter, 0x00000); + SRAM_init(adapter); + WriteRegDW(adapter, 0x208, tmp); + + dprintk("%s: sram size = 64K\n", __FUNCTION__); + + return 64; + } + + if (SRAM_testLocation(adapter, 0x10000, 0x00000) != 0) { + SRAM_setSize(adapter, 0x10000); + SRAM_init(adapter); + WriteRegDW(adapter, 0x208, tmp); + + dprintk("%s: sram size = 32K\n", __FUNCTION__); + + return 32; + } + + SRAM_setSize(adapter, 0x10000); + SRAM_init(adapter); + WriteRegDW(adapter, 0x208, tmp); + + dprintk("%s: SRAM detection failed. Set to 32K \n", __FUNCTION__); + + return 0; +} + +static void SLL_detectSramSize(struct adapter *adapter) +{ + SramDetectForFlex2(adapter); +} +/* EEPROM (Skystar2 has one "24LC08B" chip on board) */ +/* +static int EEPROM_write(struct adapter *adapter, u16 addr, u8 * buf, u16 len) +{ + return FLEXI2C_write(adapter, 0x20000000, 0x50, addr, buf, len); +} +*/ + +static int EEPROM_read(struct adapter *adapter, u16 addr, u8 * buf, u16 len) +{ + return FLEXI2C_read(adapter, 0x20000000, 0x50, addr, buf, len); +} + +u8 calc_LRC(u8 * buf, u32 len) +{ + u32 i; + u8 sum; + + sum = 0; + + for (i = 0; i < len; i++) + sum = sum ^ buf[i]; + + return sum; +} + +static int EEPROM_LRC_read(struct adapter *adapter, u32 addr, u32 len, u8 * buf, u32 retries) +{ + int i; + + for (i = 0; i < retries; i++) { + if (EEPROM_read(adapter, addr, buf, len) == len) { + if (calc_LRC(buf, len - 1) == buf[len - 1]) + return 1; + } + } + + return 0; +} + +/* +static int EEPROM_LRC_write(struct adapter *adapter, u32 addr, u32 len, u8 * wbuf, u8 * rbuf, u32 retries) +{ + int i; + + for (i = 0; i < retries; i++) { + if (EEPROM_write(adapter, addr, wbuf, len) == len) { + if (EEPROM_LRC_read(adapter, addr, len, rbuf, retries) == 1) + return 1; + } + } + + return 0; +} +*/ + +/* These functions could be called from the initialization routine + to unlock SkyStar2 cards, locked by "Europe On Line". + + in cards from "Europe On Line" the key is: + + u8 key[20] = { + 0xB2, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + }; + + LRC = 0xB3; + + in unlocked cards the key is: + + u8 key[20] = { + 0xB2, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + }; + + LRC = 0xB2; +*/ +/* +static int EEPROM_writeKey(struct adapter *adapter, u8 * key, u32 len) +{ + u8 rbuf[20]; + u8 wbuf[20]; + + if (len != 16) + return 0; + + memcpy(wbuf, key, len); + + wbuf[16] = 0; + wbuf[17] = 0; + wbuf[18] = 0; + wbuf[19] = calc_LRC(wbuf, 19); + + return EEPROM_LRC_write(adapter, 0x3E4, 20, wbuf, rbuf, 4); +} +*/ +static int EEPROM_readKey(struct adapter *adapter, u8 * key, u32 len) +{ + u8 buf[20]; + + if (len != 16) + return 0; + + if (EEPROM_LRC_read(adapter, 0x3E4, 20, buf, 4) == 0) + return 0; + + memcpy(key, buf, len); + + return 1; +} + +static int EEPROM_getMacAddr(struct adapter *adapter, char type, u8 * mac) +{ + u8 tmp[8]; + + if (EEPROM_LRC_read(adapter, 0x3F8, 8, tmp, 4) != 0) { + if (type != 0) { + mac[0] = tmp[0]; + mac[1] = tmp[1]; + mac[2] = tmp[2]; + mac[3] = 0xFE; + mac[4] = 0xFF; + mac[5] = tmp[3]; + mac[6] = tmp[4]; + mac[7] = tmp[5]; + + } else { + + mac[0] = tmp[0]; + mac[1] = tmp[1]; + mac[2] = tmp[2]; + mac[3] = tmp[3]; + mac[4] = tmp[4]; + mac[5] = tmp[5]; + } + + return 1; + + } else { + + if (type == 0) { + memset(mac, 0, 6); + + } else { + + memset(mac, 0, 8); + } + + return 0; + } +} + +/* +static char EEPROM_setMacAddr(struct adapter *adapter, char type, u8 * mac) +{ + u8 tmp[8]; + + if (type != 0) { + tmp[0] = mac[0]; + tmp[1] = mac[1]; + tmp[2] = mac[2]; + tmp[3] = mac[5]; + tmp[4] = mac[6]; + tmp[5] = mac[7]; + + } else { + + tmp[0] = mac[0]; + tmp[1] = mac[1]; + tmp[2] = mac[2]; + tmp[3] = mac[3]; + tmp[4] = mac[4]; + tmp[5] = mac[5]; + } + + tmp[6] = 0; + tmp[7] = calc_LRC(tmp, 7); + + if (EEPROM_write(adapter, 0x3F8, tmp, 8) == 8) + return 1; + + return 0; +} +*/ + +/* PID filter */ +static void FilterEnableStream1Filter(struct adapter *adapter, u32 op) +{ + dprintk("%s: op=%x\n", __FUNCTION__, op); + + if (op == 0) { + WriteRegOp(adapter, 0x208, 2, ~0x00000001, 0); + + } else { + + WriteRegOp(adapter, 0x208, 1, 0, 0x00000001); + } +} + +static void FilterEnableStream2Filter(struct adapter *adapter, u32 op) +{ + dprintk("%s: op=%x\n", __FUNCTION__, op); + + if (op == 0) { + WriteRegOp(adapter, 0x208, 2, ~0x00000002, 0); + + } else { + + WriteRegOp(adapter, 0x208, 1, 0, 0x00000002); + } +} + +static void FilterEnablePcrFilter(struct adapter *adapter, u32 op) +{ + dprintk("%s: op=%x\n", __FUNCTION__, op); + + if (op == 0) { + WriteRegOp(adapter, 0x208, 2, ~0x00000004, 0); + + } else { + + WriteRegOp(adapter, 0x208, 1, 0, 0x00000004); + } +} + +static void FilterEnablePmtFilter(struct adapter *adapter, u32 op) +{ + dprintk("%s: op=%x\n", __FUNCTION__, op); + + if (op == 0) { + WriteRegOp(adapter, 0x208, 2, ~0x00000008, 0); + + } else { + + WriteRegOp(adapter, 0x208, 1, 0, 0x00000008); + } +} + +static void FilterEnableEmmFilter(struct adapter *adapter, u32 op) +{ + dprintk("%s: op=%x\n", __FUNCTION__, op); + + if (op == 0) { + WriteRegOp(adapter, 0x208, 2, ~0x00000010, 0); + + } else { + + WriteRegOp(adapter, 0x208, 1, 0, 0x00000010); + } +} + +static void FilterEnableEcmFilter(struct adapter *adapter, u32 op) +{ + dprintk("%s: op=%x\n", __FUNCTION__, op); + + if (op == 0) { + WriteRegOp(adapter, 0x208, 2, ~0x00000020, 0); + + } else { + + WriteRegOp(adapter, 0x208, 1, 0, 0x00000020); + } +} + +/* +static void FilterEnableNullFilter(struct adapter *adapter, u32 op) +{ + dprintk("%s: op=%x\n", __FUNCTION__, op); + + if (op == 0) { + WriteRegOp(adapter, 0x208, 2, ~0x00000040, 0); + + } else { + + WriteRegOp(adapter, 0x208, 1, 0, 0x00000040); + } +} +*/ + +static void FilterEnableMaskFilter(struct adapter *adapter, u32 op) +{ + dprintk("%s: op=%x\n", __FUNCTION__, op); + + if (op == 0) { + WriteRegOp(adapter, 0x208, 2, ~0x00000080, 0); + + } else { + + WriteRegOp(adapter, 0x208, 1, 0, 0x00000080); + } +} + + +static void CtrlEnableMAC(struct adapter *adapter, u32 op) +{ + if (op == 0) { + WriteRegOp(adapter, 0x208, 2, ~0x00004000, 0); + + } else { + + WriteRegOp(adapter, 0x208, 1, 0, 0x00004000); + } +} + +static int CASetMacDstAddrFilter(struct adapter *adapter, u8 * mac) +{ + u32 tmp1, tmp2; + + tmp1 = (mac[3] << 0x18) | (mac[2] << 0x10) | (mac[1] << 0x08) | mac[0]; + tmp2 = (mac[5] << 0x08) | mac[4]; + + WriteRegDW(adapter, 0x418, tmp1); + WriteRegDW(adapter, 0x41C, tmp2); + + return 0; +} + +/* +static void SetIgnoreMACFilter(struct adapter *adapter, u8 op) +{ + if (op != 0) { + WriteRegOp(adapter, 0x208, 2, ~0x00004000, 0); + + adapter->mac_filter = 1; + + } else { + + if (adapter->mac_filter != 0) { + adapter->mac_filter = 0; + + WriteRegOp(adapter, 0x208, 1, 0, 0x00004000); + } + } +} +*/ + +/* +static void CheckNullFilterEnable(struct adapter *adapter) +{ + FilterEnableNullFilter(adapter, 1); + FilterEnableMaskFilter(adapter, 1); +} +*/ + +static void InitPIDsInfo(struct adapter *adapter) +{ + int i; + + for (i = 0; i < 0x27; i++) + adapter->pids[i] = 0x1FFF; +} + +static int CheckPID(struct adapter *adapter, u16 pid) +{ + u32 i; + + if (pid == 0x1FFF) + return 0; + + for (i = 0; i < 0x27; i++) { + if (adapter->pids[i] == pid) + return 1; + } + + return 0; +} + +static void PidSetGroupPID(struct adapter * adapter, u32 pid) +{ + u32 value; + + dprintk("%s: pid=%x\n", __FUNCTION__, pid); + + value = (pid & 0x3FFF) | (ReadRegDW(adapter, 0x30C) & 0xFFFF0000); + + WriteRegDW(adapter, 0x30C, value); + + /* return value is never used? */ +/* return value; */ +} + +static void PidSetGroupMASK(struct adapter * adapter, u32 pid) +{ + u32 value; + + dprintk("%s: pid=%x\n", __FUNCTION__, pid); + + value = ((pid & 0x3FFF) << 0x10) | (ReadRegDW(adapter, 0x30C) & 0xFFFF); + + WriteRegDW(adapter, 0x30C, value); + + /* return value is never used? */ +/* return value; */ +} + +static void PidSetStream1PID(struct adapter * adapter, u32 pid) +{ + u32 value; + + dprintk("%s: pid=%x\n", __FUNCTION__, pid); + + value = (pid & 0x3FFF) | (ReadRegDW(adapter, 0x300) & 0xFFFFC000); + + WriteRegDW(adapter, 0x300, value); + + /* return value is never used? */ +/* return value; */ +} + +static void PidSetStream2PID(struct adapter * adapter, u32 pid) +{ + u32 value; + + dprintk("%s: pid=%x\n", __FUNCTION__, pid); + + value = ((pid & 0x3FFF) << 0x10) | (ReadRegDW(adapter, 0x300) & 0xFFFF); + + WriteRegDW(adapter, 0x300, value); + + /* return value is never used? */ +/* return value; */ +} + +static void PidSetPcrPID(struct adapter * adapter, u32 pid) +{ + u32 value; + + dprintk("%s: pid=%x\n", __FUNCTION__, pid); + + value = (pid & 0x3FFF) | (ReadRegDW(adapter, 0x304) & 0xFFFFC000); + + WriteRegDW(adapter, 0x304, value); + + /* return value is never used? */ +/* return value; */ +} + +static void PidSetPmtPID(struct adapter * adapter, u32 pid) +{ + u32 value; + + dprintk("%s: pid=%x\n", __FUNCTION__, pid); + + value = ((pid & 0x3FFF) << 0x10) | (ReadRegDW(adapter, 0x304) & 0x3FFF); + + WriteRegDW(adapter, 0x304, value); + + /* return value is never used? */ +/* return value; */ +} + +static void PidSetEmmPID(struct adapter * adapter, u32 pid) +{ + u32 value; + + dprintk("%s: pid=%x\n", __FUNCTION__, pid); + + value = (pid & 0xFFFF) | (ReadRegDW(adapter, 0x308) & 0xFFFF0000); + + WriteRegDW(adapter, 0x308, value); + + /* return value is never used? */ +/* return value; */ +} + +static void PidSetEcmPID(struct adapter * adapter, u32 pid) +{ + u32 value; + + dprintk("%s: pid=%x\n", __FUNCTION__, pid); + + value = (pid << 0x10) | (ReadRegDW(adapter, 0x308) & 0xFFFF); + + WriteRegDW(adapter, 0x308, value); + + /* return value is never used? */ +/* return value; */ +} + +static int PidGetStream1PID(struct adapter * adapter) +{ + return ReadRegDW(adapter, 0x300) & 0x00001FFF; +} + +static int PidGetStream2PID(struct adapter * adapter) +{ + return (ReadRegDW(adapter, 0x300) >> 0x10)& 0x00001FFF; +} + +static int PidGetPcrPID(struct adapter * adapter) +{ + return ReadRegDW(adapter, 0x304) & 0x00001FFF; +} + +static int PidGetPmtPID(struct adapter * adapter) +{ + return (ReadRegDW(adapter, 0x304) >> 0x10)& 0x00001FFF; +} + +static int PidGetEmmPID(struct adapter * adapter) +{ + return ReadRegDW(adapter, 0x308) & 0x00001FFF; +} + +static int PidGetEcmPID(struct adapter * adapter) +{ + return (ReadRegDW(adapter, 0x308) >> 0x10)& 0x00001FFF; +} + +static int PidGetGroupPID(struct adapter * adapter) +{ + return ReadRegDW(adapter, 0x30C) & 0x00001FFF; +} + +static int PidGetGroupMASK(struct adapter * adapter) +{ + return (ReadRegDW(adapter, 0x30C) >> 0x10)& 0x00001FFF; +} + +/* +static void ResetHardwarePIDFilter(struct adapter *adapter) +{ + PidSetStream1PID(adapter, 0x1FFF); + + PidSetStream2PID(adapter, 0x1FFF); + FilterEnableStream2Filter(adapter, 0); + + PidSetPcrPID(adapter, 0x1FFF); + FilterEnablePcrFilter(adapter, 0); + + PidSetPmtPID(adapter, 0x1FFF); + FilterEnablePmtFilter(adapter, 0); + + PidSetEcmPID(adapter, 0x1FFF); + FilterEnableEcmFilter(adapter, 0); + + PidSetEmmPID(adapter, 0x1FFF); + FilterEnableEmmFilter(adapter, 0); +} +*/ + +static void OpenWholeBandwidth(struct adapter *adapter) +{ + PidSetGroupPID(adapter, 0); + + PidSetGroupMASK(adapter, 0); + + FilterEnableMaskFilter(adapter, 1); +} + +static int AddHwPID(struct adapter *adapter, u32 pid) +{ + dprintk("%s: pid=%d\n", __FUNCTION__, pid); + + if (pid <= 0x1F) + return 1; + + if ((PidGetGroupMASK(adapter) == 0) && (PidGetGroupPID(adapter) == 0)) + return 0; + + if (PidGetStream1PID(adapter) == 0x1FFF) { + PidSetStream1PID(adapter, pid & 0xFFFF); + + FilterEnableStream1Filter(adapter, 1); + + return 1; + } + + if (PidGetStream2PID(adapter) == 0x1FFF) { + PidSetStream2PID(adapter, (pid & 0xFFFF)); + + FilterEnableStream2Filter(adapter, 1); + + return 1; + } + + if (PidGetPcrPID(adapter) == 0x1FFF) { + PidSetPcrPID(adapter, (pid & 0xFFFF)); + + FilterEnablePcrFilter(adapter, 1); + + return 1; + } + + if ((PidGetPmtPID(adapter) & 0x1FFF) == 0x1FFF) { + PidSetPmtPID(adapter, (pid & 0xFFFF)); + + FilterEnablePmtFilter(adapter, 1); + + return 1; + } + + if ((PidGetEmmPID(adapter) & 0x1FFF) == 0x1FFF) { + PidSetEmmPID(adapter, (pid & 0xFFFF)); + + FilterEnableEmmFilter(adapter, 1); + + return 1; + } + + if ((PidGetEcmPID(adapter) & 0x1FFF) == 0x1FFF) { + PidSetEcmPID(adapter, (pid & 0xFFFF)); + + FilterEnableEcmFilter(adapter, 1); + + return 1; + } + + return -1; +} + +static int RemoveHwPID(struct adapter *adapter, u32 pid) +{ + dprintk("%s: pid=%d\n", __FUNCTION__, pid); + + if (pid <= 0x1F) + return 1; + + if (PidGetStream1PID(adapter) == pid) { + PidSetStream1PID(adapter, 0x1FFF); + + return 1; + } + + if (PidGetStream2PID(adapter) == pid) { + PidSetStream2PID(adapter, 0x1FFF); + + FilterEnableStream2Filter(adapter, 0); + + return 1; + } + + if (PidGetPcrPID(adapter) == pid) { + PidSetPcrPID(adapter, 0x1FFF); + + FilterEnablePcrFilter(adapter, 0); + + return 1; + } + + if (PidGetPmtPID(adapter) == pid) { + PidSetPmtPID(adapter, 0x1FFF); + + FilterEnablePmtFilter(adapter, 0); + + return 1; + } + + if (PidGetEmmPID(adapter) == pid) { + PidSetEmmPID(adapter, 0x1FFF); + + FilterEnableEmmFilter(adapter, 0); + + return 1; + } + + if (PidGetEcmPID(adapter) == pid) { + PidSetEcmPID(adapter, 0x1FFF); + + FilterEnableEcmFilter(adapter, 0); + + return 1; + } + + return -1; +} + +static int AddPID(struct adapter *adapter, u32 pid) +{ + int i; + + dprintk("%s: pid=%d\n", __FUNCTION__, pid); + + if (pid > 0x1FFE) + return -1; + + if (CheckPID(adapter, pid) == 1) + return 1; + + for (i = 0; i < 0x27; i++) { + if (adapter->pids[i] == 0x1FFF) // find free pid filter + { + adapter->pids[i] = pid; + + if (AddHwPID(adapter, pid) < 0) + OpenWholeBandwidth(adapter); + + return 1; + } + } + + return -1; +} + +static int RemovePID(struct adapter *adapter, u32 pid) +{ + u32 i; + + dprintk("%s: pid=%d\n", __FUNCTION__, pid); + + if (pid > 0x1FFE) + return -1; + + for (i = 0; i < 0x27; i++) { + if (adapter->pids[i] == pid) { + adapter->pids[i] = 0x1FFF; + + RemoveHwPID(adapter, pid); + + return 1; + } + } + + return -1; +} + +/* dma & irq */ +static void CtrlEnableSmc(struct adapter *adapter, u32 op) +{ + if (op == 0) { + WriteRegOp(adapter, 0x208, 2, ~0x00000800, 0); + + } else { + + WriteRegOp(adapter, 0x208, 1, 0, 0x00000800); + } +} + +static void DmaEnableDisableIrq(struct adapter *adapter, u32 flag1, u32 flag2, u32 flag3) +{ + adapter->dma_ctrl = adapter->dma_ctrl & 0x000F0000; + + if (flag1 == 0) { + if (flag2 == 0) + adapter->dma_ctrl = adapter->dma_ctrl & ~0x00010000; + else + adapter->dma_ctrl = adapter->dma_ctrl | 0x00010000; + + if (flag3 == 0) + adapter->dma_ctrl = adapter->dma_ctrl & ~0x00020000; + else + adapter->dma_ctrl = adapter->dma_ctrl | 0x00020000; + + } else { + + if (flag2 == 0) + adapter->dma_ctrl = adapter->dma_ctrl & ~0x00040000; + else + adapter->dma_ctrl = adapter->dma_ctrl | 0x00040000; + + if (flag3 == 0) + adapter->dma_ctrl = adapter->dma_ctrl & ~0x00080000; + else + adapter->dma_ctrl = adapter->dma_ctrl | 0x00080000; + } +} + +static void IrqDmaEnableDisableIrq(struct adapter * adapter, u32 op) +{ + u32 value; + + value = ReadRegDW(adapter, 0x208) & 0xFFF0FFFF; + + if (op != 0) + value = value | (adapter->dma_ctrl & 0x000F0000); + + WriteRegDW(adapter, 0x208, value); +} + +/* FlexCopII has 2 dma channels. DMA1 is used to transfer TS data to + system memory. + + The DMA1 buffer is divided in 2 subbuffers of equal size. + FlexCopII will transfer TS data to one subbuffer, signal an interrupt + when the subbuffer is full and continue fillig the second subbuffer. + + For DMA1: + subbuffer size in 32-bit words is stored in the first 24 bits of + register 0x004. The last 8 bits of register 0x004 contain the number + of subbuffers. + + the first 30 bits of register 0x000 contain the address of the first + subbuffer. The last 2 bits contain 0, when dma1 is disabled and 1, + when dma1 is enabled. + + the first 30 bits of register 0x00C contain the address of the second + subbuffer. the last 2 bits contain 1. + + register 0x008 will contain the address of the subbuffer that was filled + with TS data, when FlexCopII will generate an interrupt. + + For DMA2: + subbuffer size in 32-bit words is stored in the first 24 bits of + register 0x014. The last 8 bits of register 0x014 contain the number + of subbuffers. + + the first 30 bits of register 0x010 contain the address of the first + subbuffer. The last 2 bits contain 0, when dma1 is disabled and 1, + when dma1 is enabled. + + the first 30 bits of register 0x01C contain the address of the second + subbuffer. the last 2 bits contain 1. + + register 0x018 contains the address of the subbuffer that was filled + with TS data, when FlexCopII generates an interrupt. +*/ +static int DmaInitDMA(struct adapter *adapter, u32 dma_channel) +{ + u32 subbuffers, subbufsize, subbuf0, subbuf1; + + if (dma_channel == 0) { + dprintk("%s: Initializing DMA1 channel\n", __FUNCTION__); + + subbuffers = 2; + + subbufsize = (((adapter->dmaq1.buffer_size / 2) / 4) << 8) | subbuffers; + + subbuf0 = adapter->dmaq1.bus_addr & 0xFFFFFFFC; + + subbuf1 = ((adapter->dmaq1.bus_addr + adapter->dmaq1.buffer_size / 2) & 0xFFFFFFFC) | 1; + + dprintk("%s: first subbuffer address = 0x%x\n", __FUNCTION__, subbuf0); + udelay(1000); + WriteRegDW(adapter, 0x000, subbuf0); + + dprintk("%s: subbuffer size = 0x%x\n", __FUNCTION__, (subbufsize >> 8) * 4); + udelay(1000); + WriteRegDW(adapter, 0x004, subbufsize); + + dprintk("%s: second subbuffer address = 0x%x\n", __FUNCTION__, subbuf1); + udelay(1000); + WriteRegDW(adapter, 0x00C, subbuf1); + + dprintk("%s: counter = 0x%x\n", __FUNCTION__, adapter->dmaq1.bus_addr & 0xFFFFFFFC); + WriteRegDW(adapter, 0x008, adapter->dmaq1.bus_addr & 0xFFFFFFFC); + udelay(1000); + + if (subbuffers == 0) + DmaEnableDisableIrq(adapter, 0, 1, 0); + else + DmaEnableDisableIrq(adapter, 0, 1, 1); + + IrqDmaEnableDisableIrq(adapter, 1); + + SRAMSetMediaDest(adapter, 1); + SRAMSetNetDest(adapter, 1); + SRAMSetCaiDest(adapter, 2); + SRAMSetCaoDest(adapter, 2); + } + + if (dma_channel == 1) { + dprintk("%s: Initializing DMA2 channel\n", __FUNCTION__); + + subbuffers = 2; + + subbufsize = (((adapter->dmaq2.buffer_size / 2) / 4) << 8) | subbuffers; + + subbuf0 = adapter->dmaq2.bus_addr & 0xFFFFFFFC; + + subbuf1 = ((adapter->dmaq2.bus_addr + adapter->dmaq2.buffer_size / 2) & 0xFFFFFFFC) | 1; + + dprintk("%s: first subbuffer address = 0x%x\n", __FUNCTION__, subbuf0); + udelay(1000); + WriteRegDW(adapter, 0x010, subbuf0); + + dprintk("%s: subbuffer size = 0x%x\n", __FUNCTION__, (subbufsize >> 8) * 4); + udelay(1000); + WriteRegDW(adapter, 0x014, subbufsize); + + dprintk("%s: second buffer address = 0x%x\n", __FUNCTION__, subbuf1); + udelay(1000); + WriteRegDW(adapter, 0x01C, subbuf1); + + SRAMSetCaiDest(adapter, 2); + } + + return 0; +} + +static void CtrlEnableReceiveData(struct adapter *adapter, u32 op) +{ + if (op == 0) { + WriteRegOp(adapter, 0x208, 2, ~0x00008000, 0); + + adapter->dma_status = adapter->dma_status & ~0x00000004; + + } else { + + WriteRegOp(adapter, 0x208, 1, 0, 0x00008000); + + adapter->dma_status = adapter->dma_status | 0x00000004; + } +} + +/* bit 0 of dma_mask is set to 1 if dma1 channel has to be enabled/disabled + bit 1 of dma_mask is set to 1 if dma2 channel has to be enabled/disabled +*/ +static void DmaStartStop0x2102(struct adapter *adapter, u32 dma_mask, u32 start_stop) +{ + u32 dma_enable, dma1_enable, dma2_enable; + + dprintk("%s: dma_mask=%x\n", __FUNCTION__, dma_mask); + + if (start_stop == 1) { + dprintk("%s: starting dma\n", __FUNCTION__); + + dma1_enable = 0; + dma2_enable = 0; + + if (((dma_mask & 1) != 0) && ((adapter->dma_status & 1) == 0) && (adapter->dmaq1.bus_addr != 0)) { + adapter->dma_status = adapter->dma_status | 1; + dma1_enable = 1; + } + + if (((dma_mask & 2) != 0) && ((adapter->dma_status & 2) == 0) && (adapter->dmaq2.bus_addr != 0)) { + adapter->dma_status = adapter->dma_status | 2; + dma2_enable = 1; + } + // enable dma1 and dma2 + if ((dma1_enable == 1) && (dma2_enable == 1)) { + WriteRegDW(adapter, 0x000, adapter->dmaq1.bus_addr | 1); + WriteRegDW(adapter, 0x00C, (adapter->dmaq1.bus_addr + adapter->dmaq1.buffer_size / 2) | 1); + WriteRegDW(adapter, 0x010, adapter->dmaq2.bus_addr | 1); + + CtrlEnableReceiveData(adapter, 1); + + return; + } + // enable dma1 + if ((dma1_enable == 1) && (dma2_enable == 0)) { + WriteRegDW(adapter, 0x000, adapter->dmaq1.bus_addr | 1); + WriteRegDW(adapter, 0x00C, (adapter->dmaq1.bus_addr + adapter->dmaq1.buffer_size / 2) | 1); + + CtrlEnableReceiveData(adapter, 1); + + return; + } + // enable dma2 + if ((dma1_enable == 0) && (dma2_enable == 1)) { + WriteRegDW(adapter, 0x010, adapter->dmaq2.bus_addr | 1); + + CtrlEnableReceiveData(adapter, 1); + + return; + } + // start dma + if ((dma1_enable == 0) && (dma2_enable == 0)) { + CtrlEnableReceiveData(adapter, 1); + + return; + } + + } else { + + dprintk("%s: stoping dma\n", __FUNCTION__); + + dma_enable = adapter->dma_status & 0x00000003; + + if (((dma_mask & 1) != 0) && ((adapter->dma_status & 1) != 0)) { + dma_enable = dma_enable & 0xFFFFFFFE; + } + + if (((dma_mask & 2) != 0) && ((adapter->dma_status & 2) != 0)) { + dma_enable = dma_enable & 0xFFFFFFFD; + } + //stop dma + if ((dma_enable == 0) && ((adapter->dma_status & 4) != 0)) { + CtrlEnableReceiveData(adapter, 0); + + udelay(3000); + } + //disable dma1 + if (((dma_mask & 1) != 0) && ((adapter->dma_status & 1) != 0) && (adapter->dmaq1.bus_addr != 0)) { + WriteRegDW(adapter, 0x000, adapter->dmaq1.bus_addr); + WriteRegDW(adapter, 0x00C, (adapter->dmaq1.bus_addr + adapter->dmaq1.buffer_size / 2) | 1); + + adapter->dma_status = adapter->dma_status & ~0x00000001; + } + //disable dma2 + if (((dma_mask & 2) != 0) && ((adapter->dma_status & 2) != 0) && (adapter->dmaq2.bus_addr != 0)) { + WriteRegDW(adapter, 0x010, adapter->dmaq2.bus_addr); + + adapter->dma_status = adapter->dma_status & ~0x00000002; + } + } +} + +static void OpenStream(struct adapter *adapter, u32 pid) +{ + u32 dma_mask; + + if (adapter->capturing == 0) + adapter->capturing = 1; + + FilterEnableMaskFilter(adapter, 1); + + AddPID(adapter, pid); + + dprintk("%s: adapter->dma_status=%x\n", __FUNCTION__, adapter->dma_status); + + if ((adapter->dma_status & 7) != 7) { + dma_mask = 0; + + if (((adapter->dma_status & 0x10000000) != 0) && ((adapter->dma_status & 1) == 0)) { + dma_mask = dma_mask | 1; + + adapter->dmaq1.head = 0; + adapter->dmaq1.tail = 0; + + memset(adapter->dmaq1.buffer, 0, adapter->dmaq1.buffer_size); + } + + if (((adapter->dma_status & 0x20000000) != 0) && ((adapter->dma_status & 2) == 0)) { + dma_mask = dma_mask | 2; + + adapter->dmaq2.head = 0; + adapter->dmaq2.tail = 0; + } + + if (dma_mask != 0) { + IrqDmaEnableDisableIrq(adapter, 1); + + DmaStartStop0x2102(adapter, dma_mask, 1); + } + } +} + +static void CloseStream(struct adapter *adapter, u32 pid) +{ + u32 dma_mask; + + if (adapter->capturing != 0) + adapter->capturing = 0; + + dprintk("%s: dma_status=%x\n", __FUNCTION__, adapter->dma_status); + + dma_mask = 0; + + if ((adapter->dma_status & 1) != 0) + dma_mask = dma_mask | 0x00000001; + if ((adapter->dma_status & 2) != 0) + dma_mask = dma_mask | 0x00000002; + + if (dma_mask != 0) { + DmaStartStop0x2102(adapter, dma_mask, 0); + } + + RemovePID(adapter, pid); +} + +static void InterruptServiceDMA1(struct adapter *adapter) +{ + struct dvb_demux *dvbdmx = &adapter->demux; + struct packet_header packet_header; + + int nCurDmaCounter; + u32 nNumBytesParsed; + u32 nNumNewBytesTransferred; + u32 dwDefaultPacketSize = 188; + u8 gbTmpBuffer[188]; + u8 *pbDMABufCurPos; + + nCurDmaCounter = readl(adapter->io_mem + 0x008) - adapter->dmaq1.bus_addr; + nCurDmaCounter = (nCurDmaCounter / dwDefaultPacketSize) * dwDefaultPacketSize; + + if ((nCurDmaCounter < 0) || (nCurDmaCounter > adapter->dmaq1.buffer_size)) { + dprintk("%s: dma counter outside dma buffer\n", __FUNCTION__); + return; + } + + adapter->dmaq1.head = nCurDmaCounter; + + if (adapter->dmaq1.tail <= nCurDmaCounter) { + nNumNewBytesTransferred = nCurDmaCounter - adapter->dmaq1.tail; + + } else { + + nNumNewBytesTransferred = (adapter->dmaq1.buffer_size - adapter->dmaq1.tail) + nCurDmaCounter; + } + +// dprintk("%s: nCurDmaCounter = %d\n" , __FUNCTION__, nCurDmaCounter); +// dprintk("%s: dmaq1.tail = %d\n" , __FUNCTION__, adapter->dmaq1.tail): +// dprintk("%s: BytesTransferred = %d\n" , __FUNCTION__, nNumNewBytesTransferred); + + if (nNumNewBytesTransferred < dwDefaultPacketSize) + return; + + nNumBytesParsed = 0; + + while (nNumBytesParsed < nNumNewBytesTransferred) { + pbDMABufCurPos = adapter->dmaq1.buffer + adapter->dmaq1.tail; + + if (adapter->dmaq1.buffer + adapter->dmaq1.buffer_size < adapter->dmaq1.buffer + adapter->dmaq1.tail + 188) { + memcpy(gbTmpBuffer, adapter->dmaq1.buffer + adapter->dmaq1.tail, adapter->dmaq1.buffer_size - adapter->dmaq1.tail); + memcpy(gbTmpBuffer + (adapter->dmaq1.buffer_size - adapter->dmaq1.tail), adapter->dmaq1.buffer, (188 - (adapter->dmaq1.buffer_size - adapter->dmaq1.tail))); + + pbDMABufCurPos = gbTmpBuffer; + } + + if (adapter->capturing != 0) { + u32 *dq = (u32 *) pbDMABufCurPos; + + packet_header.sync_byte = *dq & 0x000000FF; + packet_header.transport_error_indicator = *dq & 0x00008000; + packet_header.payload_unit_start_indicator = *dq & 0x00004000; + packet_header.transport_priority = *dq & 0x00002000; + packet_header.pid = ((*dq & 0x00FF0000) >> 0x10) | (*dq & 0x00001F00); + packet_header.transport_scrambling_control = *dq >> 0x1E; + packet_header.adaptation_field_control = (*dq & 0x30000000) >> 0x1C; + packet_header.continuity_counter = (*dq & 0x0F000000) >> 0x18; + + if ((packet_header.sync_byte == 0x47) && (packet_header.transport_error_indicator == 0) && (packet_header.pid != 0x1FFF)) { + if (CheckPID(adapter, packet_header.pid & 0x0000FFFF) != 0) { + dvb_dmx_swfilter_packets(dvbdmx, pbDMABufCurPos, dwDefaultPacketSize / 188); + + } else { + +// dprintk("%s: pid=%x\n", __FUNCTION__, packet_header.pid); + } + } + } + + nNumBytesParsed = nNumBytesParsed + dwDefaultPacketSize; + + adapter->dmaq1.tail = adapter->dmaq1.tail + dwDefaultPacketSize; + + if (adapter->dmaq1.tail >= adapter->dmaq1.buffer_size) + adapter->dmaq1.tail = adapter->dmaq1.tail - adapter->dmaq1.buffer_size; + }; +} + +static void InterruptServiceDMA2(struct adapter *adapter) +{ + printk("%s:\n", __FUNCTION__); +} + +static irqreturn_t isr(int irq, void *dev_id, struct pt_regs *regs) +{ + struct adapter *tmp = dev_id; + + u32 value; + +// dprintk("%s:\n", __FUNCTION__); + + spin_lock_irq(&tmp->lock); + + if (0 == ((value = ReadRegDW(tmp, 0x20C)) & 0x0F)) { + spin_unlock_irq(&tmp->lock); + return IRQ_NONE; + } + + while (value != 0) { + if ((value & 0x03) != 0) + InterruptServiceDMA1(tmp); + if ((value & 0x0C) != 0) + InterruptServiceDMA2(tmp); + value = ReadRegDW(tmp, 0x20C) & 0x0F; + } + + spin_unlock_irq(&tmp->lock); + return IRQ_HANDLED; +} + +static void Initdmaqueue(struct adapter *adapter) +{ + dma_addr_t dma_addr; + + if (adapter->dmaq1.buffer != 0) + return; + + adapter->dmaq1.head = 0; + adapter->dmaq1.tail = 0; + adapter->dmaq1.buffer = 0; + + adapter->dmaq1.buffer = pci_alloc_consistent(adapter->pdev, SizeOfBufDMA1 + 0x80, &dma_addr); + + if (adapter->dmaq1.buffer != 0) { + memset(adapter->dmaq1.buffer, 0, SizeOfBufDMA1); + + adapter->dmaq1.bus_addr = dma_addr; + adapter->dmaq1.buffer_size = SizeOfBufDMA1; + + DmaInitDMA(adapter, 0); + + adapter->dma_status = adapter->dma_status | 0x10000000; + + dprintk("%s: allocated dma buffer at 0x%x, length=%d\n", __FUNCTION__, (int) adapter->dmaq1.buffer, SizeOfBufDMA1); + + } else { + + adapter->dma_status = adapter->dma_status & ~0x10000000; + } + + if (adapter->dmaq2.buffer != 0) + return; + + adapter->dmaq2.head = 0; + adapter->dmaq2.tail = 0; + adapter->dmaq2.buffer = 0; + + adapter->dmaq2.buffer = pci_alloc_consistent(adapter->pdev, SizeOfBufDMA2 + 0x80, &dma_addr); + + if (adapter->dmaq2.buffer != 0) { + memset(adapter->dmaq2.buffer, 0, SizeOfBufDMA2); + + adapter->dmaq2.bus_addr = dma_addr; + adapter->dmaq2.buffer_size = SizeOfBufDMA2; + + DmaInitDMA(adapter, 1); + + adapter->dma_status = adapter->dma_status | 0x20000000; + + dprintk("%s: allocated dma buffer at 0x%x, length=%d\n", __FUNCTION__, (int) adapter->dmaq2.buffer, (int) SizeOfBufDMA2); + + } else { + + adapter->dma_status = adapter->dma_status & ~0x20000000; + } +} + +static void Freedmaqueue(struct adapter *adapter) +{ + if (adapter->dmaq1.buffer != 0) { + pci_free_consistent(adapter->pdev, SizeOfBufDMA1 + 0x80, adapter->dmaq1.buffer, adapter->dmaq1.bus_addr); + + adapter->dmaq1.bus_addr = 0; + adapter->dmaq1.head = 0; + adapter->dmaq1.tail = 0; + adapter->dmaq1.buffer_size = 0; + adapter->dmaq1.buffer = 0; + } + + if (adapter->dmaq2.buffer != 0) { + pci_free_consistent(adapter->pdev, SizeOfBufDMA2 + 0x80, adapter->dmaq2.buffer, adapter->dmaq2.bus_addr); + + adapter->dmaq2.bus_addr = 0; + adapter->dmaq2.head = 0; + adapter->dmaq2.tail = 0; + adapter->dmaq2.buffer_size = 0; + adapter->dmaq2.buffer = 0; + } +} + +static void FreeAdapterObject(struct adapter *adapter) +{ + dprintk("%s:\n", __FUNCTION__); + + CloseStream(adapter, 0); + + if (adapter->irq != 0) + free_irq(adapter->irq, adapter); + + Freedmaqueue(adapter); + + if (adapter->io_mem != 0) + iounmap((void *) adapter->io_mem); + + if (adapter != 0) + kfree(adapter); +} + +static struct pci_driver skystar2_pci_driver; + +static int ClaimAdapter(struct adapter *adapter) +{ + struct pci_dev *pdev = adapter->pdev; + + u16 var; + + if (!request_region(pci_resource_start(pdev, 1), pci_resource_len(pdev, 1), skystar2_pci_driver.name)) + return -EBUSY; + + if (!request_mem_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0), skystar2_pci_driver.name)) + return -EBUSY; + + pci_read_config_byte(pdev, PCI_CLASS_REVISION, &adapter->card_revision); + + dprintk("%s: card revision %x \n", __FUNCTION__, adapter->card_revision); + + if (pci_enable_device(pdev)) + return -EIO; + + pci_read_config_word(pdev, 4, &var); + + if ((var & 4) == 0) + pci_set_master(pdev); + + adapter->io_port = pdev->resource[1].start; + + adapter->io_mem = (u32) ioremap(pdev->resource[0].start, 0x800); + + if (adapter->io_mem == 0) { + dprintk("%s: can not map io memory\n", __FUNCTION__); + + return 2; + } + + dprintk("%s: io memory maped at %x\n", __FUNCTION__, adapter->io_mem); + + return 1; +} + +/* +static int SLL_reset_FlexCOP(struct adapter *adapter) +{ + WriteRegDW(adapter, 0x208, 0); + WriteRegDW(adapter, 0x210, 0xB2FF); + + return 0; +} +*/ + +static int DriverInitialize(struct pci_dev * pdev) +{ + struct adapter *adapter; + u32 tmp; + u8 key[16]; + + if (!(adapter = kmalloc(sizeof(struct adapter), GFP_KERNEL))) { + dprintk("%s: out of memory!\n", __FUNCTION__); + + return -ENOMEM; + } + + memset(adapter, 0, sizeof(struct adapter)); + + pci_set_drvdata(pdev,adapter); + + adapter->pdev = pdev; + adapter->irq = pdev->irq; + + if ((ClaimAdapter(adapter)) != 1) { + FreeAdapterObject(adapter); + + return -ENODEV; + } + + IrqDmaEnableDisableIrq(adapter, 0); + + if (request_irq(pdev->irq, isr, 0x4000000, "Skystar2", adapter) != 0) { + dprintk("%s: unable to allocate irq=%d !\n", __FUNCTION__, pdev->irq); + + FreeAdapterObject(adapter); + + return -ENODEV; + } + + ReadRegDW(adapter, 0x208); + WriteRegDW(adapter, 0x208, 0); + WriteRegDW(adapter, 0x210, 0xB2FF); + WriteRegDW(adapter, 0x208, 0x40); + + InitPIDsInfo(adapter); + + PidSetGroupPID(adapter, 0); + PidSetGroupMASK(adapter, 0x1FE0); + PidSetStream1PID(adapter, 0x1FFF); + PidSetStream2PID(adapter, 0x1FFF); + PidSetPmtPID(adapter, 0x1FFF); + PidSetPcrPID(adapter, 0x1FFF); + PidSetEcmPID(adapter, 0x1FFF); + PidSetEmmPID(adapter, 0x1FFF); + + Initdmaqueue(adapter); + + if ((adapter->dma_status & 0x30000000) == 0) { + FreeAdapterObject(adapter); + + return -ENODEV; + } + + adapter->b2c2_revision = (ReadRegDW(adapter, 0x204) >> 0x18); + + if ((adapter->b2c2_revision != 0x82) && (adapter->b2c2_revision != 0xC3)) + if (adapter->b2c2_revision != 0x82) { + dprintk("%s: The revision of the FlexCopII chip on your card is - %d\n", __FUNCTION__, adapter->b2c2_revision); + dprintk("%s: This driver works now only with FlexCopII(rev.130) and FlexCopIIB(rev.195).\n", __FUNCTION__); + + FreeAdapterObject(adapter); + + return -ENODEV; + } + + tmp = ReadRegDW(adapter, 0x204); + + WriteRegDW(adapter, 0x204, 0); + mdelay(20); + + WriteRegDW(adapter, 0x204, tmp); + mdelay(10); + + tmp = ReadRegDW(adapter, 0x308); + WriteRegDW(adapter, 0x308, 0x4000 | tmp); + + adapter->dwSramType = 0x10000; + + SLL_detectSramSize(adapter); + + dprintk("%s sram length = %d, sram type= %x\n", __FUNCTION__, SRAM_length(adapter), adapter->dwSramType); + + SRAMSetMediaDest(adapter, 1); + SRAMSetNetDest(adapter, 1); + + CtrlEnableSmc(adapter, 0); + + SRAMSetCaiDest(adapter, 2); + SRAMSetCaoDest(adapter, 2); + + DmaEnableDisableIrq(adapter, 1, 0, 0); + + if (EEPROM_getMacAddr(adapter, 0, adapter->mac_addr) != 0) { + printk("%s MAC address = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x \n", __FUNCTION__, adapter->mac_addr[0], adapter->mac_addr[1], adapter->mac_addr[2], adapter->mac_addr[3], adapter->mac_addr[4], adapter->mac_addr[5], adapter->mac_addr[6], adapter->mac_addr[7] + ); + + CASetMacDstAddrFilter(adapter, adapter->mac_addr); + CtrlEnableMAC(adapter, 1); + } + + EEPROM_readKey(adapter, key, 16); + + printk("%s key = \n %02x %02x %02x %02x \n %02x %02x %02x %02x \n %02x %02x %02x %02x \n %02x %02x %02x %02x \n", __FUNCTION__, key[0], key[1], key[2], key[3], key[4], key[5], key[6], key[7], key[8], key[9], key[10], key[11], key[12], key[13], key[14], key[15]); + + adapter->lock = SPIN_LOCK_UNLOCKED; + + return 0; +} + +static void DriverHalt(struct pci_dev *pdev) +{ + struct adapter *adapter; + + adapter = pci_get_drvdata(pdev); + + IrqDmaEnableDisableIrq(adapter, 0); + + CtrlEnableReceiveData(adapter, 0); + + FreeAdapterObject(adapter); + + pci_set_drvdata(pdev, NULL); + + release_region(pci_resource_start(pdev, 1), pci_resource_len(pdev, 1)); + + release_mem_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); +} + +static int dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + struct dvb_demux *dvbdmx = dvbdmxfeed->demux; + struct adapter *adapter = (struct adapter *) dvbdmx->priv; + + dprintk("%s: PID=%d, type=%d\n", __FUNCTION__, dvbdmxfeed->pid, dvbdmxfeed->type); + + OpenStream(adapter, dvbdmxfeed->pid); + + return 0; +} + +static int dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + struct dvb_demux *dvbdmx = dvbdmxfeed->demux; + struct adapter *adapter = (struct adapter *) dvbdmx->priv; + + dprintk("%s: PID=%d, type=%d\n", __FUNCTION__, dvbdmxfeed->pid, dvbdmxfeed->type); + + CloseStream(adapter, dvbdmxfeed->pid); + + return 0; +} + +/* lnb control */ +static void set_tuner_tone(struct adapter *adapter, u8 tone) +{ + u16 wzHalfPeriodFor45MHz[] = { 0x01FF, 0x0154, 0x00FF, 0x00CC }; + u16 ax; + + dprintk("%s: %u\n", __FUNCTION__, tone); + + switch (tone) { + case 1: + ax = wzHalfPeriodFor45MHz[0]; + break; + case 2: + ax = wzHalfPeriodFor45MHz[1]; + break; + case 3: + ax = wzHalfPeriodFor45MHz[2]; + break; + case 4: + ax = wzHalfPeriodFor45MHz[3]; + break; + + default: + ax = 0; + } + + if (ax != 0) { + WriteRegDW(adapter, 0x200, ((ax << 0x0F) + (ax & 0x7FFF)) | 0x40000000); + + } else { + + WriteRegDW(adapter, 0x200, 0x40FF8000); + } +} + +static void set_tuner_polarity(struct adapter *adapter, u8 polarity) +{ + u32 var; + + dprintk("%s : polarity = %u \n", __FUNCTION__, polarity); + + var = ReadRegDW(adapter, 0x204); + + if (polarity == 0) { + dprintk("%s: LNB power off\n", __FUNCTION__); + var = var | 1; + }; + + if (polarity == 1) { + var = var & ~1; + var = var & ~4; + }; + + if (polarity == 2) { + var = var & ~1; + var = var | 4; + } + + WriteRegDW(adapter, 0x204, var); +} + +static int flexcop_diseqc_ioctl(struct dvb_frontend *fe, unsigned int cmd, void *arg) +{ + struct adapter *adapter = fe->before_after_data; + + switch (cmd) { + case FE_SLEEP: + { + printk("%s: FE_SLEEP\n", __FUNCTION__); + + set_tuner_polarity(adapter, 0); + + // return -EOPNOTSUPP, to make DVB core also send "FE_SLEEP" command to frontend. + return -EOPNOTSUPP; + } + + case FE_SET_VOLTAGE: + { + dprintk("%s: FE_SET_VOLTAGE\n", __FUNCTION__); + + switch ((fe_sec_voltage_t) arg) { + case SEC_VOLTAGE_13: + + printk("%s: SEC_VOLTAGE_13, %x\n", __FUNCTION__, SEC_VOLTAGE_13); + + set_tuner_polarity(adapter, 1); + + break; + + case SEC_VOLTAGE_18: + + printk("%s: SEC_VOLTAGE_18, %x\n", __FUNCTION__, SEC_VOLTAGE_18); + + set_tuner_polarity(adapter, 2); + + break; + + default: + + return -EINVAL; + }; + + break; + } + + case FE_SET_TONE: + { + dprintk("%s: FE_SET_TONE\n", __FUNCTION__); + + switch ((fe_sec_tone_mode_t) arg) { + case SEC_TONE_ON: + + printk("%s: SEC_TONE_ON, %x\n", __FUNCTION__, SEC_TONE_ON); + + set_tuner_tone(adapter, 1); + + break; + + case SEC_TONE_OFF: + + printk("%s: SEC_TONE_OFF, %x\n", __FUNCTION__, SEC_TONE_OFF); + + set_tuner_tone(adapter, 0); + + break; + + default: + + return -EINVAL; + }; + + break; + } + + default: + + return -EOPNOTSUPP; + }; + + return 0; +} + +static int skystar2_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + struct adapter *adapter; + struct dvb_adapter *dvb_adapter; + struct dvb_demux *dvbdemux; + + int ret; + + if (pdev == NULL) + return -ENODEV; + + if (DriverInitialize(pdev) != 0) + return -ENODEV; + + dvb_register_adapter(&dvb_adapter, skystar2_pci_driver.name); + + if (dvb_adapter == NULL) { + printk("%s: Error registering DVB adapter\n", __FUNCTION__); + + DriverHalt(pdev); + + return -ENODEV; + } + + adapter = (struct adapter *) pci_get_drvdata(pdev); + + adapter->dvb_adapter = dvb_adapter; + + init_MUTEX(&adapter->i2c_sem); + + adapter->i2c_bus = dvb_register_i2c_bus(master_xfer, adapter, adapter->dvb_adapter, 0); + + if (!adapter->i2c_bus) + return -ENOMEM; + + dvb_add_frontend_ioctls(adapter->dvb_adapter, flexcop_diseqc_ioctl, NULL, adapter); + + dvbdemux = &adapter->demux; + + dvbdemux->priv = (void *) adapter; + dvbdemux->filternum = 32; + dvbdemux->feednum = 32; + dvbdemux->start_feed = dvb_start_feed; + dvbdemux->stop_feed = dvb_stop_feed; + dvbdemux->write_to_decoder = 0; + dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING); + + dvb_dmx_init(&adapter->demux); + + adapter->hw_frontend.source = DMX_FRONTEND_0; + + adapter->dmxdev.filternum = 32; + adapter->dmxdev.demux = &dvbdemux->dmx; + adapter->dmxdev.capabilities = 0; + + dvb_dmxdev_init(&adapter->dmxdev, adapter->dvb_adapter); + + ret = dvbdemux->dmx.add_frontend(&dvbdemux->dmx, &adapter->hw_frontend); + if (ret < 0) + return ret; + + adapter->mem_frontend.source = DMX_MEMORY_FE; + + ret = dvbdemux->dmx.add_frontend(&dvbdemux->dmx, &adapter->mem_frontend); + if (ret < 0) + return ret; + + ret = dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, &adapter->hw_frontend); + if (ret < 0) + return ret; + + dvb_net_init(adapter->dvb_adapter, &adapter->dvbnet, &dvbdemux->dmx); + return 0; +} + +static void skystar2_remove(struct pci_dev *pdev) +{ + struct adapter *adapter; + struct dvb_demux *dvbdemux; + + if (pdev == NULL) + return; + + adapter = pci_get_drvdata(pdev); + + if (adapter != NULL) { + dvb_net_release(&adapter->dvbnet); + dvbdemux = &adapter->demux; + + dvbdemux->dmx.close(&dvbdemux->dmx); + dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &adapter->hw_frontend); + dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &adapter->mem_frontend); + + dvb_dmxdev_release(&adapter->dmxdev); + dvb_dmx_release(&adapter->demux); + + if (adapter->dvb_adapter != NULL) { + dvb_remove_frontend_ioctls(adapter->dvb_adapter, flexcop_diseqc_ioctl, NULL); + + if (adapter->i2c_bus != NULL) + dvb_unregister_i2c_bus(master_xfer, adapter->i2c_bus->adapter, adapter->i2c_bus->id); + + dvb_unregister_adapter(adapter->dvb_adapter); + } + + DriverHalt(pdev); + } +} + +static struct pci_device_id skystar2_pci_tbl[] = { + {0x000013D0, 0x00002103, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000}, + {0,}, +}; + +static struct pci_driver skystar2_pci_driver = { + .name = "Technisat SkyStar2 driver", + .id_table = skystar2_pci_tbl, + .probe = skystar2_probe, + .remove = skystar2_remove, +}; + +static int skystar2_init(void) +{ + return pci_module_init(&skystar2_pci_driver); +} + +static void skystar2_cleanup(void) +{ + pci_unregister_driver(&skystar2_pci_driver); +} + +module_init(skystar2_init); +module_exit(skystar2_cleanup); + +MODULE_DESCRIPTION("Technisat SkyStar2 DVB PCI Driver"); +MODULE_LICENSE("GPL"); diff -Nru a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c --- a/drivers/media/dvb/dvb-core/dvb_demux.c Sun Jul 27 10:13:42 2003 +++ b/drivers/media/dvb/dvb-core/dvb_demux.c Sun Jul 27 10:13:42 2003 @@ -403,13 +403,16 @@ { int p = 0,i, j; + spin_lock(&demux->lock); + if ((i = demux->tsbufp)) { if (count < (j=188-i)) { memcpy(&demux->tsbuf[i], buf, count); demux->tsbufp += count; - return; + goto bailout; } memcpy(&demux->tsbuf[i], buf, j); + if (demux->tsbuf[0] == 0x47) dvb_dmx_swfilter_packet(demux, demux->tsbuf); demux->tsbufp = 0; p += j; @@ -424,11 +427,14 @@ i = count-p; memcpy(demux->tsbuf, buf+p, i); demux->tsbufp=i; - return; + goto bailout; } } else p++; } + +bailout: + spin_unlock(&demux->lock); } @@ -1030,9 +1036,11 @@ if (down_interruptible (&dvbdemux->mutex)) return -ERESTARTSYS; - dvb_dmx_swfilter(dvbdemux, buf, count); up(&dvbdemux->mutex); + + if (signal_pending(current)) + return -EINTR; return count; } @@ -1110,8 +1118,8 @@ return 0; } -int -dvb_dmx_init(struct dvb_demux *dvbdemux) + +int dvb_dmx_init(struct dvb_demux *dvbdemux) { int i, err; struct dmx_demux *dmx = &dvbdemux->dmx; @@ -1181,8 +1189,8 @@ return 0; } -int -dvb_dmx_release(struct dvb_demux *dvbdemux) + +int dvb_dmx_release(struct dvb_demux *dvbdemux) { struct dmx_demux *dmx = &dvbdemux->dmx; diff -Nru a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c --- a/drivers/media/dvb/dvb-core/dvb_frontend.c Sun Jul 27 10:13:42 2003 +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c Sun Jul 27 10:13:42 2003 @@ -263,8 +263,14 @@ if (flags & O_NONBLOCK) return -EWOULDBLOCK; + up(&fe->sem); + ret = wait_event_interruptible (events->wait_queue, events->eventw != events->eventr); + + if (down_interruptible (&fe->sem)) + return -ERESTARTSYS; + if (ret < 0) return ret; } diff -Nru a/drivers/media/dvb/dvb-core/dvb_functions.c b/drivers/media/dvb/dvb-core/dvb_functions.c --- a/drivers/media/dvb/dvb-core/dvb_functions.c Sun Jul 27 10:13:50 2003 +++ b/drivers/media/dvb/dvb-core/dvb_functions.c Sun Jul 27 10:13:50 2003 @@ -1,11 +1,11 @@ #include -#include -#include -#include #include +#include +#include #include #include #include +#include #include void dvb_kernel_thread_setup (const char *thread_name) diff -Nru a/drivers/media/dvb/dvb-core/dvb_functions.h b/drivers/media/dvb/dvb-core/dvb_functions.h --- a/drivers/media/dvb/dvb-core/dvb_functions.h Sun Jul 27 10:13:46 2003 +++ b/drivers/media/dvb/dvb-core/dvb_functions.h Sun Jul 27 10:13:46 2003 @@ -1,6 +1,8 @@ #ifndef __DVB_FUNCTIONS_H__ #define __DVB_FUNCTIONS_H__ +#include + /** * a sleeping delay function, waits i ms * diff -Nru a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c --- a/drivers/media/dvb/dvb-core/dvb_net.c Sun Jul 27 10:13:42 2003 +++ b/drivers/media/dvb/dvb-core/dvb_net.c Sun Jul 27 10:13:42 2003 @@ -24,22 +24,25 @@ * */ -#include -#include -#include -#include -#include -#include - #include +#include #include "dvb_demux.h" #include "dvb_net.h" #include "dvb_functions.h" + +#if 1 +#define dprintk(x...) printk(x) +#else +#define dprintk(x...) +#endif + + #define DVB_NET_MULTICAST_MAX 10 struct dvb_net_priv { + int in_use; struct net_device_stats stats; char name[6]; u16 pid; @@ -49,10 +52,17 @@ int multi_num; struct dmx_section_filter *multi_secfilter[DVB_NET_MULTICAST_MAX]; unsigned char multi_macs[DVB_NET_MULTICAST_MAX][6]; - int mode; + int rx_mode; +#define RX_MODE_UNI 0 +#define RX_MODE_MULTI 1 +#define RX_MODE_ALL_MULTI 2 +#define RX_MODE_PROMISC 3 + struct work_struct set_multicast_list_wq; + struct work_struct restart_net_feed_wq; }; -/* + +/** * Determine the packet's protocol ID. The rule here is that we * assume 802.3 if the type field is short enough to be a length. * This is normal practice and works for any 'now in use' protocol. @@ -60,8 +70,8 @@ * stolen from eth.c out of the linux kernel, hacked for dvb-device * by Michael Holzt */ - -unsigned short my_eth_type_trans(struct sk_buff *skb, struct net_device *dev) +static unsigned short dvb_net_eth_type_trans(struct sk_buff *skb, + struct net_device *dev) { struct ethhdr *eth; unsigned char *rawp; @@ -70,8 +80,7 @@ skb_pull(skb,dev->hard_header_len); eth= skb->mac.ethernet; - if(*eth->h_dest&1) - { + if (*eth->h_dest & 1) { if(memcmp(eth->h_dest,dev->broadcast, ETH_ALEN)==0) skb->pkt_type=PACKET_BROADCAST; else @@ -83,7 +92,7 @@ rawp = skb->data; - /* + /** * This is a magic hack to spot IPX packets. Older Novell breaks * the protocol design and runs IPX over 802.3 without an 802.2 LLC * layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This @@ -92,42 +101,73 @@ if (*(unsigned short *)rawp == 0xFFFF) return htons(ETH_P_802_3); - /* + /** * Real 802.2 LLC */ return htons(ETH_P_802_2); } -static void dvb_net_sec(struct net_device *dev, const u8 *pkt, int pkt_len) + +static void dvb_net_sec(struct net_device *dev, u8 *pkt, int pkt_len) { u8 *eth; struct sk_buff *skb; - if (pkt_len<13) { - printk("%s: IP/MPE packet length = %d too small.\n", dev->name, pkt_len); + /* note: pkt_len includes a 32bit checksum */ + if (pkt_len < 16) { + printk("%s: IP/MPE packet length = %d too small.\n", + dev->name, pkt_len); + ((struct dvb_net_priv *) dev->priv)->stats.rx_errors++; + ((struct dvb_net_priv *) dev->priv)->stats.rx_length_errors++; + return; + } + if ((pkt[5] & 0xfd) != 0xc1) { + /* drop scrambled or broken packets */ + ((struct dvb_net_priv *) dev->priv)->stats.rx_errors++; + ((struct dvb_net_priv *) dev->priv)->stats.rx_crc_errors++; return; } - skb = dev_alloc_skb(pkt_len+2); - if (skb == NULL) { - printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", - dev->name); + if (pkt[5] & 0x02) { + //FIXME: handle LLC/SNAP ((struct dvb_net_priv *)dev->priv)->stats.rx_dropped++; return; } - eth=(u8 *) skb_put(skb, pkt_len+2); - memcpy(eth+14, (void*)pkt+12, pkt_len-12); + if (pkt[7]) { + /* FIXME: assemble datagram from multiple sections */ + ((struct dvb_net_priv *) dev->priv)->stats.rx_errors++; + ((struct dvb_net_priv *) dev->priv)->stats.rx_frame_errors++; + return; + } + /* we have 14 byte ethernet header (ip header follows); + * 12 byte MPE header; 4 byte checksum; + 2 byte alignment + */ + if (!(skb = dev_alloc_skb(pkt_len - 4 - 12 + 14 + 2))) { + //printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name); + ((struct dvb_net_priv *) dev->priv)->stats.rx_dropped++; + return; + } + skb_reserve(skb, 2); /* longword align L3 header */ + skb->dev = dev; + + /* copy L3 payload */ + eth = (u8 *) skb_put(skb, pkt_len - 12 - 4 + 14); + memcpy(eth + 14, pkt + 12, pkt_len - 12 - 4); + + /* create ethernet header: */ eth[0]=pkt[0x0b]; eth[1]=pkt[0x0a]; eth[2]=pkt[0x09]; eth[3]=pkt[0x08]; eth[4]=pkt[0x04]; eth[5]=pkt[0x03]; + eth[6]=eth[7]=eth[8]=eth[9]=eth[10]=eth[11]=0; - eth[12]=0x08; eth[13]=0x00; - skb->protocol=my_eth_type_trans(skb,dev); - skb->dev=dev; + eth[12] = 0x08; /* ETH_P_IP */ + eth[13] = 0x00; + + skb->protocol = dvb_net_eth_type_trans(skb, dev); ((struct dvb_net_priv *)dev->priv)->stats.rx_packets++; ((struct dvb_net_priv *)dev->priv)->stats.rx_bytes+=skb->len; @@ -141,9 +181,11 @@ { struct net_device *dev=(struct net_device *) filter->priv; - /* FIXME: this only works if exactly one complete section is - delivered in buffer1 only */ - dvb_net_sec(dev, buffer1, buffer1_len); + /** + * we rely on the DVB API definition where exactly one complete + * section is delivered in buffer1 + */ + dvb_net_sec (dev, (u8*) buffer1, buffer1_len); return 0; } @@ -178,24 +220,27 @@ memset((*secfilter)->filter_mode, 0xff, DMX_MAX_FILTER_SIZE); (*secfilter)->filter_value[0]=0x3e; - (*secfilter)->filter_mask[0]=0xff; - (*secfilter)->filter_value[3]=mac[5]; - (*secfilter)->filter_mask[3]=mac_mask[5]; (*secfilter)->filter_value[4]=mac[4]; - (*secfilter)->filter_mask[4]=mac_mask[4]; (*secfilter)->filter_value[8]=mac[3]; - (*secfilter)->filter_mask[8]=mac_mask[3]; (*secfilter)->filter_value[9]=mac[2]; - (*secfilter)->filter_mask[9]=mac_mask[2]; - (*secfilter)->filter_value[10]=mac[1]; - (*secfilter)->filter_mask[10]=mac_mask[1]; (*secfilter)->filter_value[11]=mac[0]; + + (*secfilter)->filter_mask[0] = 0xff; + (*secfilter)->filter_mask[3] = mac_mask[5]; + (*secfilter)->filter_mask[4] = mac_mask[4]; + (*secfilter)->filter_mask[8] = mac_mask[3]; + (*secfilter)->filter_mask[9] = mac_mask[2]; + (*secfilter)->filter_mask[10] = mac_mask[1]; (*secfilter)->filter_mask[11]=mac_mask[0]; - printk("%s: filter mac=%02x %02x %02x %02x %02x %02x\n", + dprintk("%s: filter mac=%02x %02x %02x %02x %02x %02x\n", dev->name, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + dprintk("%s: filter mask=%02x %02x %02x %02x %02x %02x\n", + dev->name, mac_mask[0], mac_mask[1], mac_mask[2], + mac_mask[3], mac_mask[4], mac_mask[5]); + return 0; } @@ -206,46 +251,57 @@ struct dmx_demux *demux = priv->demux; unsigned char *mac = (unsigned char *) dev->dev_addr; + dprintk("%s: rx_mode %i\n", __FUNCTION__, priv->rx_mode); + if (priv->secfeed || priv->secfilter || priv->multi_secfilter[0]) + printk("%s: BUG %d\n", __FUNCTION__, __LINE__); + priv->secfeed=0; priv->secfilter=0; + dprintk("%s: alloc secfeed\n", __FUNCTION__); ret=demux->allocate_section_feed(demux, &priv->secfeed, dvb_net_callback); if (ret<0) { - printk("%s: could not get section feed\n", dev->name); + printk("%s: could not allocate section feed\n", dev->name); return ret; } - ret=priv->secfeed->set(priv->secfeed, priv->pid, 32768, 0, 0); + ret = priv->secfeed->set(priv->secfeed, priv->pid, 32768, 0, 1); + if (ret<0) { printk("%s: could not set section feed\n", dev->name); - priv->demux-> - release_section_feed(priv->demux, priv->secfeed); + priv->demux->release_section_feed(priv->demux, priv->secfeed); priv->secfeed=0; return ret; } - /* fixme: is this correct? */ - try_module_get(THIS_MODULE); - if (priv->mode<3) + if (priv->rx_mode != RX_MODE_PROMISC) { + dprintk("%s: set secfilter\n", __FUNCTION__); dvb_net_filter_set(dev, &priv->secfilter, mac, mask_normal); + } - switch (priv->mode) { - case 1: - for (i=0; imulti_num; i++) + switch (priv->rx_mode) { + case RX_MODE_MULTI: + for (i = 0; i < priv->multi_num; i++) { + dprintk("%s: set multi_secfilter[%d]\n", __FUNCTION__, i); dvb_net_filter_set(dev, &priv->multi_secfilter[i], priv->multi_macs[i], mask_normal); + } break; - case 2: + case RX_MODE_ALL_MULTI: priv->multi_num=1; - dvb_net_filter_set(dev, &priv->multi_secfilter[0], mac_allmulti, mask_allmulti); + dprintk("%s: set multi_secfilter[0]\n", __FUNCTION__); + dvb_net_filter_set(dev, &priv->multi_secfilter[0], + mac_allmulti, mask_allmulti); break; - case 3: + case RX_MODE_PROMISC: priv->multi_num=0; + dprintk("%s: set secfilter\n", __FUNCTION__); dvb_net_filter_set(dev, &priv->secfilter, mac, mask_promisc); break; } + dprintk("%s: start filtering\n", __FUNCTION__); priv->secfeed->start_filtering(priv->secfeed); return 0; } @@ -255,89 +311,93 @@ struct dvb_net_priv *priv = (struct dvb_net_priv*) dev->priv; int i; + dprintk("%s\n", __FUNCTION__); if (priv->secfeed) { - if (priv->secfeed->is_filtering) + if (priv->secfeed->is_filtering) { + dprintk("%s: stop secfeed\n", __FUNCTION__); priv->secfeed->stop_filtering(priv->secfeed); - if (priv->secfilter) - priv->secfeed-> - release_filter(priv->secfeed, + } + + if (priv->secfilter) { + dprintk("%s: release secfilter\n", __FUNCTION__); + priv->secfeed->release_filter(priv->secfeed, priv->secfilter); priv->secfilter=0; + } for (i=0; imulti_num; i++) { - if (priv->multi_secfilter[i]) - priv->secfeed-> - release_filter(priv->secfeed, + if (priv->multi_secfilter[i]) { + dprintk("%s: release multi_filter[%d]\n", __FUNCTION__, i); + priv->secfeed->release_filter(priv->secfeed, priv->multi_secfilter[i]); priv->multi_secfilter[i]=0; } - priv->demux-> - release_section_feed(priv->demux, priv->secfeed); + } + + priv->demux->release_section_feed(priv->demux, priv->secfeed); priv->secfeed=0; - /* fixme: is this correct? */ - module_put(THIS_MODULE); } else printk("%s: no feed to stop\n", dev->name); } -static int dvb_add_mc_filter(struct net_device *dev, struct dev_mc_list *mc) + +static int dvb_set_mc_filter (struct net_device *dev, struct dev_mc_list *mc) { struct dvb_net_priv *priv = (struct dvb_net_priv*) dev->priv; - int ret; - if (priv->multi_num >= DVB_NET_MULTICAST_MAX) + if (priv->multi_num == DVB_NET_MULTICAST_MAX) return -ENOMEM; - ret = memcmp(priv->multi_macs[priv->multi_num], mc->dmi_addr, 6); memcpy(priv->multi_macs[priv->multi_num], mc->dmi_addr, 6); priv->multi_num++; - - return ret; + return 0; } -static void dvb_net_set_multi(struct net_device *dev) + +static void wq_set_multicast_list (void *data) { + struct net_device *dev = data; struct dvb_net_priv *priv = (struct dvb_net_priv*) dev->priv; - struct dev_mc_list *mc; - int mci; - int update = 0; + + dvb_net_feed_stop(dev); + + priv->rx_mode = RX_MODE_UNI; if(dev->flags & IFF_PROMISC) { -// printk("%s: promiscuous mode\n", dev->name); - if(priv->mode != 3) - update = 1; - priv->mode = 3; - } else if(dev->flags & IFF_ALLMULTI) { -// printk("%s: allmulti mode\n", dev->name); - if(priv->mode != 2) - update = 1; - priv->mode = 2; - } else if(dev->mc_count > 0) { -// printk("%s: set_mc_list, %d entries\n", -// dev->name, dev->mc_count); - if(priv->mode != 1) - update = 1; - priv->mode = 1; + dprintk("%s: promiscuous mode\n", dev->name); + priv->rx_mode = RX_MODE_PROMISC; + } else if ((dev->flags & IFF_ALLMULTI)) { + dprintk("%s: allmulti mode\n", dev->name); + priv->rx_mode = RX_MODE_ALL_MULTI; + } else if (dev->mc_count) { + int mci; + struct dev_mc_list *mc; + + dprintk("%s: set_mc_list, %d entries\n", + dev->name, dev->mc_count); + + priv->rx_mode = RX_MODE_MULTI; priv->multi_num = 0; + for (mci = 0, mc=dev->mc_list; mci < dev->mc_count; - mc=mc->next, mci++) - if(dvb_add_mc_filter(dev, mc) != 0) - update = 1; - } else { - if(priv->mode != 0) - update = 1; - priv->mode = 0; + mc = mc->next, mci++) { + dvb_set_mc_filter(dev, mc); + } } - if(netif_running(dev) != 0 && update > 0) - { - dvb_net_feed_stop(dev); dvb_net_feed_start(dev); } + + +static void dvb_net_set_multicast_list (struct net_device *dev) +{ + struct dvb_net_priv *priv = (struct dvb_net_priv*) dev->priv; + schedule_work(&priv->set_multicast_list_wq); } + static int dvb_net_set_config(struct net_device *dev, struct ifmap *map) { if (netif_running(dev)) @@ -345,29 +405,47 @@ return 0; } -static int dvb_net_set_mac(struct net_device *dev, void *p) + +static void wq_restart_net_feed (void *data) { - struct sockaddr *addr=p; - int update; + struct net_device *dev = data; - update = memcmp(dev->dev_addr, addr->sa_data, dev->addr_len); - memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); - if (netif_running(dev) != 0 && update > 0) { + if (netif_running(dev)) { dvb_net_feed_stop(dev); dvb_net_feed_start(dev); } +} + + +static int dvb_net_set_mac (struct net_device *dev, void *p) +{ + struct dvb_net_priv *priv = (struct dvb_net_priv*) dev->priv; + struct sockaddr *addr=p; + + memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); + + if (netif_running(dev)) + schedule_work(&priv->restart_net_feed_wq); + return 0; } static int dvb_net_open(struct net_device *dev) { + struct dvb_net_priv *priv = (struct dvb_net_priv*) dev->priv; + + priv->in_use++; dvb_net_feed_start(dev); return 0; } + static int dvb_net_stop(struct net_device *dev) { + struct dvb_net_priv *priv = (struct dvb_net_priv*) dev->priv; + + priv->in_use--; dvb_net_feed_stop(dev); return 0; } @@ -386,16 +464,14 @@ dev->stop = dvb_net_stop; dev->hard_start_xmit = dvb_net_tx; dev->get_stats = dvb_net_get_stats; - dev->set_multicast_list = dvb_net_set_multi; + dev->set_multicast_list = dvb_net_set_multicast_list; dev->set_config = dvb_net_set_config; dev->set_mac_address = dvb_net_set_mac; dev->mtu = 4096; dev->mc_count = 0; - - dev->flags |= IFF_NOARP; dev->hard_header_cache = NULL; - //SET_MODULE_OWNER(dev); + dev->flags |= IFF_NOARP; return 0; } @@ -404,18 +480,19 @@ { int i; - for (i=0; idev_num; i++) + for (i=0; istate[i]) break; - if (i==dvbnet->dev_num) + + if (i == DVB_NET_DEVICES_MAX) return -1; + dvbnet->state[i]=1; return i; } -int -dvb_net_add_if(struct dvb_net *dvbnet, u16 pid) +static int dvb_net_add_if(struct dvb_net *dvbnet, u16 pid) { struct net_device *net; struct dmx_demux *demux; @@ -423,59 +500,63 @@ int result; int if_num; - if_num=get_if(dvbnet); - if (if_num<0) + if ((if_num = get_if(dvbnet)) < 0) return -EINVAL; net=&dvbnet->device[if_num]; demux=dvbnet->demux; - net->base_addr = 0; - net->irq = 0; - net->dma = 0; - net->mem_start = 0; + memset(net, 0, sizeof(struct net_device)); + memcpy(net->name, "dvb0_0", 7); - net->name[3]=dvbnet->card_num+0x30; - net->name[5]=if_num+0x30; + net->name[3] = dvbnet->dvbdev->adapter->num + '0'; + net->name[5] = if_num + '0'; + net->addr_len = 6; + memcpy(net->dev_addr, dvbnet->dvbdev->adapter->proposed_mac, 6); net->next = NULL; net->init = dvb_net_init_dev; - net->priv = kmalloc(sizeof(struct dvb_net_priv), GFP_KERNEL); - if (net->priv == NULL) + + if (!(net->priv = kmalloc(sizeof(struct dvb_net_priv), GFP_KERNEL))) return -ENOMEM; priv = net->priv; memset(priv, 0, sizeof(struct dvb_net_priv)); priv->demux = demux; priv->pid = pid; - priv->mode = 0; + priv->rx_mode = RX_MODE_UNI; + + INIT_WORK(&priv->set_multicast_list_wq, wq_set_multicast_list, net); + INIT_WORK(&priv->restart_net_feed_wq, wq_restart_net_feed, net); net->base_addr = pid; if ((result = register_netdev(net)) < 0) { return result; } - /* fixme: is this correct? */ - try_module_get(THIS_MODULE); return if_num; } -int -dvb_net_remove_if(struct dvb_net *dvbnet, int num) + +static int dvb_net_remove_if(struct dvb_net *dvbnet, int num) { + struct dvb_net_priv *priv = dvbnet->device[num].priv; + if (!dvbnet->state[num]) return -EINVAL; + if (priv->in_use) + return -EBUSY; + dvb_net_stop(&dvbnet->device[num]); - kfree(dvbnet->device[num].priv); + flush_scheduled_work(); + kfree(priv); unregister_netdev(&dvbnet->device[num]); dvbnet->state[num]=0; - /* fixme: is this correct? */ - module_put(THIS_MODULE); - return 0; } -int dvb_net_do_ioctl(struct inode *inode, struct file *file, + +static int dvb_net_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *parg) { struct dvb_device *dvbdev = (struct dvb_device *) file->private_data; @@ -490,6 +571,8 @@ struct dvb_net_if *dvbnetif=(struct dvb_net_if *)parg; int result; + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; result=dvb_net_add_if(dvbnet, dvbnetif->pid); if (result<0) return result; @@ -502,7 +585,7 @@ struct dvb_net_priv *priv_data; struct dvb_net_if *dvbnetif=(struct dvb_net_if *)parg; - if (dvbnetif->if_num >= dvbnet->dev_num || + if (dvbnetif->if_num >= DVB_NET_DEVICES_MAX || !dvbnet->state[dvbnetif->if_num]) return -EFAULT; @@ -512,7 +595,9 @@ break; } case NET_REMOVE_IF: - return dvb_net_remove_if(dvbnet, (long) parg); + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + return dvb_net_remove_if(dvbnet, (int) parg); default: return -EINVAL; } @@ -542,28 +627,29 @@ .fops = &dvb_net_fops, }; -void -dvb_net_release(struct dvb_net *dvbnet) + +void dvb_net_release (struct dvb_net *dvbnet) { int i; dvb_unregister_device(dvbnet->dvbdev); - for (i=0; idev_num; i++) { + + for (i=0; istate[i]) continue; dvb_net_remove_if(dvbnet, i); } } -int -dvb_net_init(struct dvb_adapter *adap, struct dvb_net *dvbnet, struct dmx_demux *dmx) + +int dvb_net_init (struct dvb_adapter *adap, struct dvb_net *dvbnet, + struct dmx_demux *dmx) { int i; dvbnet->demux = dmx; - dvbnet->dev_num = DVB_NET_DEVICES_MAX; - for (i=0; idev_num; i++) + for (i=0; istate[i] = 0; dvb_register_device (adap, &dvbnet->dvbdev, &dvbdev_net, diff -Nru a/drivers/media/dvb/dvb-core/dvb_net.h b/drivers/media/dvb/dvb-core/dvb_net.h --- a/drivers/media/dvb/dvb-core/dvb_net.h Sun Jul 27 10:13:41 2003 +++ b/drivers/media/dvb/dvb-core/dvb_net.h Sun Jul 27 10:13:41 2003 @@ -35,8 +35,6 @@ struct dvb_net { struct dvb_device *dvbdev; - int card_num; - int dev_num; struct net_device device[DVB_NET_DEVICES_MAX]; int state[DVB_NET_DEVICES_MAX]; struct dmx_demux *demux; diff -Nru a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c --- a/drivers/media/dvb/dvb-core/dvbdev.c Sun Jul 27 10:13:42 2003 +++ b/drivers/media/dvb/dvb-core/dvbdev.c Sun Jul 27 10:13:42 2003 @@ -29,8 +29,6 @@ #include #include #include -#include -#include #include "dvbdev.h" #include "dvb_functions.h" diff -Nru a/drivers/media/dvb/dvb-core/dvbdev.h b/drivers/media/dvb/dvb-core/dvbdev.h --- a/drivers/media/dvb/dvb-core/dvbdev.h Sun Jul 27 10:13:43 2003 +++ b/drivers/media/dvb/dvb-core/dvbdev.h Sun Jul 27 10:13:43 2003 @@ -27,8 +27,9 @@ #include #include #include -#include #include +#include +#include #define DVB_MAJOR 250 @@ -48,6 +49,7 @@ struct list_head list_head; struct list_head device_list; const char *name; + u8 proposed_mac [6]; }; diff -Nru a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig --- a/drivers/media/dvb/frontends/Kconfig Sun Jul 27 10:13:41 2003 +++ b/drivers/media/dvb/frontends/Kconfig Sun Jul 27 10:13:41 2003 @@ -93,6 +93,16 @@ DVB adapter simply enable all supported frontends, the right one will get autodetected. +config DVB_MT312 + tristate "Zarlink MT312 Satellite Channel Decoder (QPSK)" + depends on DVB_CORE + help + A DVB-S tuner module. Say Y when you want to support this frontend. + + If you don't know what tuner module is soldered on your + DVB adapter simply enable all supported frontends, the + right one will get autodetected. + config DVB_VES1820 tristate "Frontends with external VES1820 demodulator (QAM)" depends on DVB_CORE @@ -105,3 +115,23 @@ DVB adapter simply enable all supported frontends, the right one will get autodetected. +config DVB_TDA1004X + tristate "Frontends with external TDA1004X demodulators (OFDM)" + depends on DVB_CORE + help + A DVB-T tuner module. Say Y when you want to support this frontend. + + If you don't know what tuner module is soldered on your + DVB adapter simply enable all supported frontends, the + right one will get autodetected. + +config DVB_TDA1004X_FIRMWARE_FILE + string "Full pathname of tda1004x.bin firmware file" + depends on DVB_TDA1004X + default "/etc/dvb/tda1004x.bin" + help + The TDA1004X requires additional firmware in order to function. + The firmware file can obtained as follows: + wget http://www.technotrend.de/new/215/TTweb_215a_budget_20_05_2003.zip + unzip -j TTweb_215a_budget_20_05_2003.zip Software/Oem/PCI/App/ttlcdacc.dll + mv ttlcdacc.dll /etc/dvb/tda1004x.bin diff -Nru a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile --- a/drivers/media/dvb/frontends/Makefile Sun Jul 27 10:13:40 2003 +++ b/drivers/media/dvb/frontends/Makefile Sun Jul 27 10:13:40 2003 @@ -12,4 +12,6 @@ obj-$(CONFIG_DVB_CX24110) += cx24110.o obj-$(CONFIG_DVB_GRUNDIG_29504_491) += grundig_29504-491.o obj-$(CONFIG_DVB_GRUNDIG_29504_401) += grundig_29504-401.o +obi-$(CONFIG_DVB_MT312) += mt312.o obj-$(CONFIG_DVB_VES1820) += ves1820.o +obj-$(CONFIG_DVB_TDA1004X) += tda1004x.o diff -Nru a/drivers/media/dvb/frontends/alps_bsrv2.c b/drivers/media/dvb/frontends/alps_bsrv2.c --- a/drivers/media/dvb/frontends/alps_bsrv2.c Sun Jul 27 10:13:41 2003 +++ b/drivers/media/dvb/frontends/alps_bsrv2.c Sun Jul 27 10:13:41 2003 @@ -55,7 +55,7 @@ 0x01, 0xA4, 0x35, 0x81, 0x2A, 0x0d, 0x55, 0xC4, 0x09, 0x69, 0x00, 0x86, 0x4c, 0x28, 0x7F, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x80, 0x00, 0x31, 0xb0, 0x14, 0x00, 0xDC, 0x20, + 0x80, 0x00, 0x31, 0xb0, 0x14, 0x00, 0xDC, 0x00, 0x81, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x7f, 0x00 @@ -158,6 +158,11 @@ { u8 val; + /* + * inversion on/off are interchanged because i and q seem to + * be swapped on the hardware + */ + switch (inversion) { case INVERSION_OFF: val = 0xc0; @@ -166,13 +171,16 @@ val = 0x80; break; case INVERSION_AUTO: - val = 0x40; + val = 0x00; break; default: return -EINVAL; } - return ves1893_writereg (i2c, 0x0c, (init_1893_tab[0x0c] & 0x3f) | val); + /* needs to be saved for FE_GET_FRONTEND */ + init_1893_tab[0x0c] = (init_1893_tab[0x0c] & 0x3f) | val; + + return ves1893_writereg (i2c, 0x0c, init_1893_tab[0x0c]); } @@ -383,8 +391,14 @@ afc = (afc * (int)(p->u.qpsk.symbol_rate/1000/8))/16; p->frequency -= afc; + + /* + * inversion indicator is only valid + * if auto inversion was used + */ + if (!(init_1893_tab[0x0c] & 0x80)) p->inversion = (ves1893_readreg (i2c, 0x0f) & 2) ? - INVERSION_ON : INVERSION_OFF; + INVERSION_OFF : INVERSION_ON; p->u.qpsk.fec_inner = ves1893_get_fec (i2c); /* XXX FIXME: timing offset !! */ break; diff -Nru a/drivers/media/dvb/frontends/alps_tdlb7.c b/drivers/media/dvb/frontends/alps_tdlb7.c --- a/drivers/media/dvb/frontends/alps_tdlb7.c Sun Jul 27 10:13:42 2003 +++ b/drivers/media/dvb/frontends/alps_tdlb7.c Sun Jul 27 10:13:42 2003 @@ -349,6 +349,9 @@ sp5659_set_tv_freq (i2c, p->frequency); + // read status reg in order to clear pending irqs + sp8870_readreg(i2c, 0x200); + // sample rate correction bit [23..17] sp8870_writereg(i2c,0x0319,0x000A); diff -Nru a/drivers/media/dvb/frontends/grundig_29504-401.c b/drivers/media/dvb/frontends/grundig_29504-401.c --- a/drivers/media/dvb/frontends/grundig_29504-401.c Sun Jul 27 10:13:41 2003 +++ b/drivers/media/dvb/frontends/grundig_29504-401.c Sun Jul 27 10:13:41 2003 @@ -37,15 +37,15 @@ struct dvb_frontend_info grundig_29504_401_info = { - .name = "Grundig 29504-401", - .type = FE_OFDM, -/* .frequency_min = ???,*/ -/* .frequency_max = ???,*/ - .frequency_stepsize = 166666, -/* .frequency_tolerance = ???,*/ -/* .symbol_rate_tolerance = ???,*/ - .notifier_delay = 0, - .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + name: "Grundig 29504-401", + type: FE_OFDM, +/* frequency_min: ???,*/ +/* frequency_max: ???,*/ + frequency_stepsize: 166666, +/* frequency_tolerance: ???,*/ +/* symbol_rate_tolerance: ???,*/ + notifier_delay: 0, + caps: FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_MUTE_TS /*| FE_CAN_CLEAN_SETUP*/ @@ -109,15 +109,15 @@ div = (36125000 + freq) / 166666; cfg = 0x88; - cpump = div < 175000000 ? 2 : div < 390000000 ? 1 : - div < 470000000 ? 2 : div < 750000000 ? 1 : 3; + cpump = freq < 175000000 ? 2 : freq < 390000000 ? 1 : + freq < 470000000 ? 2 : freq < 750000000 ? 1 : 3; - band_select = div < 175000000 ? 0x0e : div < 470000000 ? 0x05 : 0x03; + band_select = freq < 175000000 ? 0x0e : freq < 470000000 ? 0x05 : 0x03; buf [0] = (div >> 8) & 0x7f; buf [1] = div & 0xff; buf [2] = ((div >> 10) & 0x60) | cfg; - buf [3] = cpump | band_select; + buf [3] = (cpump << 6) | band_select; return tsa5060_write (i2c, buf); } @@ -267,12 +267,12 @@ } -static void reset_and_configure (struct dvb_i2c_bus *i2c) +static int reset_and_configure (struct dvb_i2c_bus *i2c) { u8 buf [] = { 0x06 }; struct i2c_msg msg = { .addr = 0x00, .flags = 0, .buf = buf, .len = 1 }; - i2c->xfer (i2c, &msg, 1); + return (i2c->xfer (i2c, &msg, 1) == 1) ? 0 : -ENODEV; } @@ -391,7 +391,7 @@ struct dvb_frontend_parameters *p = arg; tsa5060_set_tv_freq (i2c, p->frequency); - apply_frontend_param (i2c, p); + return apply_frontend_param (i2c, p); } case FE_GET_FRONTEND: /* we could correct the frequency here, but... @@ -417,25 +417,61 @@ static int l64781_attach (struct dvb_i2c_bus *i2c) { + u8 reg0x3e; u8 b0 [] = { 0x1a }; u8 b1 [] = { 0x00 }; struct i2c_msg msg [] = { { .addr = 0x55, .flags = 0, .buf = b0, .len = 1 }, { .addr = 0x55, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; - if (i2c->xfer (i2c, msg, 2) == 2) /* probably an EEPROM... */ + /** + * the L64781 won't show up before we send the reset_and_configure() + * broadcast. If nothing responds there is no L64781 on the bus... + */ + if (reset_and_configure(i2c) < 0) { + dprintk("no response on reset_and_configure() broadcast, bailing out...\n"); return -ENODEV; + } - reset_and_configure (i2c); - - if (i2c->xfer (i2c, msg, 2) != 2) /* nothing... */ + /* The chip always responds to reads */ + if (i2c->xfer(i2c, msg, 2) != 2) { + dprintk("no response to read on I2C bus\n"); return -ENODEV; + } - if (b1[0] != 0xa1) + /* Save current register contents for bailout */ + reg0x3e = l64781_readreg(i2c, 0x3e); + + /* Reading the POWER_DOWN register always returns 0 */ + if (reg0x3e != 0) { + dprintk("Device doesn't look like L64781\n"); return -ENODEV; + } + + /* Turn the chip off */ + l64781_writereg (i2c, 0x3e, 0x5a); + + /* Responds to all reads with 0 */ + if (l64781_readreg(i2c, 0x1a) != 0) { + dprintk("Read 1 returned unexpcted value\n"); + goto bailout; + } + + /* Turn the chip on */ + l64781_writereg (i2c, 0x3e, 0xa5); + + /* Responds with register default value */ + if (l64781_readreg(i2c, 0x1a) != 0xa1) { + dprintk("Read 2 returned unexpcted value\n"); + goto bailout; + } dvb_register_frontend (grundig_29504_401_ioctl, i2c, NULL, &grundig_29504_401_info); return 0; + + bailout: + l64781_writereg (i2c, 0x3e, reg0x3e); /* restore reg 0x3e */ + return -ENODEV; } diff -Nru a/drivers/media/dvb/frontends/grundig_29504-491.c b/drivers/media/dvb/frontends/grundig_29504-491.c --- a/drivers/media/dvb/frontends/grundig_29504-491.c Sun Jul 27 10:13:50 2003 +++ b/drivers/media/dvb/frontends/grundig_29504-491.c Sun Jul 27 10:13:50 2003 @@ -179,10 +179,7 @@ static fe_code_rate_t fec_tab [] = { FEC_8_9, FEC_1_2, FEC_2_3, FEC_3_4, FEC_4_5, FEC_5_6, FEC_6_7, FEC_7_8 }; - index = tda8083_readreg (i2c, 0x0e) & 0x3; - - if (index > 7) - return FEC_NONE; + index = tda8083_readreg(i2c, 0x0e) & 0x07; return fec_tab [index]; } diff -Nru a/drivers/media/dvb/frontends/mt312.c b/drivers/media/dvb/frontends/mt312.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/media/dvb/frontends/mt312.c Sun Jul 27 10:13:53 2003 @@ -0,0 +1,749 @@ +/* + Driver for Zarlink MT312 Satellite Channel Decoder + + Copyright (C) 2003 Andreas Oberritter + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + References: + http://products.zarlink.com/product_profiles/MT312.htm + http://products.zarlink.com/product_profiles/SL1935.htm +*/ + +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "mt312.h" + +#define I2C_ADDR_MT312 0x0e +#define I2C_ADDR_SL1935 0x61 +#define I2C_ADDR_TSA5059 0x61 + +#define MT312_DEBUG 0 + +#define MT312_SYS_CLK 90000000UL /* 90 MHz */ +#define MT312_PLL_CLK 10000000UL /* 10 MHz */ + +static struct dvb_frontend_info mt312_info = { + .name = "Zarlink MT312", + .type = FE_QPSK, + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_stepsize = (MT312_PLL_CLK / 1000) / 128, + /*.frequency_tolerance = 29500, FIXME: binary compatibility waste? */ + .symbol_rate_min = MT312_SYS_CLK / 128, + .symbol_rate_max = MT312_SYS_CLK / 2, + /*.symbol_rate_tolerance = 500, FIXME: binary compatibility waste? 2% */ + .notifier_delay = 0, + .caps = + FE_CAN_INVERSION_AUTO | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | + FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | + FE_CAN_FEC_AUTO | FE_CAN_QPSK | FE_CAN_RECOVER | + FE_CAN_CLEAN_SETUP | FE_CAN_MUTE_TS +}; + +static int mt312_read(struct dvb_i2c_bus *i2c, + const enum mt312_reg_addr reg, void *buf, + const size_t count) +{ + int ret; + struct i2c_msg msg[2]; + u8 regbuf[1] = { reg }; + + msg[0].addr = I2C_ADDR_MT312; + msg[0].flags = 0; + msg[0].buf = regbuf; + msg[0].len = 1; + msg[1].addr = I2C_ADDR_MT312; + msg[1].flags = I2C_M_RD; + msg[1].buf = buf; + msg[1].len = count; + + ret = i2c->xfer(i2c, msg, 2); + + if (ret != 2) { + printk(KERN_ERR "%s: ret == %d\n", __FUNCTION__, ret); + return -EREMOTEIO; + } +#ifdef MT312_DEBUG + { + int i; + printk(KERN_INFO "R(%d):", reg & 0x7f); + for (i = 0; i < count; i++) + printk(" %02x", ((const u8 *) buf)[i]); + printk("\n"); + } +#endif + + return 0; +} + +static int mt312_write(struct dvb_i2c_bus *i2c, + const enum mt312_reg_addr reg, const void *src, + const size_t count) +{ + int ret; + u8 buf[count + 1]; + struct i2c_msg msg; + +#ifdef MT312_DEBUG + { + int i; + printk(KERN_INFO "W(%d):", reg & 0x7f); + for (i = 0; i < count; i++) + printk(" %02x", ((const u8 *) src)[i]); + printk("\n"); + } +#endif + + buf[0] = reg; + memcpy(&buf[1], src, count); + + msg.addr = I2C_ADDR_MT312; + msg.flags = 0; + msg.buf = buf; + msg.len = count + 1; + + ret = i2c->xfer(i2c, &msg, 1); + + if (ret != 1) { + printk(KERN_ERR "%s: ret == %d\n", __FUNCTION__, ret); + return -EREMOTEIO; + } + + return 0; +} + +static inline int mt312_readreg(struct dvb_i2c_bus *i2c, + const enum mt312_reg_addr reg, u8 * val) +{ + return mt312_read(i2c, reg, val, 1); +} + +static inline int mt312_writereg(struct dvb_i2c_bus *i2c, + const enum mt312_reg_addr reg, const u8 val) +{ + return mt312_write(i2c, reg, &val, 1); +} + +static int mt312_pll_write(struct dvb_i2c_bus *i2c, const u8 addr, + u8 * buf, const u8 len) +{ + int ret; + struct i2c_msg msg; + + msg.addr = addr; + msg.flags = 0; + msg.buf = buf; + msg.len = len; + + if ((ret = mt312_writereg(i2c, GPP_CTRL, 0x40)) < 0) + return ret; + + if ((ret = i2c->xfer(i2c, &msg, 1)) != 1) + printk(KERN_ERR "%s: i/o error (ret == %d)\n", __FUNCTION__, ret); + + if ((ret = mt312_writereg(i2c, GPP_CTRL, 0x00)) < 0) + return ret; + + return 0; +} + +static inline u32 mt312_div(u32 a, u32 b) +{ + return (a + (b / 2)) / b; +} + +static int sl1935_set_tv_freq(struct dvb_i2c_bus *i2c, u32 freq, u32 sr) +{ + /* 155 uA, Baseband Path B */ + u8 buf[4] = { 0x00, 0x00, 0x80, 0x00 }; + + u8 exp; + u32 ref; + u32 div; + + if (sr < 10000000) { /* 1-10 MSym/s: ratio 2 ^ 3 */ + exp = 3; + buf[2] |= 0x40; /* 690 uA */ + } else if (sr < 15000000) { /* 10-15 MSym/s: ratio 2 ^ 4 */ + exp = 4; + buf[2] |= 0x20; /* 330 uA */ + } else { /* 15-45 MSym/s: ratio 2 ^ 7 */ + exp = 7; + buf[3] |= 0x08; /* Baseband Path A */ + } + + div = mt312_div(MT312_PLL_CLK, 1 << exp); + ref = mt312_div(freq * 1000, div); + mt312_info.frequency_stepsize = mt312_div(div, 1000); + + buf[0] = (ref >> 8) & 0x7f; + buf[1] = (ref >> 0) & 0xff; + buf[2] |= (exp - 1); + + if (freq < 1550000) + buf[3] |= 0x10; + + printk(KERN_INFO "synth dword = %02x%02x%02x%02x\n", buf[0], + buf[1], buf[2], buf[3]); + + return mt312_pll_write(i2c, I2C_ADDR_SL1935, buf, sizeof(buf)); +} + +static int tsa5059_set_tv_freq(struct dvb_i2c_bus *i2c, u32 freq, u32 sr) +{ + u8 buf[4]; + + u32 ref = mt312_div(freq, 125); + + buf[0] = (ref >> 8) & 0x7f; + buf[1] = (ref >> 0) & 0xff; + buf[2] = 0x84 | ((ref >> 10) & 0x60); + buf[3] = 0x80; + + if (freq < 1550000) + buf[3] |= 0x02; + + printk(KERN_INFO "synth dword = %02x%02x%02x%02x\n", buf[0], + buf[1], buf[2], buf[3]); + + return mt312_pll_write(i2c, I2C_ADDR_TSA5059, buf, sizeof(buf)); +} + +static int mt312_reset(struct dvb_i2c_bus *i2c, const u8 full) +{ + return mt312_writereg(i2c, RESET, full ? 0x80 : 0x40); +} + +static int mt312_init(struct dvb_i2c_bus *i2c, const long id) +{ + int ret; + u8 buf[2]; + + /* wake up */ + if ((ret = mt312_writereg(i2c, CONFIG, 0x8c)) < 0) + return ret; + + /* wait at least 150 usec */ + udelay(150); + + /* full reset */ + if ((ret = mt312_reset(i2c, 1)) < 0) + return ret; + + /* SYS_CLK */ + buf[0] = mt312_div(MT312_SYS_CLK * 2, 1000000); + + /* DISEQC_RATIO */ + buf[1] = mt312_div(MT312_PLL_CLK, 15000 * 4); + + if ((ret = mt312_write(i2c, SYS_CLK, buf, sizeof(buf))) < 0) + return ret; + + if ((ret = mt312_writereg(i2c, SNR_THS_HIGH, 0x32)) < 0) + return ret; + + if ((ret = mt312_writereg(i2c, OP_CTRL, 0x53)) < 0) + return ret; + + /* TS_SW_LIM */ + buf[0] = 0x8c; + buf[1] = 0x98; + + if ((ret = mt312_write(i2c, TS_SW_LIM_L, buf, sizeof(buf))) < 0) + return ret; + + if ((ret = mt312_writereg(i2c, CS_SW_LIM, 0x69)) < 0) + return ret; + + return 0; +} + +static int mt312_send_master_cmd(struct dvb_i2c_bus *i2c, + const struct dvb_diseqc_master_cmd *c) +{ + int ret; + u8 diseqc_mode; + + if ((c->msg_len == 0) || (c->msg_len > sizeof(c->msg))) + return -EINVAL; + + if ((ret = mt312_readreg(i2c, DISEQC_MODE, &diseqc_mode)) < 0) + return ret; + + if ((ret = + mt312_write(i2c, (0x80 | DISEQC_INSTR), c->msg, c->msg_len)) < 0) + return ret; + + if ((ret = + mt312_writereg(i2c, DISEQC_MODE, + (diseqc_mode & 0x40) | ((c->msg_len - 1) << 3) + | 0x04)) < 0) + return ret; + + /* set DISEQC_MODE[2:0] to zero if a return message is expected */ + if (c->msg[0] & 0x02) + if ((ret = + mt312_writereg(i2c, DISEQC_MODE, (diseqc_mode & 0x40))) < 0) + return ret; + + return 0; +} + +static int mt312_recv_slave_reply(struct dvb_i2c_bus *i2c, + struct dvb_diseqc_slave_reply *r) +{ + /* TODO */ + return -EOPNOTSUPP; +} + +static int mt312_send_burst(struct dvb_i2c_bus *i2c, const fe_sec_mini_cmd_t c) +{ + const u8 mini_tab[2] = { 0x02, 0x03 }; + + int ret; + u8 diseqc_mode; + + if (c > SEC_MINI_B) + return -EINVAL; + + if ((ret = mt312_readreg(i2c, DISEQC_MODE, &diseqc_mode)) < 0) + return ret; + + if ((ret = + mt312_writereg(i2c, DISEQC_MODE, + (diseqc_mode & 0x40) | mini_tab[c])) < 0) + return ret; + + return 0; +} + +static int mt312_set_tone(struct dvb_i2c_bus *i2c, const fe_sec_tone_mode_t t) +{ + const u8 tone_tab[2] = { 0x01, 0x00 }; + + int ret; + u8 diseqc_mode; + + if (t > SEC_TONE_OFF) + return -EINVAL; + + if ((ret = mt312_readreg(i2c, DISEQC_MODE, &diseqc_mode)) < 0) + return ret; + + if ((ret = + mt312_writereg(i2c, DISEQC_MODE, + (diseqc_mode & 0x40) | tone_tab[t])) < 0) + return ret; + + return 0; +} + +static int mt312_set_voltage(struct dvb_i2c_bus *i2c, const fe_sec_voltage_t v) +{ + const u8 volt_tab[3] = { 0x00, 0x40, 0x00 }; + + if (v > SEC_VOLTAGE_OFF) + return -EINVAL; + + return mt312_writereg(i2c, DISEQC_MODE, volt_tab[v]); +} + +static int mt312_read_status(struct dvb_i2c_bus *i2c, fe_status_t * s) +{ + int ret; + u8 status[3]; + + *s = 0; + + if ((ret = mt312_read(i2c, QPSK_STAT_H, status, sizeof(status))) < 0) + return ret; + + if (status[0] & 0xc0) + *s |= FE_HAS_SIGNAL; /* signal noise ratio */ + if (status[0] & 0x04) + *s |= FE_HAS_CARRIER; /* qpsk carrier lock */ + if (status[2] & 0x02) + *s |= FE_HAS_VITERBI; /* viterbi lock */ + if (status[2] & 0x04) + *s |= FE_HAS_SYNC; /* byte align lock */ + if (status[0] & 0x01) + *s |= FE_HAS_LOCK; /* qpsk lock */ + + return 0; +} + +static int mt312_read_bercnt(struct dvb_i2c_bus *i2c, u32 * ber) +{ + int ret; + u8 buf[3]; + + if ((ret = mt312_read(i2c, RS_BERCNT_H, buf, 3)) < 0) + return ret; + + *ber = ((buf[0] << 16) | (buf[1] << 8) | buf[2]) * 64; + + return 0; +} + +static int mt312_read_agc(struct dvb_i2c_bus *i2c, u16 * signal_strength) +{ + int ret; + u8 buf[3]; + u16 agc; + s16 err_db; + + if ((ret = mt312_read(i2c, AGC_H, buf, sizeof(buf))) < 0) + return ret; + + agc = (buf[0] << 6) | (buf[1] >> 2); + err_db = (s16) (((buf[1] & 0x03) << 14) | buf[2] << 6) >> 6; + + *signal_strength = agc; + + printk(KERN_DEBUG "agc=%08x err_db=%hd\n", agc, err_db); + + return 0; +} + +static int mt312_read_snr(struct dvb_i2c_bus *i2c, u16 * snr) +{ + int ret; + u8 buf[2]; + + if ((ret = mt312_read(i2c, M_SNR_H, &buf, sizeof(buf))) < 0) + return ret; + + *snr = 0xFFFF - ((((buf[0] & 0x7f) << 8) | buf[1]) << 1); + + return 0; +} + +static int mt312_read_ubc(struct dvb_i2c_bus *i2c, u32 * ubc) +{ + int ret; + u8 buf[2]; + + if ((ret = mt312_read(i2c, RS_UBC_H, &buf, sizeof(buf))) < 0) + return ret; + + *ubc = (buf[0] << 8) | buf[1]; + + return 0; +} + +static int mt312_set_frontend(struct dvb_i2c_bus *i2c, + const struct dvb_frontend_parameters *p, + const long id) +{ + int ret; + u8 buf[5]; + u16 sr; + + const u8 fec_tab[10] = + { 0x00, 0x01, 0x02, 0x04, 0x3f, 0x08, 0x10, 0x20, 0x3f, 0x3f }; + const u8 inv_tab[3] = { 0x00, 0x40, 0x80 }; + + int (*set_tv_freq)(struct dvb_i2c_bus *i2c, u32 freq, u32 sr); + + if ((p->frequency < mt312_info.frequency_min) + || (p->frequency > mt312_info.frequency_max)) + return -EINVAL; + + if ((p->inversion < INVERSION_OFF) + || (p->inversion > INVERSION_AUTO)) + return -EINVAL; + + if ((p->u.qpsk.symbol_rate < mt312_info.symbol_rate_min) + || (p->u.qpsk.symbol_rate > mt312_info.symbol_rate_max)) + return -EINVAL; + + if ((p->u.qpsk.fec_inner < FEC_NONE) + || (p->u.qpsk.fec_inner > FEC_AUTO)) + return -EINVAL; + + if ((p->u.qpsk.fec_inner == FEC_4_5) + || (p->u.qpsk.fec_inner == FEC_8_9)) + return -EINVAL; + + switch (id) { + case ID_VP310: + set_tv_freq = tsa5059_set_tv_freq; + break; + case ID_MT312: + set_tv_freq = sl1935_set_tv_freq; + break; + default: + return -EINVAL; + } + + if ((ret = set_tv_freq(i2c, p->frequency, p->u.qpsk.symbol_rate)) < 0) + return ret; + + /* sr = (u16)(sr * 256.0 / 1000000.0) */ + sr = mt312_div(p->u.qpsk.symbol_rate * 4, 15625); + + /* SYM_RATE */ + buf[0] = (sr >> 8) & 0x3f; + buf[1] = (sr >> 0) & 0xff; + + /* VIT_MODE */ + buf[2] = inv_tab[p->inversion] | fec_tab[p->u.qpsk.fec_inner]; + + /* QPSK_CTRL */ + buf[3] = 0x40; /* swap I and Q before QPSK demodulation */ + + if (p->u.qpsk.symbol_rate < 10000000) + buf[3] |= 0x04; /* use afc mode */ + + /* GO */ + buf[4] = 0x01; + + if ((ret = mt312_write(i2c, SYM_RATE_H, buf, sizeof(buf))) < 0) + return ret; + + return 0; +} + +static int mt312_get_inversion(struct dvb_i2c_bus *i2c, + fe_spectral_inversion_t * i) +{ + int ret; + u8 vit_mode; + + if ((ret = mt312_readreg(i2c, VIT_MODE, &vit_mode)) < 0) + return ret; + + if (vit_mode & 0x80) /* auto inversion was used */ + *i = (vit_mode & 0x40) ? INVERSION_ON : INVERSION_OFF; + + return 0; +} + +static int mt312_get_symbol_rate(struct dvb_i2c_bus *i2c, u32 * sr) +{ + int ret; + u8 sym_rate_h; + u8 dec_ratio; + u16 sym_rat_op; + u16 monitor; + u8 buf[2]; + + if ((ret = mt312_readreg(i2c, SYM_RATE_H, &sym_rate_h)) < 0) + return ret; + + if (sym_rate_h & 0x80) { /* symbol rate search was used */ + if ((ret = mt312_writereg(i2c, MON_CTRL, 0x03)) < 0) + return ret; + + if ((ret = mt312_read(i2c, MONITOR_H, buf, sizeof(buf))) < 0) + return ret; + + monitor = (buf[0] << 8) | buf[1]; + + printk(KERN_DEBUG "sr(auto) = %u\n", + mt312_div(monitor * 15625, 4)); + } else { + if ((ret = mt312_writereg(i2c, MON_CTRL, 0x05)) < 0) + return ret; + + if ((ret = mt312_read(i2c, MONITOR_H, buf, sizeof(buf))) < 0) + return ret; + + dec_ratio = ((buf[0] >> 5) & 0x07) * 32; + + if ((ret = mt312_read(i2c, SYM_RAT_OP_H, buf, sizeof(buf))) < 0) + return ret; + + sym_rat_op = (buf[0] << 8) | buf[1]; + + printk(KERN_DEBUG "sym_rat_op=%d dec_ratio=%d\n", + sym_rat_op, dec_ratio); + printk(KERN_DEBUG "*sr(manual) = %lu\n", + (((MT312_PLL_CLK * 8192) / (sym_rat_op + 8192)) * + 2) - dec_ratio); + } + + return 0; +} + +static int mt312_get_code_rate(struct dvb_i2c_bus *i2c, fe_code_rate_t * cr) +{ + const fe_code_rate_t fec_tab[8] = + { FEC_1_2, FEC_2_3, FEC_3_4, FEC_5_6, FEC_6_7, FEC_7_8, + FEC_AUTO, FEC_AUTO }; + + int ret; + u8 fec_status; + + if ((ret = mt312_readreg(i2c, FEC_STATUS, &fec_status)) < 0) + return ret; + + *cr = fec_tab[(fec_status >> 4) & 0x07]; + + return 0; +} + +static int mt312_get_frontend(struct dvb_i2c_bus *i2c, + struct dvb_frontend_parameters *p) +{ + int ret; + + if ((ret = mt312_get_inversion(i2c, &p->inversion)) < 0) + return ret; + + if ((ret = mt312_get_symbol_rate(i2c, &p->u.qpsk.symbol_rate)) < 0) + return ret; + + if ((ret = mt312_get_code_rate(i2c, &p->u.qpsk.fec_inner)) < 0) + return ret; + + return 0; +} + +static int mt312_sleep(struct dvb_i2c_bus *i2c) +{ + int ret; + u8 config; + + /* reset all registers to defaults */ + if ((ret = mt312_reset(i2c, 1)) < 0) + return ret; + + if ((ret = mt312_readreg(i2c, CONFIG, &config)) < 0) + return ret; + + /* enter standby */ + if ((ret = mt312_writereg(i2c, CONFIG, config & 0x7f)) < 0) + return ret; + + return 0; +} + +static int mt312_ioctl(struct dvb_frontend *fe, unsigned int cmd, void *arg) +{ + struct dvb_i2c_bus *i2c = fe->i2c; + + switch (cmd) { + case FE_GET_INFO: + memcpy(arg, &mt312_info, sizeof(struct dvb_frontend_info)); + break; + + case FE_DISEQC_RESET_OVERLOAD: + return -EOPNOTSUPP; + + case FE_DISEQC_SEND_MASTER_CMD: + return mt312_send_master_cmd(i2c, arg); + + case FE_DISEQC_RECV_SLAVE_REPLY: + if ((long) fe->data == ID_MT312) + return mt312_recv_slave_reply(i2c, arg); + else + return -EOPNOTSUPP; + + case FE_DISEQC_SEND_BURST: + return mt312_send_burst(i2c, (fe_sec_mini_cmd_t) arg); + + case FE_SET_TONE: + return mt312_set_tone(i2c, (fe_sec_tone_mode_t) arg); + + case FE_SET_VOLTAGE: + return mt312_set_voltage(i2c, (fe_sec_voltage_t) arg); + + case FE_ENABLE_HIGH_LNB_VOLTAGE: + return -EOPNOTSUPP; + + case FE_READ_STATUS: + return mt312_read_status(i2c, arg); + + case FE_READ_BER: + return mt312_read_bercnt(i2c, arg); + + case FE_READ_SIGNAL_STRENGTH: + return mt312_read_agc(i2c, arg); + + case FE_READ_SNR: + return mt312_read_snr(i2c, arg); + + case FE_READ_UNCORRECTED_BLOCKS: + return mt312_read_ubc(i2c, arg); + + case FE_SET_FRONTEND: + return mt312_set_frontend(i2c, arg, (long) fe->data); + + case FE_GET_FRONTEND: + return mt312_get_frontend(i2c, arg); + + case FE_GET_EVENT: + return -EOPNOTSUPP; + + case FE_SLEEP: + return mt312_sleep(i2c); + + case FE_INIT: + return mt312_init(i2c, (long) fe->data); + + case FE_RESET: + return mt312_reset(i2c, 0); + + default: + return -ENOIOCTLCMD; + } + + return 0; +} + +static int mt312_attach(struct dvb_i2c_bus *i2c) +{ + int ret; + u8 id; + + if ((ret = mt312_readreg(i2c, ID, &id)) < 0) + return ret; + + if ((id != ID_VP310) && (id != ID_MT312)) + return -ENODEV; + + return dvb_register_frontend(mt312_ioctl, i2c, (void *) (long) id, + &mt312_info); +} + +static void mt312_detach(struct dvb_i2c_bus *i2c) +{ + dvb_unregister_frontend(mt312_ioctl, i2c); +} + +static int __init mt312_module_init(void) +{ + return dvb_register_i2c_device(THIS_MODULE, mt312_attach, mt312_detach); +} + +static void __exit mt312_module_exit(void) +{ + dvb_unregister_i2c_device(mt312_attach); +} + +module_init(mt312_module_init); +module_exit(mt312_module_exit); + +MODULE_DESCRIPTION("MT312 Satellite Channel Decoder Driver"); +MODULE_AUTHOR("Andreas Oberritter "); +MODULE_LICENSE("GPL"); diff -Nru a/drivers/media/dvb/frontends/mt312.h b/drivers/media/dvb/frontends/mt312.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/media/dvb/frontends/mt312.h Sun Jul 27 10:13:53 2003 @@ -0,0 +1,162 @@ +/* + Driver for Zarlink MT312 QPSK Frontend + + Copyright (C) 2003 Andreas Oberritter + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef _DVB_FRONTENDS_MT312 +#define _DVB_FRONTENDS_MT312 + +enum mt312_reg_addr { + QPSK_INT_H = 0, + QPSK_INT_M = 1, + QPSK_INT_L = 2, + FEC_INT = 3, + QPSK_STAT_H = 4, + QPSK_STAT_L = 5, + FEC_STATUS = 6, + LNB_FREQ_H = 7, + LNB_FREQ_L = 8, + M_SNR_H = 9, + M_SNR_L = 10, + VIT_ERRCNT_H = 11, + VIT_ERRCNT_M = 12, + VIT_ERRCNT_L = 13, + RS_BERCNT_H = 14, + RS_BERCNT_M = 15, + RS_BERCNT_L = 16, + RS_UBC_H = 17, + RS_UBC_L = 18, + SIG_LEVEL = 19, + GPP_CTRL = 20, + RESET = 21, + DISEQC_MODE = 22, + SYM_RATE_H = 23, + SYM_RATE_L = 24, + VIT_MODE = 25, + QPSK_CTRL = 26, + GO = 27, + IE_QPSK_H = 28, + IE_QPSK_M = 29, + IE_QPSK_L = 30, + IE_FEC = 31, + QPSK_STAT_EN = 32, + FEC_STAT_EN = 33, + SYS_CLK = 34, + DISEQC_RATIO = 35, + DISEQC_INSTR = 36, + FR_LIM = 37, + FR_OFF = 38, + AGC_CTRL = 39, + AGC_INIT = 40, + AGC_REF = 41, + AGC_MAX = 42, + AGC_MIN = 43, + AGC_LK_TH = 44, + TS_AGC_LK_TH = 45, + AGC_PWR_SET = 46, + QPSK_MISC = 47, + SNR_THS_LOW = 48, + SNR_THS_HIGH = 49, + TS_SW_RATE = 50, + TS_SW_LIM_L = 51, + TS_SW_LIM_H = 52, + CS_SW_RATE_1 = 53, + CS_SW_RATE_2 = 54, + CS_SW_RATE_3 = 55, + CS_SW_RATE_4 = 56, + CS_SW_LIM = 57, + TS_LPK = 58, + TS_LPK_M = 59, + TS_LPK_L = 60, + CS_KPROP_H = 61, + CS_KPROP_L = 62, + CS_KINT_H = 63, + CS_KINT_L = 64, + QPSK_SCALE = 65, + TLD_OUTCLK_TH = 66, + TLD_INCLK_TH = 67, + FLD_TH = 68, + PLD_OUTLK3 = 69, + PLD_OUTLK2 = 70, + PLD_OUTLK1 = 71, + PLD_OUTLK0 = 72, + PLD_INLK3 = 73, + PLD_INLK2 = 74, + PLD_INLK1 = 75, + PLD_INLK0 = 76, + PLD_ACC_TIME = 77, + SWEEP_PAR = 78, + STARTUP_TIME = 79, + LOSSLOCK_TH = 80, + FEC_LOCK_TM = 81, + LOSSLOCK_TM = 82, + VIT_ERRPER_H = 83, + VIT_ERRPER_M = 84, + VIT_ERRPER_L = 85, + VIT_SETUP = 86, + VIT_REF0 = 87, + VIT_REF1 = 88, + VIT_REF2 = 89, + VIT_REF3 = 90, + VIT_REF4 = 91, + VIT_REF5 = 92, + VIT_REF6 = 93, + VIT_MAXERR = 94, + BA_SETUPT = 95, + OP_CTRL = 96, + FEC_SETUP = 97, + PROG_SYNC = 98, + AFC_SEAR_TH = 99, + CSACC_DIF_TH = 100, + QPSK_LK_CT = 101, + QPSK_ST_CT = 102, + MON_CTRL = 103, + QPSK_RESET = 104, + QPSK_TST_CT = 105, + QPSK_TST_ST = 106, + TEST_R = 107, + AGC_H = 108, + AGC_M = 109, + AGC_L = 110, + FREQ_ERR1_H = 111, + FREQ_ERR1_M = 112, + FREQ_ERR1_L = 113, + FREQ_ERR2_H = 114, + FREQ_ERR2_L = 115, + SYM_RAT_OP_H = 116, + SYM_RAT_OP_L = 117, + DESEQC2_INT = 118, + DISEQC2_STAT = 119, + DISEQC2_FIFO = 120, + DISEQC2_CTRL1 = 121, + DISEQC2_CTRL2 = 122, + MONITOR_H = 123, + MONITOR_L = 124, + TEST_MODE = 125, + ID = 126, + CONFIG = 127 +}; + +enum mt312_model_id { + ID_VP310 = 1, + ID_MT312 = 3 +}; + +#endif /* DVB_FRONTENDS_MT312 */ diff -Nru a/drivers/media/dvb/frontends/nxt6000.c b/drivers/media/dvb/frontends/nxt6000.c --- a/drivers/media/dvb/frontends/nxt6000.c Sun Jul 27 10:13:49 2003 +++ b/drivers/media/dvb/frontends/nxt6000.c Sun Jul 27 10:13:49 2003 @@ -6,8 +6,10 @@ Alps TDME7 (Tuner: MITEL SP5659) Alps TDED4 (Tuner: TI ALP510, external Nxt6000) + Comtech DVBT-6k07 (PLL IC: SP5730) Copyright (C) 2002-2003 Florian Schirmer + Copyright (C) 2003 Paul Andreassen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -78,6 +80,7 @@ #define TUNER_TYPE_ALP510 0 #define TUNER_TYPE_SP5659 1 +#define TUNER_TYPE_SP5730 2 #define FE2NXT(fe) ((struct nxt6000_config *)&(fe->data)) #define FREQ2DIV(freq) ((freq + 36166667) / 166667) @@ -212,6 +215,39 @@ } +static int sp5730_set_tv_freq(struct dvb_frontend *fe, u32 freq) +{ + + u8 buf[4]; + struct nxt6000_config *nxt = FE2NXT(fe); + + buf[0] = (FREQ2DIV(freq) >> 8) & 0x7F; + buf[1] = FREQ2DIV(freq) & 0xFF; + buf[2] = 0x93; + + if ((freq >= 51000000) && (freq < 132100000)) + buf[3] = 0x05; + else if ((freq >= 132100000) && (freq < 143000000)) + buf[3] = 0x45; + else if ((freq >= 146000000) && (freq < 349100000)) + buf[3] = 0x06; + else if ((freq >= 349100000) && (freq < 397100000)) + buf[3] = 0x46; + else if ((freq >= 397100000) && (freq < 426000000)) + buf[3] = 0x86; + else if ((freq >= 430000000) && (freq < 659100000)) + buf[3] = 0x03; + else if ((freq >= 659100000) && (freq < 759100000)) + buf[3] = 0x43; + else if ((freq >= 759100000) && (freq < 858000000)) + buf[3] = 0x83; + else + return -EINVAL; + + return pll_write(fe->i2c, nxt->demod_addr, nxt->tuner_addr, buf, 4); + +} + static void nxt6000_reset(struct dvb_frontend *fe) { @@ -756,6 +792,13 @@ break; + case TUNER_TYPE_SP5730: + + if ((result = sp5730_set_tv_freq(fe, param->frequency)) < 0) + return result; + + break; + default: return -EFAULT; @@ -815,6 +858,14 @@ nxt.clock_inversion = 0; dprintk("nxt6000: detected MITEL SP5659 tuner at 0x%02X\n", nxt.tuner_addr); + + } else if (pll_write(i2c, demod_addr_tbl[addr_nr], 0xC0, NULL, 0) == 0) { + + nxt.tuner_addr = 0xC0; + nxt.tuner_type = TUNER_TYPE_SP5730; + nxt.clock_inversion = 0; + + dprintk("nxt6000: detected SP5730 tuner at 0x%02X\n", nxt.tuner_addr); } else { diff -Nru a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/media/dvb/frontends/tda1004x.c Sun Jul 27 10:13:53 2003 @@ -0,0 +1,1158 @@ + /* + Driver for Philips tda1004x OFDM Frontend + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + */ + +/* + This driver needs a copy of the DLL "ttlcdacc.dll" from the Haupauge or Technotrend + windows driver saved as '/etc/dvb/tda1004x.mc'. + You can also pass the complete file name with the module parameter 'tda1004x_firmware'. + + Currently the DLL from v2.15a of the technotrend driver is supported. Other versions can + be added reasonably painlessly. + + Windows driver URL: http://www.technotrend.de/ + */ + + +#define __KERNEL_SYSCALLS__ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "dvb_frontend.h" +#include "dvb_functions.h" + +#ifndef CONFIG_TDA1004X_MC_LOCATION +#define CONFIG_TDA1004X_MC_LOCATION "/etc/dvb/tda1004x.mc" +#endif + +static int tda1004x_debug = 0; +static char *tda1004x_firmware = CONFIG_TDA1004X_MC_LOCATION; + + +#define TDA10045H_ADDRESS 0x08 +#define TD1344_ADDRESS 0x61 +#define TDM1316L_ADDRESS 0x63 +#define MC44BC374_ADDRESS 0x65 + +#define TDA1004X_CHIPID 0x00 +#define TDA1004X_AUTO 0x01 +#define TDA1004X_IN_CONF1 0x02 +#define TDA1004X_IN_CONF2 0x03 +#define TDA1004X_OUT_CONF1 0x04 +#define TDA1004X_OUT_CONF2 0x05 +#define TDA1004X_STATUS_CD 0x06 +#define TDA1004X_CONFC4 0x07 +#define TDA1004X_DSSPARE2 0x0C +#define TDA1004X_CODE_IN 0x0D +#define TDA1004X_FWPAGE 0x0E +#define TDA1004X_SCAN_CPT 0x10 +#define TDA1004X_DSP_CMD 0x11 +#define TDA1004X_DSP_ARG 0x12 +#define TDA1004X_DSP_DATA1 0x13 +#define TDA1004X_DSP_DATA2 0x14 +#define TDA1004X_CONFADC1 0x15 +#define TDA1004X_CONFC1 0x16 +#define TDA1004X_SIGNAL_STRENGTH 0x1a +#define TDA1004X_SNR 0x1c +#define TDA1004X_REG1E 0x1e +#define TDA1004X_REG1F 0x1f +#define TDA1004X_CBER_RESET 0x20 +#define TDA1004X_CBER_MSB 0x21 +#define TDA1004X_CBER_LSB 0x22 +#define TDA1004X_CVBER_LUT 0x23 +#define TDA1004X_VBER_MSB 0x24 +#define TDA1004X_VBER_MID 0x25 +#define TDA1004X_VBER_LSB 0x26 +#define TDA1004X_UNCOR 0x27 +#define TDA1004X_CONFPLL_P 0x2D +#define TDA1004X_CONFPLL_M_MSB 0x2E +#define TDA1004X_CONFPLL_M_LSB 0x2F +#define TDA1004X_CONFPLL_N 0x30 +#define TDA1004X_UNSURW_MSB 0x31 +#define TDA1004X_UNSURW_LSB 0x32 +#define TDA1004X_WREF_MSB 0x33 +#define TDA1004X_WREF_MID 0x34 +#define TDA1004X_WREF_LSB 0x35 +#define TDA1004X_MUXOUT 0x36 +#define TDA1004X_CONFADC2 0x37 +#define TDA1004X_IOFFSET 0x38 + +#define dprintk if (tda1004x_debug) printk + +static struct dvb_frontend_info tda10045h_info = { + .name = "Philips TDA10045H", + .type = FE_OFDM, + .frequency_min = 51000000, + .frequency_max = 858000000, + .frequency_stepsize = 166667, + .caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO +}; + +#pragma pack(1) +struct tda1004x_state { + u8 tda1004x_address; + u8 tuner_address; + u8 initialised:1; +}; +#pragma pack() + +struct fwinfo { + int file_size; + int fw_offset; + int fw_size; +}; +static struct fwinfo tda10045h_fwinfo[] = { {.file_size = 286720,.fw_offset = 0x34cc5,.fw_size = 30555} }; +static int tda10045h_fwinfo_count = sizeof(tda10045h_fwinfo) / sizeof(struct fwinfo); + +static int errno; + + +static int tda1004x_write_byte(struct dvb_i2c_bus *i2c, struct tda1004x_state *tda_state, int reg, int data) +{ + int ret; + u8 buf[] = { reg, data }; + struct i2c_msg msg = { .addr=0, .flags=0, .buf=buf, .len=2 }; + + dprintk("%s: reg=0x%x, data=0x%x\n", __FUNCTION__, reg, data); + + msg.addr = tda_state->tda1004x_address; + ret = i2c->xfer(i2c, &msg, 1); + + if (ret != 1) + dprintk("%s: error reg=0x%x, data=0x%x, ret=%i\n", + __FUNCTION__, reg, data, ret); + + dprintk("%s: success reg=0x%x, data=0x%x, ret=%i\n", __FUNCTION__, + reg, data, ret); + return (ret != 1) ? -1 : 0; +} + +static int tda1004x_read_byte(struct dvb_i2c_bus *i2c, struct tda1004x_state *tda_state, int reg) +{ + int ret; + u8 b0[] = { reg }; + u8 b1[] = { 0 }; + struct i2c_msg msg[] = {{ .addr=0, .flags=0, .buf=b0, .len=1}, + { .addr=0, .flags=I2C_M_RD, .buf=b1, .len = 1}}; + + dprintk("%s: reg=0x%x\n", __FUNCTION__, reg); + + msg[0].addr = tda_state->tda1004x_address; + msg[1].addr = tda_state->tda1004x_address; + ret = i2c->xfer(i2c, msg, 2); + + if (ret != 2) { + dprintk("%s: error reg=0x%x, ret=%i\n", __FUNCTION__, reg, + ret); + return -1; + } + + dprintk("%s: success reg=0x%x, data=0x%x, ret=%i\n", __FUNCTION__, + reg, b1[0], ret); + return b1[0]; +} + +static int tda1004x_write_mask(struct dvb_i2c_bus *i2c, struct tda1004x_state *tda_state, int reg, int mask, int data) +{ + int val; + dprintk("%s: reg=0x%x, mask=0x%x, data=0x%x\n", __FUNCTION__, reg, + mask, data); + + // read a byte and check + val = tda1004x_read_byte(i2c, tda_state, reg); + if (val < 0) + return val; + + // mask if off + val = val & ~mask; + val |= data & 0xff; + + // write it out again + return tda1004x_write_byte(i2c, tda_state, reg, val); +} + +static int tda1004x_write_buf(struct dvb_i2c_bus *i2c, struct tda1004x_state *tda_state, int reg, unsigned char *buf, int len) +{ + int i; + int result; + + dprintk("%s: reg=0x%x, len=0x%x\n", __FUNCTION__, reg, len); + + result = 0; + for (i = 0; i < len; i++) { + result = tda1004x_write_byte(i2c, tda_state, reg + i, buf[i]); + if (result != 0) + break; + } + + return result; +} + +static int tda1004x_enable_tuner_i2c(struct dvb_i2c_bus *i2c, struct tda1004x_state *tda_state) +{ + int result; + dprintk("%s\n", __FUNCTION__); + + result = tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC4, 2, 2); + dvb_delay(1); + return result; +} + +static int tda1004x_disable_tuner_i2c(struct dvb_i2c_bus *i2c, struct tda1004x_state *tda_state) +{ + + dprintk("%s\n", __FUNCTION__); + + return tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC4, 2, 0); +} + + +static int tda10045h_set_bandwidth(struct dvb_i2c_bus *i2c, + struct tda1004x_state *tda_state, + fe_bandwidth_t bandwidth) +{ + static u8 bandwidth_6mhz[] = { 0x02, 0x00, 0x3d, 0x00, 0x60, 0x1e, 0xa7, 0x45, 0x4f }; + static u8 bandwidth_7mhz[] = { 0x02, 0x00, 0x37, 0x00, 0x4a, 0x2f, 0x6d, 0x76, 0xdb }; + static u8 bandwidth_8mhz[] = { 0x02, 0x00, 0x3d, 0x00, 0x48, 0x17, 0x89, 0xc7, 0x14 }; + + switch (bandwidth) { + case BANDWIDTH_6_MHZ: + tda1004x_write_byte(i2c, tda_state, TDA1004X_DSSPARE2, 0x14); + tda1004x_write_buf(i2c, tda_state, TDA1004X_CONFPLL_P, bandwidth_6mhz, sizeof(bandwidth_6mhz)); + break; + + case BANDWIDTH_7_MHZ: + tda1004x_write_byte(i2c, tda_state, TDA1004X_DSSPARE2, 0x80); + tda1004x_write_buf(i2c, tda_state, TDA1004X_CONFPLL_P, bandwidth_7mhz, sizeof(bandwidth_7mhz)); + break; + + case BANDWIDTH_8_MHZ: + tda1004x_write_byte(i2c, tda_state, TDA1004X_DSSPARE2, 0x14); + tda1004x_write_buf(i2c, tda_state, TDA1004X_CONFPLL_P, bandwidth_8mhz, sizeof(bandwidth_8mhz)); + break; + + default: + return -EINVAL; + } + + tda1004x_write_byte(i2c, tda_state, TDA1004X_IOFFSET, 0); + + // done + return 0; +} + + +static int tda1004x_init(struct dvb_i2c_bus *i2c, struct tda1004x_state *tda_state) +{ + u8 fw_buf[65]; + struct i2c_msg fw_msg = {.addr = 0,.flags = 0,.buf = fw_buf,.len = 0 }; + struct i2c_msg tuner_msg = {.addr = 0,.flags = 0,.buf = 0,.len = 0 }; + unsigned char *firmware = NULL; + int filesize; + int fd; + int fwinfo_idx; + int fw_size = 0; + int fw_pos; + int tx_size; + static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 }; + mm_segment_t fs = get_fs(); + + dprintk("%s\n", __FUNCTION__); + + // Load the firmware + set_fs(get_ds()); + fd = open(tda1004x_firmware, 0, 0); + if (fd < 0) { + printk("%s: Unable to open firmware %s\n", __FUNCTION__, + tda1004x_firmware); + return -EIO; + } + filesize = lseek(fd, 0L, 2); + if (filesize <= 0) { + printk("%s: Firmware %s is empty\n", __FUNCTION__, + tda1004x_firmware); + sys_close(fd); + return -EIO; + } + + // find extraction parameters + for (fwinfo_idx = 0; fwinfo_idx < tda10045h_fwinfo_count; fwinfo_idx++) { + if (tda10045h_fwinfo[fwinfo_idx].file_size == filesize) + break; + } + if (fwinfo_idx >= tda10045h_fwinfo_count) { + printk("%s: Unsupported firmware %s\n", __FUNCTION__, tda1004x_firmware); + sys_close(fd); + return -EIO; + } + fw_size = tda10045h_fwinfo[fwinfo_idx].fw_size; + + // allocate buffer for it + firmware = vmalloc(fw_size); + if (firmware == NULL) { + printk("%s: Out of memory loading firmware\n", + __FUNCTION__); + sys_close(fd); + return -EIO; + } + + // read it! + lseek(fd, tda10045h_fwinfo[fwinfo_idx].fw_offset, 0); + if (read(fd, firmware, fw_size) != fw_size) { + printk("%s: Failed to read firmware\n", __FUNCTION__); + vfree(firmware); + sys_close(fd); + return -EIO; + } + sys_close(fd); + set_fs(fs); + + // Disable the MC44BC374C + tda1004x_enable_tuner_i2c(i2c, tda_state); + tuner_msg.addr = MC44BC374_ADDRESS; + tuner_msg.buf = disable_mc44BC374c; + tuner_msg.len = sizeof(disable_mc44BC374c); + if (i2c->xfer(i2c, &tuner_msg, 1) != 1) { + i2c->xfer(i2c, &tuner_msg, 1); + } + tda1004x_disable_tuner_i2c(i2c, tda_state); + + // set some valid bandwith parameters + switch(tda_state->tda1004x_address) { + case TDA10045H_ADDRESS: + tda10045h_set_bandwidth(i2c, tda_state, BANDWIDTH_8_MHZ); + break; + } + dvb_delay(500); + + // do the firmware upload + tda1004x_write_byte(i2c, tda_state, TDA1004X_FWPAGE, 0); + fw_msg.addr = tda_state->tda1004x_address; + fw_pos = 0; + while (fw_pos != fw_size) { + // work out how much to send this time + tx_size = fw_size - fw_pos; + if (tx_size > 64) { + tx_size = 64; + } + // send the chunk + fw_buf[0] = TDA1004X_CODE_IN; + memcpy(fw_buf + 1, firmware + fw_pos, tx_size); + fw_msg.len = tx_size + 1; + if (i2c->xfer(i2c, &fw_msg, 1) != 1) { + vfree(firmware); + return -EIO; + } + fw_pos += tx_size; + + dprintk("%s: fw_pos=0x%x\n", __FUNCTION__, fw_pos); + } + dvb_delay(100); + vfree(firmware); + + // Initialise the DSP and check upload was OK + tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC4, 0x10, 0); + tda1004x_write_byte(i2c, tda_state, TDA1004X_DSP_CMD, 0x67); + if ((tda1004x_read_byte(i2c, tda_state, TDA1004X_DSP_DATA1) != 0x67) || + (tda1004x_read_byte(i2c, tda_state, TDA1004X_DSP_DATA2) != 0x2c)) { + printk("%s: firmware upload failed!\n", __FUNCTION__); + return -EIO; + } + + // tda setup + tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 8, 0); + tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 0x10, 0x10); + tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF2, 0xC0, 0x0); + tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC4, 0x20, 0); + tda1004x_write_byte(i2c, tda_state, TDA1004X_CONFADC1, 0x2e); + tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC1, 0x80, 0x80); + tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC1, 0x40, 0); + tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC1, 0x10, 0); + tda1004x_write_byte(i2c, tda_state, TDA1004X_REG1E, 0); + tda1004x_write_byte(i2c, tda_state, TDA1004X_REG1F, 0); + tda1004x_write_mask(i2c, tda_state, TDA1004X_VBER_MSB, 0xe0, 0xa0); + + // done + return 0; +} + +static int tda1004x_encode_fec(int fec) +{ + // convert known FEC values + switch (fec) { + case FEC_1_2: + return 0; + case FEC_2_3: + return 1; + case FEC_3_4: + return 2; + case FEC_5_6: + return 3; + case FEC_7_8: + return 4; + } + + // unsupported + return -EINVAL; +} + +static int tda1004x_decode_fec(int tdafec) +{ + // convert known FEC values + switch (tdafec) { + case 0: + return FEC_1_2; + case 1: + return FEC_2_3; + case 2: + return FEC_3_4; + case 3: + return FEC_5_6; + case 4: + return FEC_7_8; + } + + // unsupported + return -1; +} + +static int tda1004x_set_frequency(struct dvb_i2c_bus *i2c, + struct tda1004x_state *tda_state, + struct dvb_frontend_parameters *fe_params) +{ + u8 tuner_buf[4]; + struct i2c_msg tuner_msg = {.addr=0, .flags=0, .buf=tuner_buf, .len=sizeof(tuner_buf) }; + int tuner_frequency; + u8 band, cp, filter; + int counter, counter2; + + dprintk("%s\n", __FUNCTION__); + + // setup the frequency buffer + switch (tda_state->tuner_address) { + case TD1344_ADDRESS: + + // setup tuner buffer + tuner_frequency = + (((fe_params->frequency / 1000) * 6) + 217502) / 1000; + tuner_buf[0] = tuner_frequency >> 8; + tuner_buf[1] = tuner_frequency & 0xff; + tuner_buf[2] = 0x88; + if (fe_params->frequency < 550000000) { + tuner_buf[3] = 0xab; + } else { + tuner_buf[3] = 0xeb; + } + + // tune it + tda1004x_enable_tuner_i2c(i2c, tda_state); + tuner_msg.addr = tda_state->tuner_address; + tuner_msg.len = 4; + i2c->xfer(i2c, &tuner_msg, 1); + + // wait for it to finish + tuner_msg.len = 1; + tuner_msg.flags = I2C_M_RD; + counter = 0; + counter2 = 0; + while (counter++ < 100) { + if (i2c->xfer(i2c, &tuner_msg, 1) == 1) { + if (tuner_buf[0] & 0x40) { + counter2++; + } else { + counter2 = 0; + } + } + + if (counter2 > 10) { + break; + } + } + tda1004x_disable_tuner_i2c(i2c, tda_state); + break; + + case TDM1316L_ADDRESS: + // determine charge pump + tuner_frequency = fe_params->frequency + 36130000; + if (tuner_frequency < 87000000) { + return -EINVAL; + } else if (tuner_frequency < 130000000) { + cp = 3; + } else if (tuner_frequency < 160000000) { + cp = 5; + } else if (tuner_frequency < 200000000) { + cp = 6; + } else if (tuner_frequency < 290000000) { + cp = 3; + } else if (tuner_frequency < 420000000) { + cp = 5; + } else if (tuner_frequency < 480000000) { + cp = 6; + } else if (tuner_frequency < 620000000) { + cp = 3; + } else if (tuner_frequency < 830000000) { + cp = 5; + } else if (tuner_frequency < 895000000) { + cp = 7; + } else { + return -EINVAL; + } + + // determine band + if (fe_params->frequency < 49000000) { + return -EINVAL; + } else if (fe_params->frequency < 159000000) { + band = 1; + } else if (fe_params->frequency < 444000000) { + band = 2; + } else if (fe_params->frequency < 861000000) { + band = 4; + } else { + return -EINVAL; + } + + // work out filter + switch (fe_params->u.ofdm.bandwidth) { + case BANDWIDTH_6_MHZ: + // 6 MHz isn't supported directly, but set this to + // the 8 MHz setting in case we can fiddle it later + filter = 1; + break; + + case BANDWIDTH_7_MHZ: + filter = 0; + break; + + case BANDWIDTH_8_MHZ: + filter = 1; + break; + + default: + return -EINVAL; + } + + // calculate tuner parameters + tuner_frequency = + (((fe_params->frequency / 1000) * 6) + 217280) / 1000; + tuner_buf[0] = tuner_frequency >> 8; + tuner_buf[1] = tuner_frequency & 0xff; + tuner_buf[2] = 0xca; + tuner_buf[3] = (cp << 5) | (filter << 3) | band; + + // tune it + tda1004x_enable_tuner_i2c(i2c, tda_state); + tuner_msg.addr = tda_state->tuner_address; + tuner_msg.len = 4; + if (i2c->xfer(i2c, &tuner_msg, 1) != 1) { + return -EIO; + } + dvb_delay(1); + tda1004x_disable_tuner_i2c(i2c, tda_state); + break; + + default: + return -EINVAL; + } + + dprintk("%s: success\n", __FUNCTION__); + + // done + return 0; +} + +static int tda1004x_set_fe(struct dvb_i2c_bus *i2c, + struct tda1004x_state *tda_state, + struct dvb_frontend_parameters *fe_params) +{ + int tmp; + + dprintk("%s\n", __FUNCTION__); + + + // set frequency + tmp = tda1004x_set_frequency(i2c, tda_state, fe_params); + if (tmp < 0) + return tmp; + + // hardcoded to use auto as much as possible + fe_params->u.ofdm.code_rate_HP = FEC_AUTO; + fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO; + fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO; + + // Set standard params.. or put them to auto + if ((fe_params->u.ofdm.code_rate_HP == FEC_AUTO) || + (fe_params->u.ofdm.code_rate_LP == FEC_AUTO) || + (fe_params->u.ofdm.constellation == QAM_AUTO) || + (fe_params->u.ofdm.hierarchy_information == HIERARCHY_AUTO)) { + tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 1, 1); // enable auto + tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 0x03, 0); // turn off constellation bits + tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 0x60, 0); // turn off hierarchy bits + tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF2, 0x3f, 0); // turn off FEC bits + } else { + tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 1, 0); // disable auto + + // set HP FEC + tmp = tda1004x_encode_fec(fe_params->u.ofdm.code_rate_HP); + if (tmp < 0) return tmp; + tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF2, 7, tmp); + + // set LP FEC + if (fe_params->u.ofdm.code_rate_LP != FEC_NONE) { + tmp = tda1004x_encode_fec(fe_params->u.ofdm.code_rate_LP); + if (tmp < 0) return tmp; + tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF2, 0x38, tmp << 3); + } + + // set constellation + switch (fe_params->u.ofdm.constellation) { + case QPSK: + tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 3, 0); + break; + + case QAM_16: + tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 3, 1); + break; + + case QAM_64: + tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 3, 2); + break; + + default: + return -EINVAL; + } + + // set hierarchy + switch (fe_params->u.ofdm.hierarchy_information) { + case HIERARCHY_NONE: + tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 0x60, 0 << 5); + break; + + case HIERARCHY_1: + tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 0x60, 1 << 5); + break; + + case HIERARCHY_2: + tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 0x60, 2 << 5); + break; + + case HIERARCHY_4: + tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 0x60, 3 << 5); + break; + + default: + return -EINVAL; + } + } + + // set bandwidth + switch(tda_state->tda1004x_address) { + case TDA10045H_ADDRESS: + tda10045h_set_bandwidth(i2c, tda_state, fe_params->u.ofdm.bandwidth); + break; + } + + // set inversion + switch (fe_params->inversion) { + case INVERSION_OFF: + tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC1, 0x20, 0); + break; + + case INVERSION_ON: + tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC1, 0x20, 0x20); + break; + + default: + return -EINVAL; + } + + // set guard interval + switch (fe_params->u.ofdm.guard_interval) { + case GUARD_INTERVAL_1_32: + tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 2, 0); + tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 0x0c, 0 << 2); + break; + + case GUARD_INTERVAL_1_16: + tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 2, 0); + tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 0x0c, 1 << 2); + break; + + case GUARD_INTERVAL_1_8: + tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 2, 0); + tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 0x0c, 2 << 2); + break; + + case GUARD_INTERVAL_1_4: + tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 2, 0); + tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 0x0c, 3 << 2); + break; + + case GUARD_INTERVAL_AUTO: + tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 2, 2); + tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 0x0c, 0 << 2); + break; + + default: + return -EINVAL; + } + + // set transmission mode + switch (fe_params->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_2K: + tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 4, 0); + tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 0x10, 0 << 4); + break; + + case TRANSMISSION_MODE_8K: + tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 4, 0); + tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 0x10, 1 << 4); + break; + + case TRANSMISSION_MODE_AUTO: + tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 4, 4); + tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 0x10, 0); + break; + + default: + return -EINVAL; + } + + // reset DSP + tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC4, 8, 8); + tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC4, 8, 0); + dvb_delay(10); + + // done + return 0; +} + + +static int tda1004x_get_fe(struct dvb_i2c_bus *i2c, struct tda1004x_state* tda_state, struct dvb_frontend_parameters *fe_params) +{ + + dprintk("%s\n", __FUNCTION__); + + // inversion status + fe_params->inversion = INVERSION_OFF; + if (tda1004x_read_byte(i2c, tda_state, TDA1004X_CONFC1) & 0x20) { + fe_params->inversion = INVERSION_ON; + } + + // bandwidth + switch (tda1004x_read_byte(i2c, tda_state, TDA1004X_WREF_LSB)) { + case 0x14: + fe_params->u.ofdm.bandwidth = BANDWIDTH_8_MHZ; + break; + case 0xdb: + fe_params->u.ofdm.bandwidth = BANDWIDTH_7_MHZ; + break; + case 0x4f: + fe_params->u.ofdm.bandwidth = BANDWIDTH_6_MHZ; + break; + } + + // FEC + fe_params->u.ofdm.code_rate_HP = + tda1004x_decode_fec(tda1004x_read_byte(i2c, tda_state, TDA1004X_OUT_CONF2) & 7); + fe_params->u.ofdm.code_rate_LP = + tda1004x_decode_fec((tda1004x_read_byte(i2c, tda_state, TDA1004X_OUT_CONF2) >> 3) & 7); + + // constellation + switch (tda1004x_read_byte(i2c, tda_state, TDA1004X_OUT_CONF1) & 3) { + case 0: + fe_params->u.ofdm.constellation = QPSK; + break; + case 1: + fe_params->u.ofdm.constellation = QAM_16; + break; + case 2: + fe_params->u.ofdm.constellation = QAM_64; + break; + } + + // transmission mode + fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; + if (tda1004x_read_byte(i2c, tda_state, TDA1004X_OUT_CONF1) & 0x10) { + fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; + } + + // guard interval + switch ((tda1004x_read_byte(i2c, tda_state, TDA1004X_OUT_CONF1) & 0x0c) >> 2) { + case 0: + fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; + break; + case 1: + fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; + break; + case 2: + fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; + break; + case 3: + fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; + break; + } + + // hierarchy + switch ((tda1004x_read_byte(i2c, tda_state, TDA1004X_OUT_CONF1) & 0x60) >> 5) { + case 0: + fe_params->u.ofdm.hierarchy_information = HIERARCHY_NONE; + break; + case 1: + fe_params->u.ofdm.hierarchy_information = HIERARCHY_1; + break; + case 2: + fe_params->u.ofdm.hierarchy_information = HIERARCHY_2; + break; + case 3: + fe_params->u.ofdm.hierarchy_information = HIERARCHY_4; + break; + } + + // done + return 0; +} + + +static int tda1004x_read_status(struct dvb_i2c_bus *i2c, struct tda1004x_state* tda_state, fe_status_t * fe_status) +{ + int status; + int cber; + int vber; + + dprintk("%s\n", __FUNCTION__); + + // read status + status = tda1004x_read_byte(i2c, tda_state, TDA1004X_STATUS_CD); + if (status == -1) { + return -EIO; + } + + // decode + *fe_status = 0; + if (status & 4) *fe_status |= FE_HAS_SIGNAL; + if (status & 2) *fe_status |= FE_HAS_CARRIER; + if (status & 8) *fe_status |= FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; + + // if we don't already have VITERBI (i.e. not LOCKED), see if the viterbi + // is getting anything valid + if (!(*fe_status & FE_HAS_VITERBI)) { + // read the CBER + cber = tda1004x_read_byte(i2c, tda_state, TDA1004X_CBER_LSB); + if (cber == -1) return -EIO; + status = tda1004x_read_byte(i2c, tda_state, TDA1004X_CBER_MSB); + if (status == -1) return -EIO; + cber |= (status << 8); + tda1004x_read_byte(i2c, tda_state, TDA1004X_CBER_RESET); + + if (cber != 65535) { + *fe_status |= FE_HAS_VITERBI; + } + } + + // if we DO have some valid VITERBI output, but don't already have SYNC + // bytes (i.e. not LOCKED), see if the RS decoder is getting anything valid. + if ((*fe_status & FE_HAS_VITERBI) && (!(*fe_status & FE_HAS_SYNC))) { + // read the VBER + vber = tda1004x_read_byte(i2c, tda_state, TDA1004X_VBER_LSB); + if (vber == -1) return -EIO; + status = tda1004x_read_byte(i2c, tda_state, TDA1004X_VBER_MID); + if (status == -1) return -EIO; + vber |= (status << 8); + status = tda1004x_read_byte(i2c, tda_state, TDA1004X_VBER_MSB); + if (status == -1) return -EIO; + vber |= ((status << 16) & 0x0f); + tda1004x_read_byte(i2c, tda_state, TDA1004X_CVBER_LUT); + + // if RS has passed some valid TS packets, then we must be + // getting some SYNC bytes + if (vber < 16632) { + *fe_status |= FE_HAS_SYNC; + } + } + + // success + dprintk("%s: fe_status=0x%x\n", __FUNCTION__, *fe_status); + return 0; +} + +static int tda1004x_read_signal_strength(struct dvb_i2c_bus *i2c, struct tda1004x_state* tda_state, u16 * signal) +{ + int tmp; + + dprintk("%s\n", __FUNCTION__); + + // read it + tmp = tda1004x_read_byte(i2c, tda_state, TDA1004X_SIGNAL_STRENGTH); + if (tmp < 0) + return -EIO; + + // done + *signal = (tmp << 8) | tmp; + dprintk("%s: signal=0x%x\n", __FUNCTION__, *signal); + return 0; +} + + +static int tda1004x_read_snr(struct dvb_i2c_bus *i2c, struct tda1004x_state* tda_state, u16 * snr) +{ + int tmp; + + dprintk("%s\n", __FUNCTION__); + + // read it + tmp = tda1004x_read_byte(i2c, tda_state, TDA1004X_SNR); + if (tmp < 0) + return -EIO; + if (tmp) { + tmp = 255 - tmp; + } + + // done + *snr = ((tmp << 8) | tmp); + dprintk("%s: snr=0x%x\n", __FUNCTION__, *snr); + return 0; +} + +static int tda1004x_read_ucblocks(struct dvb_i2c_bus *i2c, struct tda1004x_state* tda_state, u32* ucblocks) +{ + int tmp; + int tmp2; + int counter; + + dprintk("%s\n", __FUNCTION__); + + // read the UCBLOCKS and reset + counter = 0; + tmp = tda1004x_read_byte(i2c, tda_state, TDA1004X_UNCOR); + if (tmp < 0) + return -EIO; + tmp &= 0x7f; + while (counter++ < 5) { + tda1004x_write_mask(i2c, tda_state, TDA1004X_UNCOR, 0x80, 0); + tda1004x_write_mask(i2c, tda_state, TDA1004X_UNCOR, 0x80, 0); + tda1004x_write_mask(i2c, tda_state, TDA1004X_UNCOR, 0x80, 0); + + tmp2 = tda1004x_read_byte(i2c, tda_state, TDA1004X_UNCOR); + if (tmp2 < 0) + return -EIO; + tmp2 &= 0x7f; + if ((tmp2 < tmp) || (tmp2 == 0)) + break; + } + + // done + if (tmp != 0x7f) { + *ucblocks = tmp; + } else { + *ucblocks = 0xffffffff; + } + dprintk("%s: ucblocks=0x%x\n", __FUNCTION__, *ucblocks); + return 0; +} + +static int tda1004x_read_ber(struct dvb_i2c_bus *i2c, struct tda1004x_state* tda_state, u32* ber) +{ + int tmp; + + dprintk("%s\n", __FUNCTION__); + + // read it in + tmp = tda1004x_read_byte(i2c, tda_state, TDA1004X_CBER_LSB); + if (tmp < 0) return -EIO; + *ber = tmp << 1; + tmp = tda1004x_read_byte(i2c, tda_state, TDA1004X_CBER_MSB); + if (tmp < 0) return -EIO; + *ber |= (tmp << 9); + tda1004x_read_byte(i2c, tda_state, TDA1004X_CBER_RESET); + + // done + dprintk("%s: ber=0x%x\n", __FUNCTION__, *ber); + return 0; +} + + +static int tda1004x_ioctl(struct dvb_frontend *fe, unsigned int cmd, void *arg) +{ + int status = 0; + struct dvb_i2c_bus *i2c = fe->i2c; + struct tda1004x_state *tda_state = (struct tda1004x_state *) &(fe->data); + + dprintk("%s: cmd=0x%x\n", __FUNCTION__, cmd); + + switch (cmd) { + case FE_GET_INFO: + switch(tda_state->tda1004x_address) { + case TDA10045H_ADDRESS: + memcpy(arg, &tda10045h_info, sizeof(struct dvb_frontend_info)); + break; + } + break; + + case FE_READ_STATUS: + return tda1004x_read_status(i2c, tda_state, (fe_status_t *) arg); + + case FE_READ_BER: + return tda1004x_read_ber(i2c, tda_state, (u32 *) arg); + + case FE_READ_SIGNAL_STRENGTH: + return tda1004x_read_signal_strength(i2c, tda_state, (u16 *) arg); + + case FE_READ_SNR: + return tda1004x_read_snr(i2c, tda_state, (u16 *) arg); + + case FE_READ_UNCORRECTED_BLOCKS: + return tda1004x_read_ucblocks(i2c, tda_state, (u32 *) arg); + + case FE_SET_FRONTEND: + return tda1004x_set_fe(i2c, tda_state, (struct dvb_frontend_parameters*) arg); + + case FE_GET_FRONTEND: + return tda1004x_get_fe(i2c, tda_state, (struct dvb_frontend_parameters*) arg); + + case FE_INIT: + // don't bother reinitialising + if (tda_state->initialised) + return 0; + + // OK, perform initialisation + status = tda1004x_init(i2c, tda_state); + if (status == 0) + tda_state->initialised = 1; + return status; + + default: + return -EOPNOTSUPP; + } + + return 0; +} + + +static int tda1004x_attach(struct dvb_i2c_bus *i2c) +{ + int tda1004x_address = -1; + int tuner_address = -1; + struct tda1004x_state tda_state; + struct i2c_msg tuner_msg = {.addr=0, .flags=0, .buf=0, .len=0 }; + static u8 td1344_init[] = { 0x0b, 0xf5, 0x88, 0xab }; + static u8 tdm1316l_init[] = { 0x0b, 0xf5, 0x85, 0xab }; + + dprintk("%s\n", __FUNCTION__); + + // probe for frontend + tda_state.tda1004x_address = TDA10045H_ADDRESS; + if (tda1004x_read_byte(i2c, &tda_state, TDA1004X_CHIPID) == 0x25) { + tda1004x_address = TDA10045H_ADDRESS; + printk("tda1004x: Detected Philips TDA10045H.\n"); + } + + // did we find a frontend? + if (tda1004x_address == -1) { + return -ENODEV; + } + + // supported tuner? + tda1004x_enable_tuner_i2c(i2c, &tda_state); + tuner_msg.addr = TD1344_ADDRESS; + tuner_msg.buf = td1344_init; + tuner_msg.len = sizeof(td1344_init); + if (i2c->xfer(i2c, &tuner_msg, 1) == 1) { + dvb_delay(1); + tuner_address = TD1344_ADDRESS; + printk("tda1004x: Detected Philips TD1344 tuner. PLEASE CHECK THIS AND REPORT BACK!.\n"); + } else { + tuner_msg.addr = TDM1316L_ADDRESS; + tuner_msg.buf = tdm1316l_init; + tuner_msg.len = sizeof(tdm1316l_init); + if (i2c->xfer(i2c, &tuner_msg, 1) == 1) { + dvb_delay(1); + tuner_address = TDM1316L_ADDRESS; + printk("tda1004x: Detected Philips TDM1316L tuner.\n"); + } + } + tda1004x_disable_tuner_i2c(i2c, &tda_state); + + // did we find a tuner? + if (tuner_address == -1) { + printk("tda1004x: Detected, but with unknown tuner.\n"); + return -ENODEV; + } + + // create state + tda_state.tda1004x_address = tda1004x_address; + tda_state.tuner_address = tuner_address; + tda_state.initialised = 0; + + // register + switch(tda_state.tda1004x_address) { + case TDA10045H_ADDRESS: + dvb_register_frontend(tda1004x_ioctl, i2c, (void *)(*((u32*) &tda_state)), &tda10045h_info); + break; + } + + // success + return 0; +} + + +static +void tda1004x_detach(struct dvb_i2c_bus *i2c) +{ + dprintk("%s\n", __FUNCTION__); + + dvb_unregister_frontend(tda1004x_ioctl, i2c); +} + + +static +int __init init_tda1004x(void) +{ + return dvb_register_i2c_device(THIS_MODULE, tda1004x_attach, tda1004x_detach); +} + + +static +void __exit exit_tda1004x(void) +{ + dvb_unregister_i2c_device(tda1004x_attach); +} + +module_init(init_tda1004x); +module_exit(exit_tda1004x); + +MODULE_DESCRIPTION("Philips TDA10045H DVB-T Frontend"); +MODULE_AUTHOR("Andrew de Quincey & Robert Schlabbach"); +MODULE_LICENSE("GPL"); + +MODULE_PARM(tda1004x_debug, "i"); +MODULE_PARM_DESC(tda1004x_debug, "enable verbose debug messages"); + +MODULE_PARM(tda1004x_firmware, "s"); +MODULE_PARM_DESC(tda1004x_firmware, "Where to find the firmware file"); diff -Nru a/drivers/media/dvb/frontends/ves1820.c b/drivers/media/dvb/frontends/ves1820.c --- a/drivers/media/dvb/frontends/ves1820.c Sun Jul 27 10:13:45 2003 +++ b/drivers/media/dvb/frontends/ves1820.c Sun Jul 27 10:13:45 2003 @@ -95,7 +95,7 @@ static u8 ves1820_inittab [] = { - 0x69, 0x6A, 0x9B, 0x0A, 0x52, 0x46, 0x26, 0x1A, + 0x69, 0x6A, 0x9B, 0x12, 0x12, 0x46, 0x26, 0x1A, 0x43, 0x6A, 0xAA, 0xAA, 0x1E, 0x85, 0x43, 0x28, 0xE0, 0x00, 0xA1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, @@ -109,7 +109,7 @@ { u8 addr = GET_DEMOD_ADDR(fe->data); u8 buf[] = { 0x00, reg, data }; - struct i2c_msg msg = { addr: addr, .flags = 0, .buf = buf, .len = 3 }; + struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = 3 }; struct dvb_i2c_bus *i2c = fe->i2c; int ret; @@ -130,8 +130,8 @@ u8 b0 [] = { 0x00, reg }; u8 b1 [] = { 0 }; u8 addr = GET_DEMOD_ADDR(fe->data); - struct i2c_msg msg [] = { { addr: addr, .flags = 0, .buf = b0, .len = 2 }, - { addr: addr, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; + struct i2c_msg msg [] = { { .addr = addr, .flags = 0, .buf = b0, .len = 2 }, + { .addr = addr, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; struct dvb_i2c_bus *i2c = fe->i2c; int ret; @@ -147,7 +147,7 @@ static int tuner_write (struct dvb_i2c_bus *i2c, u8 addr, u8 data [4]) { int ret; - struct i2c_msg msg = { addr: addr, .flags = 0, .buf = data, .len = 4 }; + struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = data, .len = 4 }; ret = i2c->xfer (i2c, &msg, 1); diff -Nru a/drivers/media/dvb/ttpci/Makefile b/drivers/media/dvb/ttpci/Makefile --- a/drivers/media/dvb/ttpci/Makefile Sun Jul 27 10:13:41 2003 +++ b/drivers/media/dvb/ttpci/Makefile Sun Jul 27 10:13:41 2003 @@ -3,16 +3,12 @@ # and the AV7110 DVB device driver # -dvb-ttpci-budget-objs := budget.o -dvb-ttpci-budget-av-objs := budget-av.o -dvb-ttpci-budget-ci-objs := budget-ci.o -dvb-ttpci-budget-patch-objs := budget-patch.o dvb-ttpci-objs := av7110.o av7110_ipack.o av7110_ir.o -obj-$(CONFIG_DVB_BUDGET) += budget-core.o dvb-ttpci-budget.o -obj-$(CONFIG_DVB_BUDGET_CI) += budget-core.o dvb-ttpci-budget-ci.o -obj-$(CONFIG_DVB_BUDGET_AV) += budget-core.o dvb-ttpci-budget-av.o -obj-$(CONFIG_DVB_BUDGET_PATCH) += budget-core.o dvb-ttpci-budget-patch.o -obj-$(CONFIG_DVB_AV7110) += dvb-ttpci.o +obj-$(CONFIG_DVB_BUDGET) += budget-core.o budget.o ttpci-eeprom.o +obj-$(CONFIG_DVB_BUDGET_AV) += budget-core.o budget-av.o ttpci-eeprom.o +obj-$(CONFIG_DVB_BUDGET_CI) += budget-core.o budget-ci.o ttpci-eeprom.o +obj-$(CONFIG_DVB_BUDGET_PATCH) += budget-core.o budget-patch.o ttpci-eeprom.o +obj-$(CONFIG_DVB_AV7110) += dvb-ttpci.o ttpci-eeprom.o EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ diff -Nru a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c --- a/drivers/media/dvb/ttpci/av7110.c Sun Jul 27 10:13:48 2003 +++ b/drivers/media/dvb/ttpci/av7110.c Sun Jul 27 10:13:48 2003 @@ -86,6 +86,7 @@ #define DEB_EE(x) #endif +#include "ttpci-eeprom.h" #include "av7110.h" #include "av7110_ipack.h" @@ -110,7 +111,8 @@ int av7110_num = 0; -#define FW_CI_LL_SUPPORT(arm_app) (((arm_app) >> 16) & 0x8000) +#define FW_CI_LL_SUPPORT(arm_app) ((arm_app) & 0x80000000) +#define FW_VERSION(arm_app) ((arm_app) & 0x0000FFFF) /**************************************************************************** * DEBI functions @@ -1089,7 +1091,7 @@ u32 stat; #endif - DEB_EE(("av7110: %p\n",av7110)); +// DEB_EE(("av7110: %p\n",av7110)); if (!av7110->arm_ready) { DEB_D(("arm not ready.\n")); @@ -1166,7 +1168,7 @@ { int ret; - DEB_EE(("av7110: %p\n",av7110)); +// DEB_EE(("av7110: %p\n",av7110)); if (!av7110->arm_ready) { DEB_D(("arm not ready.\n")); @@ -1190,7 +1192,7 @@ u16 buf[num+2]; int i, ret; - DEB_EE(("av7110: %p\n",av7110)); +// DEB_EE(("av7110: %p\n",av7110)); buf[0]=(( type << 8 ) | com); buf[1]=num; @@ -1332,7 +1334,7 @@ static inline int SendDAC(struct av7110 *av7110, u8 addr, u8 data) { - DEB_EE(("av7110: %p\n",av7110)); +// DEB_EE(("av7110: %p\n",av7110)); return outcom(av7110, COMTYPE_AUDIODAC, AudioDAC, 2, addr, data); } @@ -1659,6 +1661,24 @@ color, ((blend>>4)&0x0f)); } +static int OSDSetPalette(struct av7110 *av7110, u32 *colors, u8 first, u8 last) +{ + int i; + int length = last - first + 1; + + if (length * 4 > DATA_BUFF3_SIZE) + return -1; + + for (i=0; i> 4; + u32 yuv = blend ? RGB2YUV(colors[i] & 0xFF, (colors[i] >> 8) & 0xFF, (colors[i] >> 16) & 0xFF) | blend : 0; + yuv = ((yuv & 0xFFFF0000) >> 16) | ((yuv & 0x0000FFFF) << 16); // TODO kls2003-06-15: not sure if this is endian-proof + wdebi(av7110, DEBINOSWAP, DATA_BUFF3_BASE + i*4, yuv, 4); + } + return outcom(av7110, COMTYPE_OSD, Set_Palette, 4, + av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]], first, last); +} + static int OSDSetBlock(struct av7110 *av7110, int x0, int y0, int x1, int y1, int inc, u8 *data) { uint w, h, bpp, bpl, size, lpb, bnum, brest; @@ -1721,6 +1741,9 @@ return 0; case OSD_SetPalette: { + if (FW_VERSION(av7110->arm_app) >= 0x2618) + OSDSetPalette(av7110, (u32 *)dc->data, dc->color, dc->x0); + else { int i, len=dc->x0-dc->color+1; u8 *colors=(u8 *)dc->data; @@ -1728,6 +1751,7 @@ OSDSetColor(av7110, dc->color+i, colors[i*4] , colors[i*4+1], colors[i*4+2], colors[i*4+3]); + } return 0; } case OSD_SetTrans: @@ -2087,28 +2111,28 @@ static inline void TestMode(struct av7110 *av7110, int mode) { - DEB_EE(("av7110: %p\n",av7110)); +// DEB_EE(("av7110: %p\n",av7110)); outcom(av7110, COMTYPE_ENCODER, SetTestMode, 1, mode); } static inline void VidMode(struct av7110 *av7110, int mode) { - DEB_EE(("av7110: %p\n",av7110)); +// DEB_EE(("av7110: %p\n",av7110)); outcom(av7110, COMTYPE_ENCODER, SetVidMode, 1, mode); } -static inline int vidcom(struct av7110 *av7110, u32 com, u32 arg) +static int inline vidcom(struct av7110 *av7110, u32 com, u32 arg) { - DEB_EE(("av7110: %p\n",av7110)); +// DEB_EE(("av7110: %p\n",av7110)); return outcom(av7110, 0x80, 0x02, 4, (com>>16), (com&0xffff), (arg>>16), (arg&0xffff)); } -static inline int audcom(struct av7110 *av7110, u32 com) +static int inline audcom(struct av7110 *av7110, u32 com) { - DEB_EE(("av7110: %p\n",av7110)); +// DEB_EE(("av7110: %p\n",av7110)); return outcom(av7110, 0x80, 0x03, 4, (com>>16), (com&0xffff)); } @@ -2583,38 +2607,274 @@ * V4L SECTION ****************************************************************************/ -int av7110_ioctl(struct saa7146_dev *dev, unsigned int cmd, void *arg) +static struct v4l2_input inputs[2] = { + { 0, "DVB", V4L2_INPUT_TYPE_CAMERA, 1, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 }, + { 1, "ANALOG", V4L2_INPUT_TYPE_TUNER, 2, 1, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 }, +}; + +/* taken from ves1820.c */ +static int ves1820_writereg(struct saa7146_dev *dev, u8 reg, u8 data) +{ + u8 addr = 0x09; + u8 buf[] = { 0x00, reg, data }; + struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = 3 }; + + DEB_EE(("av7710: dev: %p\n",dev)); + + if( 1 != saa7146_i2c_transfer(dev, &msg, 1, 1)) { + return -1; + } + return 0; +} + +static int tuner_write(struct saa7146_dev *dev, u8 addr, u8 data [4]) +{ + struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = data, .len = 4 }; + + DEB_EE(("av7710: dev: %p\n",dev)); + + if( 1 != saa7146_i2c_transfer(dev, &msg, 1, 1)) { + return -1; + } + return 0; +} + + +/** + * set up the downconverter frequency divisor for a + * reference clock comparision frequency of 62.5 kHz. + */ +static int tuner_set_tv_freq (struct saa7146_dev *dev, u32 freq) +{ + u32 div; + u8 config; + u8 buf [4]; + + DEB_EE(("av7710: freq: 0x%08x\n",freq)); + + /* magic number: 56. tuning with the frequency given by v4l2 + is always off by 56*62.5 kHz...*/ + div = freq + 56; + + buf[0] = (div >> 8) & 0x7f; + buf[1] = div & 0xff; + buf[2] = 0x8e; + + if (freq < 16*168.25 ) + config = 0xa0; + else if (freq < 16*447.25) + config = 0x90; + else + config = 0x30; + config &= ~0x02; + + buf[3] = config; + + return tuner_write (dev, 0x61, buf); +} + +static struct saa7146_standard analog_standard[]; +static struct saa7146_standard dvb_standard[]; +static struct saa7146_standard standard[]; + +int av7110_dvb_c_switch(struct saa7146_fh *fh) +{ + struct saa7146_dev *dev = fh->dev; + struct saa7146_vv *vv = dev->vv_data; + struct av7110 *av7110 = (struct av7110*)dev->ext_priv; + u16 buf[3] = { ((COMTYPE_AUDIODAC << 8) + ADSwitch), 1, 1 }; + + u8 band = 0; + int source, sync; + struct saa7146_fh *ov_fh = NULL; + int restart_overlay = 0; + + DEB_EE(("av7110: %p\n",av7110)); + + if( vv->ov_data != NULL ) { + ov_fh = vv->ov_data->fh; + saa7146_stop_preview(ov_fh); + restart_overlay = 1; + } + + if( 0 != av7110->current_input ) { + buf[2] = 0; + band = 0x68; /* analog band */ + source = SAA7146_HPS_SOURCE_PORT_B; + sync = SAA7146_HPS_SYNC_PORT_B; + memcpy(standard,analog_standard,sizeof(struct saa7146_standard)*2); + } else { + buf[2] = 1; + band = 0x28; /* digital band */ + source = SAA7146_HPS_SOURCE_PORT_A; + sync = SAA7146_HPS_SYNC_PORT_A; + memcpy(standard,dvb_standard,sizeof(struct saa7146_standard)*2); + } + + /* hmm, this does not do anything!? */ + if (OutCommand(av7110, buf, 3)) { + printk("ADSwitch error\n"); + } + + if( 0 != ves1820_writereg(dev, 0x0f, band )) { + printk("setting band in demodulator failed.\n"); + } + saa7146_set_hps_source_and_sync(dev, source, sync); + + /* restart overlay if it was active before */ + if( 0 != restart_overlay ) { + saa7146_start_preview(ov_fh); + } + + return 0; +} + +int av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) { + struct saa7146_dev *dev = fh->dev; + struct av7110 *av7110 = (struct av7110*)dev->ext_priv; DEB_EE(("saa7146_dev: %p\n",dev)); switch(cmd) { + case VIDIOC_G_TUNER: + { + struct v4l2_tuner *t = arg; + + DEB_EE(("VIDIOC_G_TUNER: %d\n", t->index)); + + if( 0 == av7110->has_analog_tuner || av7110->current_input != 1 ) { + return -EINVAL; + } + + memset(t,0,sizeof(*t)); + strcpy(t->name, "Television"); + + t->type = V4L2_TUNER_ANALOG_TV; + t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP; + t->rangelow = 772; /* 48.25 MHZ / 62.5 kHz = 772, see fi1216mk2-specs, page 2 */ + t->rangehigh = 13684; /* 855.25 MHz / 62.5 kHz = 13684 */ + /* FIXME: add the real signal strength here */ + t->signal = 0xffff; + t->afc = 0; + /* fixme: real autodetection here */ + t->rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO; + + return 0; + } + case VIDIOC_S_TUNER: + { + struct v4l2_tuner *t = arg; + + DEB_EE(("VIDIOC_S_TUNER: %d\n", t->index)); + + if( 0 == av7110->has_analog_tuner || av7110->current_input != 1 ) { + return -EINVAL; + } + + + switch(t->audmode) { + case V4L2_TUNER_MODE_STEREO: { + DEB_D(("VIDIOC_S_TUNER: V4L2_TUNER_MODE_STEREO\n")); + break; + } + case V4L2_TUNER_MODE_LANG1: { + DEB_D(("VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1\n")); + break; + } + case V4L2_TUNER_MODE_LANG2: { + DEB_D(("VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG2\n")); + break; + } + default: { /* case V4L2_TUNER_MODE_MONO: {*/ + DEB_D(("VIDIOC_S_TUNER: TDA9840_SET_MONO\n")); + break; + } + } + + return 0; + } + case VIDIOC_G_FREQUENCY: + { + struct v4l2_frequency *f = arg; + + DEB_EE(("VIDIOC_G_FREQ: freq:0x%08x.\n", f->frequency)); + + if( 0 == av7110->has_analog_tuner || av7110->current_input != 1 ) { + return -EINVAL; + } + + memset(f,0,sizeof(*f)); + f->type = V4L2_TUNER_ANALOG_TV; + f->frequency = av7110->current_freq; + + return 0; + } + case VIDIOC_S_FREQUENCY: + { + struct v4l2_frequency *f = arg; + + DEB_EE(("VIDIOC_S_FREQUENCY: freq:0x%08x.\n",f->frequency)); + + if( 0 == av7110->has_analog_tuner || av7110->current_input != 1 ) { + return -EINVAL; + } + + if (V4L2_TUNER_ANALOG_TV != f->type) + return -EINVAL; + + /* tune in desired frequency */ + tuner_set_tv_freq(dev, f->frequency); + av7110->current_freq = f->frequency; + + return 0; + } case VIDIOC_ENUMINPUT: { struct v4l2_input *i = arg; + DEB_EE(("VIDIOC_ENUMINPUT: %d\n", i->index)); + + if( 0 != av7110->has_analog_tuner ) { + if( i->index < 0 || i->index >= 2) { + return -EINVAL; + } + } else { if( i->index != 0 ) { return -EINVAL; } + } - memset(i,0,sizeof(*i)); - i->index = 0; - strcpy(i->name, "DVB"); - i->type = V4L2_INPUT_TYPE_CAMERA; - i->audioset = 1; + memcpy(i, &inputs[i->index], sizeof(struct v4l2_input)); return 0; } case VIDIOC_G_INPUT: { int *input = (int *)arg; - *input = 0; + *input = av7110->current_input; + DEB_EE(("VIDIOC_G_INPUT: %d\n", *input)); return 0; } case VIDIOC_S_INPUT: { + int input = *(int *)arg; + + DEB_EE(("VIDIOC_S_INPUT: %d\n", input)); + + if( 0 == av7110->has_analog_tuner ) { return 0; } + + if( input < 0 || input >= 2) { + return -EINVAL; + } + + /* fixme: switch inputs here */ + av7110->current_input = input; + return av7110_dvb_c_switch(fh); + } default: + printk("no such ioctl\n"); return -ENOIOCTLCMD; } return 0; @@ -2997,7 +3257,7 @@ DEB_EE(("av7110: fwstc = %04hx %04hx %04hx %04hx\n", fwstc[0], fwstc[1], fwstc[2], fwstc[3])); - *stc = (((uint64_t)fwstc[2] & 1) << 32) | + *stc = (((uint64_t)(~fwstc[2]) & 1) << 32) | (((uint64_t)fwstc[1]) << 16) | ((uint64_t)fwstc[0]); *base = 1; @@ -4006,7 +4266,6 @@ #endif // } - av7110->dvb_net.card_num=av7110->dvb_adapter->num; dvb_net_init(av7110->dvb_adapter, &av7110->dvb_net, &dvbdemux->dmx); return 0; @@ -4061,9 +4320,16 @@ { VIDIOC_ENUMINPUT, SAA7146_EXCLUSIVE }, { VIDIOC_G_INPUT, SAA7146_EXCLUSIVE }, { VIDIOC_S_INPUT, SAA7146_EXCLUSIVE }, + { VIDIOC_G_FREQUENCY, SAA7146_EXCLUSIVE }, + { VIDIOC_S_FREQUENCY, SAA7146_EXCLUSIVE }, + { VIDIOC_G_TUNER, SAA7146_EXCLUSIVE }, + { VIDIOC_S_TUNER, SAA7146_EXCLUSIVE }, { 0, 0 } }; +static struct saa7146_ext_vv av7110_vv_data_st; +static struct saa7146_ext_vv av7110_vv_data_c; + static int av7110_attach (struct saa7146_dev* dev, struct saa7146_pci_extension_data *pci_ext) { struct av7110 *av7110 = NULL; @@ -4081,7 +4347,16 @@ DEB_EE(("dev: %p, av7110: %p\n",dev,av7110)); - if (saa7146_vv_init(dev)) { + /* special case DVB-C: these cards have an analog tuner + plus need some special handling, so we have separate + saa7146_ext_vv data for these... */ + if (dev->pci->subsystem_vendor == 0x110a) { + ret = saa7146_vv_init(dev, &av7110_vv_data_c); + } else { + ret = saa7146_vv_init(dev, &av7110_vv_data_st); + } + + if ( 0 != ret) { ERR(("cannot init capture device. skipping.\n")); kfree(av7110); return -1; @@ -4114,6 +4389,8 @@ return -ENOMEM; } + ttpci_eeprom_parse_mac(av7110->i2c_bus); + saa7146_write(dev, PCI_BT_V1, 0x1c00101f); saa7146_write(dev, BCS_CTRL, 0x80400040); @@ -4186,9 +4463,9 @@ bootarm(av7110); firmversion(av7110); - if ((av7110->arm_app&0xffff)<0x2501) + if (FW_VERSION(av7110->arm_app)<0x2501) printk ("av7110: Warning, firmware version 0x%04x is too old. " - "System might be unstable!\n", av7110->arm_app&0xffff); + "System might be unstable!\n", FW_VERSION(av7110->arm_app)); kernel_thread(arm_thread, (void *) av7110, 0); @@ -4199,6 +4476,8 @@ VidMode(av7110, vidmode); /* remaining inits according to card and frontend type */ + av7110->has_analog_tuner = 0; + av7110->current_input = 0; if (i2c_writereg(av7110, 0x20, 0x00, 0x00)==1) { printk ("av7110(%d): Crystal audio DAC detected\n", av7110->dvb_adapter->num); @@ -4225,6 +4504,31 @@ msp_writereg(av7110, 0x12, 0x000a, 0x0220); // SCART 1 source msp_writereg(av7110, 0x12, 0x0007, 0x7f00); // SCART 1 volume msp_writereg(av7110, 0x12, 0x000d, 0x4800); // prescale SCART + + if (i2c_writereg(av7110, 0x48, 0x01, 0x00)!=1) { + INFO(("saa7113 not accessible.\n")); + } else { + av7110->has_analog_tuner = 1; + /* init the saa7113 */ + i2c_writereg(av7110, 0x48, 0x02, 0xd0); i2c_writereg(av7110, 0x48, 0x03, 0x23); i2c_writereg(av7110, 0x48, 0x04, 0x00); + i2c_writereg(av7110, 0x48, 0x05, 0x00); i2c_writereg(av7110, 0x48, 0x06, 0xe9); i2c_writereg(av7110, 0x48, 0x07, 0x0d); + i2c_writereg(av7110, 0x48, 0x08, 0x98); i2c_writereg(av7110, 0x48, 0x09, 0x02); i2c_writereg(av7110, 0x48, 0x0a, 0x80); + i2c_writereg(av7110, 0x48, 0x0b, 0x40); i2c_writereg(av7110, 0x48, 0x0c, 0x40); i2c_writereg(av7110, 0x48, 0x0d, 0x00); + i2c_writereg(av7110, 0x48, 0x0e, 0x01); i2c_writereg(av7110, 0x48, 0x0f, 0x7c); i2c_writereg(av7110, 0x48, 0x10, 0x48); + i2c_writereg(av7110, 0x48, 0x11, 0x0c); i2c_writereg(av7110, 0x48, 0x12, 0x8b); i2c_writereg(av7110, 0x48, 0x13, 0x10); + i2c_writereg(av7110, 0x48, 0x14, 0x00); i2c_writereg(av7110, 0x48, 0x15, 0x00); i2c_writereg(av7110, 0x48, 0x16, 0x00); + i2c_writereg(av7110, 0x48, 0x17, 0x00); i2c_writereg(av7110, 0x48, 0x18, 0x00); i2c_writereg(av7110, 0x48, 0x19, 0x00); + i2c_writereg(av7110, 0x48, 0x1a, 0x00); i2c_writereg(av7110, 0x48, 0x1b, 0x00); i2c_writereg(av7110, 0x48, 0x1c, 0x00); + i2c_writereg(av7110, 0x48, 0x1d, 0x00); i2c_writereg(av7110, 0x48, 0x1e, 0x00); + } + + memcpy(standard,dvb_standard,sizeof(struct saa7146_standard)*2); + /* set dd1 stream a & b */ + saa7146_write(dev, DD1_STREAM_B, 0x00000000); + saa7146_write(dev, DD1_INIT, 0x0200700); + saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); + + } else if (dev->pci->subsystem_vendor == 0x110a) { printk("av7110(%d): DVB-C w/o analog module detected\n", av7110->dvb_adapter->num); @@ -4330,6 +4634,16 @@ { "NTSC", V4L2_STD_NTSC, 0x10, 244, 480, 0x40, 708, 709, 480, 640 }, }; +static struct saa7146_standard analog_standard[] = { + { "PAL", V4L2_STD_PAL, 0x18, 288, 576, 0x08, 708, 709, 576, 768 }, + { "NTSC", V4L2_STD_NTSC, 0x10, 244, 480, 0x40, 708, 709, 480, 640 }, +}; + +static struct saa7146_standard dvb_standard[] = { + { "PAL", V4L2_STD_PAL, 0x14, 288, 576, 0x4a, 708, 709, 576, 768 }, + { "NTSC", V4L2_STD_NTSC, 0x10, 244, 480, 0x40, 708, 709, 480, 640 }, +}; + static struct saa7146_extension av7110_extension; #define MAKE_AV7110_INFO(x_var,x_name) \ @@ -4387,7 +4701,7 @@ } -static struct saa7146_ext_vv av7110_vv_data = { +static struct saa7146_ext_vv av7110_vv_data_st = { .inputs = 1, .audios = 1, .capabilities = 0, @@ -4401,9 +4715,23 @@ .ioctl = av7110_ioctl, }; +static struct saa7146_ext_vv av7110_vv_data_c = { + .inputs = 1, + .audios = 1, + .capabilities = V4L2_CAP_TUNER, + .flags = 0, + + .stds = &standard[0], + .num_stds = sizeof(standard)/sizeof(struct saa7146_standard), + .std_callback = &std_callback, + + .ioctls = &ioctls[0], + .ioctl = av7110_ioctl, +}; + + static struct saa7146_extension av7110_extension = { .name = "dvb\0", - .ext_vv_data = &av7110_vv_data, .module = THIS_MODULE, .pci_tbl = &pci_tbl[0], @@ -4442,7 +4770,11 @@ MODULE_PARM(av7110_debug,"i"); MODULE_PARM(vidmode,"i"); +MODULE_PARM_DESC(vidmode,"analog video out: 0 off, 1 CVBS+RGB (default), 2 CVBS+YC, 3 YC"); MODULE_PARM(pids_off,"i"); +MODULE_PARM_DESC(pids_off,"clear video/audio/PCR PID filters when demux is closed"); MODULE_PARM(adac,"i"); +MODULE_PARM_DESC(adac,"audio DAC type: 0 TI, 1 CRYSTAL, 2 MSP (use if autodetection fails)"); MODULE_PARM(hw_sections, "i"); +MODULE_PARM_DESC(hw_sections, "0 use software section filter, 1 use hardware"); diff -Nru a/drivers/media/dvb/ttpci/av7110.h b/drivers/media/dvb/ttpci/av7110.h --- a/drivers/media/dvb/ttpci/av7110.h Sun Jul 27 10:13:40 2003 +++ b/drivers/media/dvb/ttpci/av7110.h Sun Jul 27 10:13:40 2003 @@ -153,7 +153,8 @@ BlitBmp, ReleaseBmp, SetWTrans, - SetWNoTrans + SetWNoTrans, + Set_Palette }; enum av7110_pid_command { @@ -405,6 +406,11 @@ struct dvb_i2c_bus *i2c_bus; char *card_name; + /* support for analog module of dvb-c */ + int has_analog_tuner; + int current_input; + u32 current_freq; + struct tasklet_struct debi_tasklet; struct tasklet_struct gpio_tasklet; @@ -571,6 +577,9 @@ #define DATA_BUFF2_BASE (DATA_BUFF1_BASE+DATA_BUFF1_SIZE) #define DATA_BUFF2_SIZE 0x0800 + +#define DATA_BUFF3_BASE (DATA_BUFF2_BASE+DATA_BUFF2_SIZE) +#define DATA_BUFF3_SIZE 0x0400 #define Reserved (DPRAM_BASE + 0x1E00) #define Reserved_SIZE 0x1C0 diff -Nru a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c --- a/drivers/media/dvb/ttpci/budget-av.c Sun Jul 27 10:13:50 2003 +++ b/drivers/media/dvb/ttpci/budget-av.c Sun Jul 27 10:13:50 2003 @@ -170,6 +170,7 @@ return err; } +static struct saa7146_ext_vv vv_data; static int budget_av_attach (struct saa7146_dev* dev, struct saa7146_pci_extension_data *info) @@ -207,16 +208,22 @@ dvb_delay(500); if ((err = saa7113_init (budget_av))) { - budget_av_detach(dev); + /* fixme: proper cleanup here */ + ERR(("cannot init saa7113.\n")); + return err; + } + + if ( 0 != saa7146_vv_init(dev,&vv_data)) { + /* fixme: proper cleanup here */ + ERR(("cannot init vv subsystem.\n")); return err; } - saa7146_vv_init(dev); if ((err = saa7146_register_device(&budget_av->vd, dev, "knc1", VFL_TYPE_GRABBER))) { + /* fixme: proper cleanup here */ ERR(("cannot register capture v4l2 device.\n")); - budget_av_detach(dev); return err; } @@ -256,8 +263,9 @@ }; -static int av_ioctl(struct saa7146_dev *dev, unsigned int cmd, void *arg) +static int av_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) { + struct saa7146_dev *dev = fh->dev; struct budget_av *budget_av = (struct budget_av*) dev->ext_priv; /* struct saa7146_vv *vv = dev->vv_data; @@ -299,11 +307,19 @@ } static struct saa7146_standard standard[] = { - { "PAL", V4L2_STD_PAL, SAA7146_PAL_VALUES }, - { "NTSC", V4L2_STD_NTSC, SAA7146_NTSC_VALUES }, + { + .name = "PAL", .id = V4L2_STD_PAL, + .v_offset = 0x17, .v_field = 288, .v_calc = 576, + .h_offset = 0x14, .h_pixels = 680, .h_calc = 680+1, + .v_max_out = 576, .h_max_out = 768, + }, { + .name = "NTSC", .id = V4L2_STD_NTSC, + .v_offset = 0x16, .v_field = 240, .v_calc = 480, + .h_offset = 0x06, .h_pixels = 708, .h_calc = 708+1, + .v_max_out = 480, .h_max_out = 640, + } }; - static struct saa7146_ext_vv vv_data = { .inputs = 2, .capabilities = 0, // perhaps later: V4L2_CAP_VBI_CAPTURE, but that need tweaking with the saa7113 @@ -337,8 +353,6 @@ .module = THIS_MODULE, .attach = budget_av_attach, .detach = budget_av_detach, - - .ext_vv_data = &vv_data, .irq_mask = MASK_10, .irq_func = ttpci_budget_irq10_handler, diff -Nru a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c --- a/drivers/media/dvb/ttpci/budget-ci.c Sun Jul 27 10:13:41 2003 +++ b/drivers/media/dvb/ttpci/budget-ci.c Sun Jul 27 10:13:41 2003 @@ -371,7 +371,6 @@ static struct saa7146_extension budget_extension = { .name = "budget_ci dvb\0", .flags = 0, - .ext_vv_data = NULL, .module = THIS_MODULE, .pci_tbl = &pci_tbl[0], diff -Nru a/drivers/media/dvb/ttpci/budget-core.c b/drivers/media/dvb/ttpci/budget-core.c --- a/drivers/media/dvb/ttpci/budget-core.c Sun Jul 27 10:13:43 2003 +++ b/drivers/media/dvb/ttpci/budget-core.c Sun Jul 27 10:13:43 2003 @@ -1,4 +1,5 @@ #include "budget.h" +#include "ttpci-eeprom.h" int budget_debug = 0; @@ -165,7 +166,6 @@ if (ret < 0) return ret; - budget->dvb_net.card_num = budget->dvb_adapter->num; dvb_net_init(budget->dvb_adapter, &budget->dvb_net, &dvbdemux->dmx); return 0; @@ -222,7 +222,7 @@ get recognized before the main driver is loaded */ saa7146_write(dev, GPIO_CTRL, 0x500000); - saa7146_i2c_adapter_prepare(dev, NULL, SAA7146_I2C_BUS_BIT_RATE_3200); + saa7146_i2c_adapter_prepare(dev, NULL, SAA7146_I2C_BUS_BIT_RATE_120); budget->i2c_bus = dvb_register_i2c_bus (master_xfer, dev, budget->dvb_adapter, 0); @@ -231,6 +231,8 @@ dvb_unregister_adapter (budget->dvb_adapter); return -ENOMEM; } + + ttpci_eeprom_parse_mac(budget->i2c_bus); if( NULL == (budget->grabbing = saa7146_vmalloc_build_pgtable(dev->pci,length,&budget->pt))) { ret = -ENOMEM; diff -Nru a/drivers/media/dvb/ttpci/budget-patch.c b/drivers/media/dvb/ttpci/budget-patch.c --- a/drivers/media/dvb/ttpci/budget-patch.c Sun Jul 27 10:13:41 2003 +++ b/drivers/media/dvb/ttpci/budget-patch.c Sun Jul 27 10:13:41 2003 @@ -165,6 +165,7 @@ { struct budget_patch *budget; int err; + int count = 0; if (!(budget = kmalloc (sizeof(struct budget_patch), GFP_KERNEL))) return -ENOMEM; @@ -263,7 +264,6 @@ static struct saa7146_extension budget_extension = { .name = "budget_patch dvb\0", .flags = 0, - .ext_vv_data = NULL, .module = THIS_MODULE, .pci_tbl = pci_tbl, diff -Nru a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c --- a/drivers/media/dvb/ttpci/budget.c Sun Jul 27 10:13:46 2003 +++ b/drivers/media/dvb/ttpci/budget.c Sun Jul 27 10:13:46 2003 @@ -192,6 +192,7 @@ MAKE_BUDGET_INFO(ttbs, "TT-Budget/WinTV-NOVA-S PCI", BUDGET_TT); MAKE_BUDGET_INFO(ttbc, "TT-Budget/WinTV-NOVA-C PCI", BUDGET_TT); MAKE_BUDGET_INFO(ttbt, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT); +MAKE_BUDGET_INFO(ttbt2, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT); MAKE_BUDGET_INFO(satel, "SATELCO Multimedia PCI", BUDGET_TT_HW_DISEQC); /* Uncomment for Budget Patch */ /*MAKE_BUDGET_INFO(fs_1_3,"Siemens/Technotrend/Hauppauge PCI rev1.3+Budget_Patch", BUDGET_PATCH);*/ @@ -202,6 +203,7 @@ MAKE_EXTENSION_PCI(ttbs, 0x13c2, 0x1003), MAKE_EXTENSION_PCI(ttbc, 0x13c2, 0x1004), MAKE_EXTENSION_PCI(ttbt, 0x13c2, 0x1005), + MAKE_EXTENSION_PCI(ttbt2, 0x13c2, 0x1011), MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013), { .vendor = 0, @@ -213,7 +215,6 @@ static struct saa7146_extension budget_extension = { .name = "budget dvb\0", .flags = 0, - .ext_vv_data = NULL, .module = THIS_MODULE, .pci_tbl = pci_tbl, diff -Nru a/drivers/media/dvb/ttpci/ttpci-eeprom.c b/drivers/media/dvb/ttpci/ttpci-eeprom.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/media/dvb/ttpci/ttpci-eeprom.c Sun Jul 27 10:13:53 2003 @@ -0,0 +1,120 @@ +/* + Retrieve encoded MAC address from 24C16 serial 2-wire EEPROM, + decode it and store it in the associated adapter struct for + use by dvb_net.c + + This code was tested on TT-Budget/WinTV-NOVA-CI PCI boards with + Atmel and ST Microelectronics EEPROMs. + + This card appear to have the 24C16 write protect held to ground, + thus permitting normal read/write operation. Theoretically it + would be possible to write routines to burn a different (encoded) + MAC address into the EEPROM. + + Robert Schlabbach GMX + Michael Glaum KVH Industries + Holger Waechtler Convergence + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include +#include +#include + +#include "dvb_i2c.h" +#include "dvb_functions.h" + +#if 1 +#define dprintk(x...) printk(x) +#else +#define dprintk(x...) +#endif + + +static int ttpci_eeprom_read_encodedMAC(struct dvb_i2c_bus *i2c, u8 * encodedMAC) +{ + int ret; + u8 b0[] = { 0xd4 }; + + struct i2c_msg msg[] = { + {.addr = 0x50,.flags = 0,.buf = b0,.len = 1}, + {.addr = 0x50,.flags = I2C_M_RD,.buf = encodedMAC,.len = 6} + }; + + dprintk("%s\n", __FUNCTION__); + + ret = i2c->xfer(i2c, msg, 2); + + if (ret != 2) /* Assume EEPROM isn't there */ + return (-ENODEV); + + return 0; +} + +static void decodeMAC(u8 * decodedMAC, const u8 * encodedMAC) +{ + u8 ormask0[3] = { 0x54, 0x7B, 0x9E }; + u8 ormask1[3] = { 0xD3, 0xF1, 0x23 }; + u8 low; + u8 high; + u8 shift; + int i; + + decodedMAC[0] = 0x00; + decodedMAC[1] = 0xD0; + decodedMAC[2] = 0x5C; + + for (i = 0; i < 3; i++) { + low = encodedMAC[2 * i] ^ ormask0[i]; + high = encodedMAC[2 * i + 1] ^ ormask1[i]; + shift = (high >> 6) & 0x3; + + decodedMAC[5 - i] = ((high << 8) | low) >> shift; + } + +} + + +int ttpci_eeprom_parse_mac(struct dvb_i2c_bus *i2c) +{ + int ret; + u8 encodedMAC[6]; + u8 decodedMAC[6]; + + ret = ttpci_eeprom_read_encodedMAC(i2c, encodedMAC); + + if (ret != 0) { /* Will only be -ENODEV */ + dprintk("Couldn't read from EEPROM: not there?\n"); + memset(i2c->adapter->proposed_mac, 0, 6); + return ret; + } + + decodeMAC(decodedMAC, encodedMAC); + memcpy(i2c->adapter->proposed_mac, decodedMAC, 6); + + dprintk("%s adapter %i has MAC addr = %02x:%02x:%02x:%02x:%02x:%02x\n", + i2c->adapter->name, i2c->adapter->num, + decodedMAC[0], decodedMAC[1], decodedMAC[2], + decodedMAC[3], decodedMAC[4], decodedMAC[5]); + dprintk("encoded MAC was %02x:%02x:%02x:%02x:%02x:%02x\n", + encodedMAC[0], encodedMAC[1], encodedMAC[2], + encodedMAC[3], encodedMAC[4], encodedMAC[5]); + return 0; +} + +EXPORT_SYMBOL(ttpci_eeprom_parse_mac); diff -Nru a/drivers/media/dvb/ttpci/ttpci-eeprom.h b/drivers/media/dvb/ttpci/ttpci-eeprom.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/media/dvb/ttpci/ttpci-eeprom.h Sun Jul 27 10:13:53 2003 @@ -0,0 +1,32 @@ +/* + Retrieve encoded MAC address from ATMEL ttpci_eeprom serial 2-wire EEPROM, + decode it and store it in associated adapter net device + + Robert Schlabbach GMX + Michael Glaum KVH Industries + Holger Waechtler Convergence + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __TTPCI_EEPROM_H__ +#define __TTPCI_EEPROM_H__ + +#include "dvb_i2c.h" + +extern int ttpci_eeprom_parse_mac(struct dvb_i2c_bus *i2c); + +#endif diff -Nru a/drivers/media/dvb/ttusb-budget/Kconfig b/drivers/media/dvb/ttusb-budget/Kconfig --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/media/dvb/ttusb-budget/Kconfig Sun Jul 27 10:13:53 2003 @@ -0,0 +1,11 @@ +config DVB_TTUSB_BUDGET + tristate "Technotrend/Hauppauge Nova-USB devices" + depends on DVB_CORE && USB + help + Support for external USB adapters designed by Technotrend and + produced by Hauppauge, shipped under the brand name 'Nova-USB'. + + These devices don't have a MPEG decoder built in, so you need + an external software decoder to watch TV. + + Say Y if you own such a device and want to use it. diff -Nru a/drivers/media/dvb/ttusb-budget/Makefile b/drivers/media/dvb/ttusb-budget/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/media/dvb/ttusb-budget/Makefile Sun Jul 27 10:13:53 2003 @@ -0,0 +1,3 @@ +obj-$(CONFIG_DVB_TTUSB_BUDGET) += dvb-ttusb-budget.o + +EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ diff -Nru a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c Sun Jul 27 10:13:53 2003 @@ -0,0 +1,1271 @@ +/* + * TTUSB DVB driver + * + * Copyright (c) 2002 Holger Waechtler + * Copyright (c) 2003 Felix Domke + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "dmxdev.h" +#include "dvb_demux.h" +#include "dvb_net.h" + +#include +#include +#include +#include + +#include "dvb_functions.h" + +/* + TTUSB_HWSECTIONS: + the DSP supports filtering in hardware, however, since the "muxstream" + is a bit braindead (no matching channel masks or no matching filter mask), + we won't support this - yet. it doesn't event support negative filters, + so the best way is maybe to keep TTUSB_HWSECTIONS undef'd and just + parse TS data. USB bandwith will be a problem when having large + datastreams, especially for dvb-net, but hey, that's not my problem. + + TTUSB_DISEQC, TTUSB_TONE: + let the STC do the diseqc/tone stuff. this isn't supported at least with + my TTUSB, so let it undef'd unless you want to implement another + frontend. never tested. + + DEBUG: + define it to > 3 for really hardcore debugging. you probably don't want + this unless the device doesn't load at all. > 2 for bandwidth statistics. +*/ + +static int debug = 0; + +#define dprintk(x...) do { if (debug) printk(KERN_DEBUG x); } while (0) + +#define ISO_BUF_COUNT 4 +#define FRAMES_PER_ISO_BUF 4 +#define ISO_FRAME_SIZE 912 +#define TTUSB_MAXCHANNEL 32 +#ifdef TTUSB_HWSECTIONS +#define TTUSB_MAXFILTER 16 /* ??? */ +#endif + +#define TTUSB_BUDGET_NAME "ttusb_stc_fw" + +/** + * since we're casting (struct ttusb*) <-> (struct dvb_demux*) around + * the dvb_demux field must be the first in struct!! + */ +struct ttusb { + struct dvb_demux dvb_demux; + struct dmxdev dmxdev; + struct dvb_net dvbnet; + + /* our semaphore, for channel allocation/deallocation */ + struct semaphore sem; + /* and one for USB access. */ + struct semaphore semusb; + + struct dvb_adapter *adapter; + struct usb_device *dev; + + int disconnecting; + int iso_streaming; + + unsigned int bulk_out_pipe; + unsigned int bulk_in_pipe; + unsigned int isoc_in_pipe; + + void *iso_buffer; + dma_addr_t iso_dma_handle; + + struct urb *iso_urb[ISO_BUF_COUNT]; + + int running_feed_count; + int last_channel; + int last_filter; + + u8 c; /* transaction counter, wraps around... */ + fe_sec_tone_mode_t tone; + fe_sec_voltage_t voltage; + + int mux_state; // 0..2 - MuxSyncWord, 3 - nMuxPacks, 4 - muxpack + u8 mux_npacks; + u8 muxpack[256 + 8]; + int muxpack_ptr, muxpack_len; + + int insync; + + u16 cc; /* MuxCounter - will increment on EVERY MUX PACKET */ + /* (including stuffing. yes. really.) */ + + u8 last_result[32]; + + struct ttusb_channel { + struct ttusb *ttusb; + struct dvb_demux_feed *dvbdmxfeed; + + int active; + int id; + int pid; + int type; /* 1 - TS, 2 - Filter */ +#ifdef TTUSB_HWSECTIONS + int filterstate[TTUSB_MAXFILTER]; /* 0: not busy, 1: busy */ +#endif + } channel[TTUSB_MAXCHANNEL]; +#if 0 + devfs_handle_t stc_devfs_handle; +#endif +}; + +/* ugly workaround ... don't know why it's neccessary to read */ +/* all result codes. */ + +#define DEBUG 0 +static int ttusb_cmd(struct ttusb *ttusb, + const u8 * data, int len, int needresult) +{ + int actual_len; + int err; +#if DEBUG >= 3 + int i; + + printk(">"); + for (i = 0; i < len; ++i) + printk(" %02x", data[i]); + printk("\n"); +#endif + + if (down_interruptible(&ttusb->semusb) < 0) + return -EAGAIN; + + err = usb_bulk_msg(ttusb->dev, ttusb->bulk_out_pipe, + (u8 *) data, len, &actual_len, HZ); + if (err != 0) { + dprintk("%s: usb_bulk_msg(send) failed, err == %i!\n", + __FUNCTION__, err); + up(&ttusb->semusb); + return err; + } + if (actual_len != len) { + dprintk("%s: only wrote %d of %d bytes\n", __FUNCTION__, + actual_len, len); + up(&ttusb->semusb); + return -1; + } + + err = usb_bulk_msg(ttusb->dev, ttusb->bulk_in_pipe, + ttusb->last_result, 32, &actual_len, HZ); + + if (err != 0) { + printk("%s: failed, receive error %d\n", __FUNCTION__, + err); + up(&ttusb->semusb); + return err; + } +#if DEBUG >= 3 + actual_len = ttusb->last_result[3] + 4; + printk("<"); + for (i = 0; i < actual_len; ++i) + printk(" %02x", ttusb->last_result[i]); + printk("\n"); +#endif + if (!needresult) + up(&ttusb->semusb); + return 0; +} + +static int ttusb_result(struct ttusb *ttusb, u8 * data, int len) +{ + memcpy(data, ttusb->last_result, len); + up(&ttusb->semusb); + return 0; +} + +static int ttusb_i2c_msg(struct ttusb *ttusb, + u8 addr, u8 * snd_buf, u8 snd_len, u8 * rcv_buf, + u8 rcv_len) +{ + u8 b[0x28]; + u8 id = ++ttusb->c; + int i, err; + + if (snd_len > 0x28 - 7 || rcv_len > 0x20 - 7) + return -EINVAL; + + b[0] = 0xaa; + b[1] = id; + b[2] = 0x31; + b[3] = snd_len + 3; + b[4] = addr << 1; + b[5] = snd_len; + b[6] = rcv_len; + + for (i = 0; i < snd_len; i++) + b[7 + i] = snd_buf[i]; + + err = ttusb_cmd(ttusb, b, snd_len + 7, 1); + + if (err) + return -EREMOTEIO; + + err = ttusb_result(ttusb, b, 0x20); + + if (rcv_len > 0) { + + if (err || b[0] != 0x55 || b[1] != id) { + dprintk + ("%s: usb_bulk_msg(recv) failed, err == %i, id == %02x, b == ", + __FUNCTION__, err, id); + return -EREMOTEIO; + } + + for (i = 0; i < rcv_len; i++) + rcv_buf[i] = b[7 + i]; + } + + return rcv_len; +} + +static int ttusb_i2c_xfer(struct dvb_i2c_bus *i2c, const struct i2c_msg msg[], + int num) +{ + struct ttusb *ttusb = i2c->data; + int i = 0; + int inc; + + if (down_interruptible(&ttusb->sem) < 0) + return -EAGAIN; + + while (i < num) { + u8 addr, snd_len, rcv_len, *snd_buf, *rcv_buf; + int err; + + if (num > i + 1 && (msg[i + 1].flags & I2C_M_RD)) { + addr = msg[i].addr; + snd_buf = msg[i].buf; + snd_len = msg[i].len; + rcv_buf = msg[i + 1].buf; + rcv_len = msg[i + 1].len; + inc = 2; + } else { + addr = msg[i].addr; + snd_buf = msg[i].buf; + snd_len = msg[i].len; + rcv_buf = NULL; + rcv_len = 0; + inc = 1; + } + + err = ttusb_i2c_msg(ttusb, addr, + snd_buf, snd_len, rcv_buf, rcv_len); + + if (err < rcv_len) { + printk("%s: i == %i\n", __FUNCTION__, i); + break; + } + + i += inc; + } + + up(&ttusb->sem); + return i; +} + +#include "dvb-ttusb-dspbootcode.h" + +static int ttusb_boot_dsp(struct ttusb *ttusb) +{ + int i, err; + u8 b[40]; + + /* BootBlock */ + b[0] = 0xaa; + b[2] = 0x13; + b[3] = 28; + + /* upload dsp code in 32 byte steps (36 didn't work for me ...) */ + /* 32 is max packet size, no messages should be splitted. */ + for (i = 0; i < sizeof(dsp_bootcode); i += 28) { + memcpy(&b[4], &dsp_bootcode[i], 28); + + b[1] = ++ttusb->c; + + err = ttusb_cmd(ttusb, b, 32, 0); + if (err) + goto done; + } + + /* last block ... */ + b[1] = ++ttusb->c; + b[2] = 0x13; + b[3] = 0; + + err = ttusb_cmd(ttusb, b, 4, 0); + if (err) + goto done; + + /* BootEnd */ + b[1] = ++ttusb->c; + b[2] = 0x14; + b[3] = 0; + + err = ttusb_cmd(ttusb, b, 4, 0); + + done: + if (err) { + dprintk("%s: usb_bulk_msg() failed, return value %i!\n", + __FUNCTION__, err); + } + + return err; +} + +static int ttusb_set_channel(struct ttusb *ttusb, int chan_id, int filter_type, + int pid) +{ + int err; + /* SetChannel */ + u8 b[] = { 0xaa, ++ttusb->c, 0x22, 4, chan_id, filter_type, + (pid >> 8) & 0xff, pid & 0xff + }; + + err = ttusb_cmd(ttusb, b, sizeof(b), 0); + return err; +} + +static int ttusb_del_channel(struct ttusb *ttusb, int channel_id) +{ + int err; + /* DelChannel */ + u8 b[] = { 0xaa, ++ttusb->c, 0x23, 1, channel_id }; + + err = ttusb_cmd(ttusb, b, sizeof(b), 0); + return err; +} + +#ifdef TTUSB_HWSECTIONS +static int ttusb_set_filter(struct ttusb *ttusb, int filter_id, + int associated_chan, u8 filter[8], u8 mask[8]) +{ + int err; + /* SetFilter */ + u8 b[] = { 0xaa, 0, 0x24, 0x1a, filter_id, associated_chan, + filter[0], filter[1], filter[2], filter[3], + filter[4], filter[5], filter[6], filter[7], + filter[8], filter[9], filter[10], filter[11], + mask[0], mask[1], mask[2], mask[3], + mask[4], mask[5], mask[6], mask[7], + mask[8], mask[9], mask[10], mask[11] + }; + + err = ttusb_cmd(ttusb, b, sizeof(b), 0); + return err; +} + +static int ttusb_del_filter(struct ttusb *ttusb, int filter_id) +{ + int err; + /* DelFilter */ + u8 b[] = { 0xaa, ++ttusb->c, 0x25, 1, filter_id }; + + err = ttusb_cmd(ttusb, b, sizeof(b), 0); + return err; +} +#endif + +static int ttusb_init_controller(struct ttusb *ttusb) +{ + u8 b0[] = { 0xaa, ++ttusb->c, 0x15, 1, 0 }; + u8 b1[] = { 0xaa, ++ttusb->c, 0x15, 1, 1 }; + u8 b2[] = { 0xaa, ++ttusb->c, 0x32, 1, 0 }; + /* i2c write read: 5 bytes, addr 0x10, 0x02 bytes write, 1 bytes read. */ + u8 b3[] = + { 0xaa, ++ttusb->c, 0x31, 5, 0x10, 0x02, 0x01, 0x00, 0x1e }; + u8 b4[] = + { 0x55, ttusb->c, 0x31, 4, 0x10, 0x02, 0x01, 0x00, 0x1e }; + + u8 get_version[] = { 0xaa, ++ttusb->c, 0x17, 5, 0, 0, 0, 0, 0 }; + u8 get_dsp_version[0x20] = + { 0xaa, ++ttusb->c, 0x26, 28, 0, 0, 0, 0, 0 }; + int err; + + /* reset board */ + if ((err = ttusb_cmd(ttusb, b0, sizeof(b0), 0))) + return err; + + /* reset board (again?) */ + if ((err = ttusb_cmd(ttusb, b1, sizeof(b1), 0))) + return err; + + ttusb_boot_dsp(ttusb); + + /* set i2c bit rate */ + if ((err = ttusb_cmd(ttusb, b2, sizeof(b2), 0))) + return err; + + if ((err = ttusb_cmd(ttusb, b3, sizeof(b3), 1))) + return err; + + err = ttusb_result(ttusb, b4, sizeof(b4)); + + if ((err = ttusb_cmd(ttusb, get_version, sizeof(get_version), 1))) + return err; + + if ((err = ttusb_result(ttusb, get_version, sizeof(get_version)))) + return err; + + dprintk("%s: stc-version: %c%c%c%c%c\n", __FUNCTION__, + get_version[4], get_version[5], get_version[6], + get_version[7], get_version[8]); + + if (memcmp(get_version + 4, "V 0.0", 5) && + memcmp(get_version + 4, "V 1.1", 5)) { + printk + ("%s: unknown STC version %c%c%c%c%c, please report!\n", + __FUNCTION__, get_version[4], get_version[5], + get_version[6], get_version[7], get_version[8]); + } + + err = + ttusb_cmd(ttusb, get_dsp_version, sizeof(get_dsp_version), 1); + if (err) + return err; + + err = + ttusb_result(ttusb, get_dsp_version, sizeof(get_dsp_version)); + if (err) + return err; + printk("%s: dsp-version: %c%c%c\n", __FUNCTION__, + get_dsp_version[4], get_dsp_version[5], get_dsp_version[6]); + return 0; +} + +#ifdef TTUSB_DISEQC +static int ttusb_send_diseqc(struct ttusb *ttusb, + const struct dvb_diseqc_master_cmd *cmd) +{ + u8 b[12] = { 0xaa, ++ttusb->c, 0x18 }; + + int err; + + b[3] = 4 + 2 + cmd->msg_len; + b[4] = 0xFF; /* send diseqc master, not burst */ + b[5] = cmd->msg_len; + + memcpy(b + 5, cmd->msg, cmd->msg_len); + + /* Diseqc */ + if ((err = ttusb_cmd(ttusb, b, 4 + b[3], 0))) { + dprintk("%s: usb_bulk_msg() failed, return value %i!\n", + __FUNCTION__, err); + } + + return err; +} +#endif + +static int ttusb_update_lnb(struct ttusb *ttusb) +{ + u8 b[] = { 0xaa, ++ttusb->c, 0x16, 5, /*power: */ 1, + ttusb->voltage == SEC_VOLTAGE_18 ? 0 : 1, + ttusb->tone == SEC_TONE_ON ? 1 : 0, 1, 1 + }; + int err; + + /* SetLNB */ + if ((err = ttusb_cmd(ttusb, b, sizeof(b), 0))) { + dprintk("%s: usb_bulk_msg() failed, return value %i!\n", + __FUNCTION__, err); + } + + return err; +} + +static int ttusb_set_voltage(struct ttusb *ttusb, fe_sec_voltage_t voltage) +{ + ttusb->voltage = voltage; + return ttusb_update_lnb(ttusb); +} + +#ifdef TTUSB_TONE +static int ttusb_set_tone(struct ttusb *ttusb, fe_sec_tone_mode_t tone) +{ + ttusb->tone = tone; + return ttusb_update_lnb(ttusb); +} +#endif + +static int ttusb_lnb_ioctl(struct dvb_frontend *fe, unsigned int cmd, void *arg) +{ + struct ttusb *ttusb = fe->i2c->data; + + switch (cmd) { + case FE_SET_VOLTAGE: + return ttusb_set_voltage(ttusb, (fe_sec_voltage_t) arg); +#ifdef TTUSB_TONE + case FE_SET_TONE: + return ttusb_set_tone(ttusb, (fe_sec_tone_mode_t) arg); +#endif +#ifdef TTUSB_DISEQC + case FE_DISEQC_SEND_MASTER_CMD: + return ttusb_send_diseqc(ttusb, + (struct dvb_diseqc_master_cmd *) + arg); +#endif + default: + return -EOPNOTSUPP; + }; +} + +#if 0 +static void ttusb_set_led_freq(struct ttusb *ttusb, u8 freq) +{ + u8 b[] = { 0xaa, ++ttusb->c, 0x19, 1, freq }; + int err, actual_len; + + err = ttusb_cmd(ttusb, b, sizeof(b), 0); + if (err) { + dprintk("%s: usb_bulk_msg() failed, return value %i!\n", + __FUNCTION__, err); + } +} +#endif + +/*****************************************************************************/ + +#ifdef TTUSB_HWSECTIONS +static void ttusb_handle_ts_data(struct ttusb_channel *channel, + const u8 * data, int len); +static void ttusb_handle_sec_data(struct ttusb_channel *channel, + const u8 * data, int len); +#endif + +int numpkt = 0, lastj, numts, numstuff, numsec, numinvalid; + +static void ttusb_process_muxpack(struct ttusb *ttusb, const u8 * muxpack, + int len) +{ + u16 csum = 0, cc; + int i; + for (i = 0; i < len; i += 2) + csum ^= le16_to_cpup((u16 *) (muxpack + i)); + if (csum) { + printk("%s: muxpack with incorrect checksum, ignoring\n", + __FUNCTION__); + numinvalid++; + return; + } + + cc = (muxpack[len - 4] << 8) | muxpack[len - 3]; + cc &= 0x7FFF; + if (cc != ttusb->cc) + printk("%s: cc discontinuity (%d frames missing)\n", + __FUNCTION__, (cc - ttusb->cc) & 0x7FFF); + ttusb->cc = (cc + 1) & 0x7FFF; + if (muxpack[0] & 0x80) { +#ifdef TTUSB_HWSECTIONS + /* section data */ + int pusi = muxpack[0] & 0x40; + int channel = muxpack[0] & 0x1F; + int payload = muxpack[1]; + const u8 *data = muxpack + 2; + /* check offset flag */ + if (muxpack[0] & 0x20) + data++; + + ttusb_handle_sec_data(ttusb->channel + channel, data, + payload); + data += payload; + + if ((!!(ttusb->muxpack[0] & 0x20)) ^ + !!(ttusb->muxpack[1] & 1)) + data++; +#warning TODO: pusi + printk("cc: %04x\n", (data[0] << 8) | data[1]); +#endif + numsec++; + } else if (muxpack[0] == 0x47) { +#ifdef TTUSB_HWSECTIONS + /* we have TS data here! */ + int pid = ((muxpack[1] & 0x0F) << 8) | muxpack[2]; + int channel; + for (channel = 0; channel < TTUSB_MAXCHANNEL; ++channel) + if (ttusb->channel[channel].active + && (pid == ttusb->channel[channel].pid)) + ttusb_handle_ts_data(ttusb->channel + + channel, muxpack, + 188); +#endif + numts++; + dvb_dmx_swfilter_packets(&ttusb->dvb_demux, muxpack, 1); + } else if (muxpack[0] != 0) { + numinvalid++; + printk("illegal muxpack type %02x\n", muxpack[0]); + } else + numstuff++; +} + +static void ttusb_process_frame(struct ttusb *ttusb, u8 * data, int len) +{ + int maxwork = 1024; + while (len) { + if (!(maxwork--)) { + printk("%s: too much work\n", __FUNCTION__); + break; + } + + switch (ttusb->mux_state) { + case 0: + case 1: + case 2: + len--; + if (*data++ == 0xAA) + ++ttusb->mux_state; + else { + ttusb->mux_state = 0; +#if DEBUG > 3 + if (ttusb->insync) + printk("%02x ", data[-1]); +#else + if (ttusb->insync) { + printk("%s: lost sync.\n", + __FUNCTION__); + ttusb->insync = 0; + } +#endif + } + break; + case 3: + ttusb->insync = 1; + len--; + ttusb->mux_npacks = *data++; + ++ttusb->mux_state; + ttusb->muxpack_ptr = 0; + /* maximum bytes, until we know the length */ + ttusb->muxpack_len = 2; + break; + case 4: + { + int avail; + avail = len; + if (avail > + (ttusb->muxpack_len - + ttusb->muxpack_ptr)) + avail = + ttusb->muxpack_len - + ttusb->muxpack_ptr; + memcpy(ttusb->muxpack + ttusb->muxpack_ptr, + data, avail); + ttusb->muxpack_ptr += avail; + if (ttusb->muxpack_ptr > 264) + BUG(); + data += avail; + len -= avail; + /* determine length */ + if (ttusb->muxpack_ptr == 2) { + if (ttusb->muxpack[0] & 0x80) { + ttusb->muxpack_len = + ttusb->muxpack[1] + 2; + if (ttusb-> + muxpack[0] & 0x20) + ttusb-> + muxpack_len++; + if ((!! + (ttusb-> + muxpack[0] & 0x20)) ^ + !!(ttusb-> + muxpack[1] & 1)) + ttusb-> + muxpack_len++; + ttusb->muxpack_len += 4; + } else if (ttusb->muxpack[0] == + 0x47) + ttusb->muxpack_len = + 188 + 4; + else if (ttusb->muxpack[0] == 0x00) + ttusb->muxpack_len = + ttusb->muxpack[1] + 2 + + 4; + else { + dprintk + ("%s: invalid state: first byte is %x\n", + __FUNCTION__, + ttusb->muxpack[0]); + ttusb->mux_state = 0; + } + } + + /** + * if length is valid and we reached the end: + * goto next muxpack + */ + if ((ttusb->muxpack_ptr >= 2) && + (ttusb->muxpack_ptr == + ttusb->muxpack_len)) { + ttusb_process_muxpack(ttusb, + ttusb-> + muxpack, + ttusb-> + muxpack_ptr); + ttusb->muxpack_ptr = 0; + /* maximum bytes, until we know the length */ + ttusb->muxpack_len = 2; + + /** + * no muxpacks left? + * return to search-sync state + */ + if (!ttusb->mux_npacks--) { + ttusb->mux_state = 0; + break; + } + } + break; + } + default: + BUG(); + break; + } + } +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +static void ttusb_iso_irq(struct urb *urb) +#else +static void ttusb_iso_irq(struct urb *urb, struct pt_regs *ptregs) +#endif +{ + struct ttusb *ttusb = urb->context; + + if (!ttusb->iso_streaming) + return; + +#if 0 + printk("%s: status %d, errcount == %d, length == %i\n", + __FUNCTION__, + urb->status, urb->error_count, urb->actual_length); +#endif + + if (!urb->status) { + int i; + for (i = 0; i < urb->number_of_packets; ++i) { + struct usb_iso_packet_descriptor *d; + u8 *data; + int len; + numpkt++; + if ((jiffies - lastj) >= HZ) { +#if DEBUG > 2 + printk + ("frames/s: %d (ts: %d, stuff %d, sec: %d, invalid: %d, all: %d)\n", + numpkt * HZ / (jiffies - lastj), + numts, numstuff, numsec, numinvalid, + numts + numstuff + numsec + + numinvalid); +#endif + numts = numstuff = numsec = numinvalid = 0; + lastj = jiffies; + numpkt = 0; + } + d = &urb->iso_frame_desc[i]; + data = urb->transfer_buffer + d->offset; + len = d->actual_length; + d->actual_length = 0; + d->status = 0; + ttusb_process_frame(ttusb, data, len); + } + } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) + usb_submit_urb(urb, GFP_KERNEL); +#endif +} + +static void ttusb_free_iso_urbs(struct ttusb *ttusb) +{ + int i; + + for (i = 0; i < ISO_BUF_COUNT; i++) + if (ttusb->iso_urb[i]) + usb_free_urb(ttusb->iso_urb[i]); + + pci_free_consistent(NULL, + ISO_FRAME_SIZE * FRAMES_PER_ISO_BUF * + ISO_BUF_COUNT, ttusb->iso_buffer, + ttusb->iso_dma_handle); +} + +static int ttusb_alloc_iso_urbs(struct ttusb *ttusb) +{ + int i; + + ttusb->iso_buffer = pci_alloc_consistent(NULL, + ISO_FRAME_SIZE * + FRAMES_PER_ISO_BUF * + ISO_BUF_COUNT, + &ttusb->iso_dma_handle); + + memset(ttusb->iso_buffer, 0, + ISO_FRAME_SIZE * FRAMES_PER_ISO_BUF * ISO_BUF_COUNT); + + for (i = 0; i < ISO_BUF_COUNT; i++) { + struct urb *urb; + + if (! + (urb = + usb_alloc_urb(FRAMES_PER_ISO_BUF, GFP_KERNEL))) { + ttusb_free_iso_urbs(ttusb); + return -ENOMEM; + } + + ttusb->iso_urb[i] = urb; + } + + return 0; +} + +static void ttusb_stop_iso_xfer(struct ttusb *ttusb) +{ + int i; + + for (i = 0; i < ISO_BUF_COUNT; i++) + usb_unlink_urb(ttusb->iso_urb[i]); + + ttusb->iso_streaming = 0; +} + +static int ttusb_start_iso_xfer(struct ttusb *ttusb) +{ + int i, j, err, buffer_offset = 0; + + if (ttusb->iso_streaming) { + printk("%s: iso xfer already running!\n", __FUNCTION__); + return 0; + } + + ttusb->insync = 0; + ttusb->mux_state = 0; + + for (i = 0; i < ISO_BUF_COUNT; i++) { + int frame_offset = 0; + struct urb *urb = ttusb->iso_urb[i]; + + urb->dev = ttusb->dev; + urb->context = ttusb; + urb->complete = ttusb_iso_irq; + urb->pipe = ttusb->isoc_in_pipe; + urb->transfer_flags = URB_ISO_ASAP; + urb->number_of_packets = FRAMES_PER_ISO_BUF; + urb->transfer_buffer_length = + ISO_FRAME_SIZE * FRAMES_PER_ISO_BUF; + urb->transfer_buffer = ttusb->iso_buffer + buffer_offset; + buffer_offset += ISO_FRAME_SIZE * FRAMES_PER_ISO_BUF; + + for (j = 0; j < FRAMES_PER_ISO_BUF; j++) { + urb->iso_frame_desc[j].offset = frame_offset; + urb->iso_frame_desc[j].length = ISO_FRAME_SIZE; + frame_offset += ISO_FRAME_SIZE; + } + } + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) + for (i = 0; i < ISO_BUF_COUNT; i++) { + int next = (i + 1) % ISO_BUF_COUNT; + ttusb->iso_urb[i]->next = ttusb->iso_urb[next]; + } +#endif + + for (i = 0; i < ISO_BUF_COUNT; i++) { + if ((err = usb_submit_urb(ttusb->iso_urb[i], GFP_KERNEL))) { + ttusb_stop_iso_xfer(ttusb); + printk + ("%s: failed urb submission (%i: err = %i)!\n", + __FUNCTION__, i, err); + return err; + } + } + + ttusb->iso_streaming = 1; + + return 0; +} + +#ifdef TTUSB_HWSECTIONS +static void ttusb_handle_ts_data(struct ttusb_channel *channel, const u8 * data, + int len) +{ + struct dvb_demux_feed *dvbdmxfeed = channel->dvbdmxfeed; + + dvbdmxfeed->cb.ts(data, len, 0, 0, &dvbdmxfeed->feed.ts, 0); +} + +static void ttusb_handle_sec_data(struct ttusb_channel *channel, const u8 * data, + int len) +{ +// struct dvb_demux_feed *dvbdmxfeed = channel->dvbdmxfeed; +#error TODO: handle ugly stuff +// dvbdmxfeed->cb.sec(data, len, 0, 0, &dvbdmxfeed->feed.sec, 0); +} +#endif + +static struct ttusb_channel *ttusb_channel_allocate(struct ttusb *ttusb) +{ + int i; + + if (down_interruptible(&ttusb->sem)) + return NULL; + + /* lock! */ + for (i = 0; i < TTUSB_MAXCHANNEL; ++i) { + if (!ttusb->channel[i].active) { + ttusb->channel[i].active = 1; + up(&ttusb->sem); + return ttusb->channel + i; + } + } + + up(&ttusb->sem); + + return NULL; +} + +static int ttusb_start_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + struct ttusb *ttusb = (struct ttusb *) dvbdmxfeed->demux; + struct ttusb_channel *channel; + + printk("ttusb_start_feed\n"); + + switch (dvbdmxfeed->type) { + case DMX_TYPE_TS: + break; + case DMX_TYPE_SEC: + break; + default: + return -EINVAL; + } + + if (dvbdmxfeed->type == DMX_TYPE_TS) { + switch (dvbdmxfeed->pes_type) { + case DMX_TS_PES_VIDEO: + case DMX_TS_PES_AUDIO: + case DMX_TS_PES_TELETEXT: + case DMX_TS_PES_PCR: + case DMX_TS_PES_OTHER: + channel = ttusb_channel_allocate(ttusb); + break; + default: + return -EINVAL; + } + } else { + channel = ttusb_channel_allocate(ttusb); + } + + if (!channel) + return -EBUSY; + + dvbdmxfeed->priv = channel; + channel->dvbdmxfeed = dvbdmxfeed; + + channel->pid = dvbdmxfeed->pid; + +#ifdef TTUSB_HWSECTIONS + if (dvbdmxfeed->type == DMX_TYPE_TS) { + channel->type = 1; + } else if (dvbdmxfeed->type == DMX_TYPE_SEC) { + channel->type = 2; +#error TODO: allocate filters + } +#else + channel->type = 1; +#endif + + ttusb_set_channel(ttusb, channel->id, channel->type, channel->pid); + + if (0 == ttusb->running_feed_count++) + ttusb_start_iso_xfer(ttusb); + + return 0; +} + +static int ttusb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + struct ttusb_channel *channel = + (struct ttusb_channel *) dvbdmxfeed->priv; + struct ttusb *ttusb = (struct ttusb *) dvbdmxfeed->demux; + + ttusb_del_channel(channel->ttusb, channel->id); + + if (--ttusb->running_feed_count == 0) + ttusb_stop_iso_xfer(ttusb); + + channel->active = 0; + + return 0; +} + +static int ttusb_setup_interfaces(struct ttusb *ttusb) +{ + usb_set_configuration(ttusb->dev, 1); + usb_set_interface(ttusb->dev, 1, 1); + + ttusb->bulk_out_pipe = usb_sndbulkpipe(ttusb->dev, 1); + ttusb->bulk_in_pipe = usb_rcvbulkpipe(ttusb->dev, 1); + ttusb->isoc_in_pipe = usb_rcvisocpipe(ttusb->dev, 2); + + return 0; +} + +#if 0 +static u8 stc_firmware[8192]; + +static int stc_open(struct inode *inode, struct file *file) +{ + struct ttusb *ttusb = file->private_data; + int addr; + + for (addr = 0; addr < 8192; addr += 16) { + u8 snd_buf[2] = { addr >> 8, addr & 0xFF }; + ttusb_i2c_msg(ttusb, 0x50, snd_buf, 2, stc_firmware + addr, + 16); + } + + return 0; +} + +static ssize_t stc_read(struct file *file, char *buf, size_t count, + loff_t * offset) +{ + int tc = count; + + if ((tc + *offset) > 8192) + tc = 8192 - *offset; + + if (tc < 0) + return 0; + + copy_to_user(buf, stc_firmware + *offset, tc); + + *offset += tc; + + return tc; +} + +static int stc_release(struct inode *inode, struct file *file) +{ + return 0; +} + +static struct file_operations stc_fops = { + .owner = THIS_MODULE, + .read = stc_read, + .open = stc_open, + .release = stc_release, +}; +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +static void *ttusb_probe(struct usb_device *udev, unsigned int ifnum, + const struct usb_device_id *id) +{ + struct ttusb *ttusb; + int result, channel; + + if (ifnum != 0) + return NULL; + + dprintk("%s: TTUSB DVB connected\n", __FUNCTION__); + + if (!(ttusb = kmalloc(sizeof(struct ttusb), GFP_KERNEL))) + return NULL; + +#else +static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *id) +{ + struct usb_device *udev; + struct ttusb *ttusb; + int result, channel; + + dprintk("%s: TTUSB DVB connected\n", __FUNCTION__); + + udev = interface_to_usbdev(intf); + + if (!(ttusb = kmalloc(sizeof(struct ttusb), GFP_KERNEL))) + return -ENOMEM; + +#endif + + memset(ttusb, 0, sizeof(struct ttusb)); + + for (channel = 0; channel < TTUSB_MAXCHANNEL; ++channel) { + ttusb->channel[channel].id = channel; + ttusb->channel[channel].ttusb = ttusb; + } + + ttusb->dev = udev; + ttusb->c = 0; + ttusb->mux_state = 0; + sema_init(&ttusb->sem, 0); + sema_init(&ttusb->semusb, 1); + + ttusb_setup_interfaces(ttusb); + + ttusb_alloc_iso_urbs(ttusb); + if (ttusb_init_controller(ttusb)) + printk("ttusb_init_controller: error\n"); + + up(&ttusb->sem); + + dvb_register_adapter(&ttusb->adapter, + "Technotrend/Hauppauge Nova-USB"); + + dvb_register_i2c_bus(ttusb_i2c_xfer, ttusb, ttusb->adapter, 0); + dvb_add_frontend_ioctls(ttusb->adapter, ttusb_lnb_ioctl, NULL, + ttusb); + + memset(&ttusb->dvb_demux, 0, sizeof(ttusb->dvb_demux)); + + ttusb->dvb_demux.dmx.capabilities = + DMX_TS_FILTERING | DMX_SECTION_FILTERING; + ttusb->dvb_demux.priv = 0; +#ifdef TTUSB_HWSECTIONS + ttusb->dvb_demux.filternum = TTUSB_MAXFILTER; +#else + ttusb->dvb_demux.filternum = 32; +#endif + ttusb->dvb_demux.feednum = TTUSB_MAXCHANNEL; + ttusb->dvb_demux.start_feed = ttusb_start_feed; + ttusb->dvb_demux.stop_feed = ttusb_stop_feed; + ttusb->dvb_demux.write_to_decoder = 0; + + if ((result = dvb_dmx_init(&ttusb->dvb_demux)) < 0) { + printk("ttusb_dvb: dvb_dmx_init failed (errno = %d)\n", + result); + goto err; + } +//FIXME dmxdev (nur WAS?) + ttusb->dmxdev.filternum = ttusb->dvb_demux.filternum; + ttusb->dmxdev.demux = &ttusb->dvb_demux.dmx; + ttusb->dmxdev.capabilities = 0; + + if ((result = dvb_dmxdev_init(&ttusb->dmxdev, ttusb->adapter)) < 0) { + printk("ttusb_dvb: dvb_dmxdev_init failed (errno = %d)\n", + result); + dvb_dmx_release(&ttusb->dvb_demux); + goto err; + } + + if (dvb_net_init + (ttusb->adapter, &ttusb->dvbnet, &ttusb->dvb_demux.dmx)) { + printk("ttusb_dvb: dvb_net_init failed!\n"); + } + + err: +#if 0 + ttusb->stc_devfs_handle = + devfs_register(ttusb->adapter->devfs_handle, TTUSB_BUDGET_NAME, + DEVFS_FL_DEFAULT, 0, 192, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP + | S_IROTH | S_IWOTH, &stc_fops, ttusb); +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) + return (void *) ttusb; +#else + usb_set_intfdata(intf, (void *) ttusb); + + return 0; +#endif +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +static void ttusb_disconnect(struct usb_device *udev, void *data) +{ + struct ttusb *ttusb = data; +#else +static void ttusb_disconnect(struct usb_interface *intf) +{ + struct ttusb *ttusb = usb_get_intfdata(intf); + + usb_set_intfdata(intf, NULL); +#endif + + ttusb->disconnecting = 1; + + ttusb_stop_iso_xfer(ttusb); + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,69)) +#undef devfs_remove +#define devfs_remove(x) devfs_unregister(ttusb->stc_devfs_handle); +#endif +#if 0 + devfs_remove(TTUSB_BUDGET_NAME); +#endif + ttusb->dvb_demux.dmx.close(&ttusb->dvb_demux.dmx); + dvb_net_release(&ttusb->dvbnet); + dvb_dmxdev_release(&ttusb->dmxdev); + dvb_dmx_release(&ttusb->dvb_demux); + + dvb_unregister_i2c_bus(ttusb_i2c_xfer, ttusb->adapter, 0); + dvb_unregister_adapter(ttusb->adapter); + + ttusb_free_iso_urbs(ttusb); + + kfree(ttusb); + + dprintk("%s: TTUSB DVB disconnected\n", __FUNCTION__); +} + +static struct usb_device_id ttusb_table[] = { + {USB_DEVICE(0xb48, 0x1003)}, + {USB_DEVICE(0xb48, 0x1004)}, /* to be confirmed ???? */ + {USB_DEVICE(0xb48, 0x1005)}, /* to be confirmed ???? */ + {} +}; + +MODULE_DEVICE_TABLE(usb, ttusb_table); + +static struct usb_driver ttusb_driver = { + .name = "Technotrend/Hauppauge USB-Nova", + .probe = ttusb_probe, + .disconnect = ttusb_disconnect, + .id_table = ttusb_table, +}; + +static int __init ttusb_init(void) +{ + int err; + + if ((err = usb_register(&ttusb_driver)) < 0) { + printk("%s: usb_register failed! Error number %d", + __FILE__, err); + return -1; + } + + return 0; +} + +static void __exit ttusb_exit(void) +{ + usb_deregister(&ttusb_driver); +} + +module_init(ttusb_init); +module_exit(ttusb_exit); + +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Debug or not"); + +MODULE_AUTHOR("Holger Waechtler "); +MODULE_DESCRIPTION("TTUSB DVB Driver"); +MODULE_LICENSE("GPL"); diff -Nru a/drivers/media/dvb/ttusb-budget/dvb-ttusb-dspbootcode.h b/drivers/media/dvb/ttusb-budget/dvb-ttusb-dspbootcode.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-dspbootcode.h Sun Jul 27 10:13:53 2003 @@ -0,0 +1,1644 @@ + +#include + +u8 dsp_bootcode [] __initdata = { + 0x08, 0xaa, 0x00, 0x18, 0x00, 0x03, 0x08, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x01, 0x80, 0x18, 0x5f, + 0x00, 0x00, 0x01, 0x80, 0x77, 0x18, 0x2a, 0xeb, + 0x6b, 0xf8, 0x00, 0x18, 0x03, 0xff, 0x68, 0xf8, + 0x00, 0x18, 0xff, 0xfe, 0xf7, 0xb8, 0xf7, 0xbe, + 0xf6, 0xb9, 0xf4, 0xa0, 0xf6, 0xb7, 0xf6, 0xb5, + 0xf6, 0xb6, 0xf0, 0x20, 0x19, 0xdf, 0xf1, 0x00, + 0x00, 0x01, 0xf8, 0x4d, 0x01, 0xab, 0xf6, 0xb8, + 0xf0, 0x20, 0x19, 0xdf, 0xf0, 0x73, 0x01, 0xa5, + 0x7e, 0xf8, 0x00, 0x12, 0xf0, 0x00, 0x00, 0x01, + 0x47, 0xf8, 0x00, 0x11, 0x7e, 0x92, 0x00, 0xf8, + 0x00, 0x11, 0xf0, 0x00, 0x00, 0x01, 0x7e, 0xf8, + 0x00, 0x11, 0xf0, 0x00, 0x00, 0x01, 0x6c, 0x89, + 0x01, 0x9a, 0xf7, 0xb8, 0xee, 0xfc, 0xf0, 0x20, + 0xff, 0xff, 0xf1, 0x00, 0x00, 0x01, 0xf8, 0x4d, + 0x01, 0xbf, 0xf2, 0x73, 0x01, 0xb9, 0x4e, 0x02, + 0xf4, 0x95, 0xf5, 0xe3, 0x56, 0x02, 0x7e, 0x00, + 0x11, 0x00, 0xfa, 0x4c, 0x01, 0xb7, 0x6b, 0x03, + 0x00, 0x01, 0xf6, 0xb8, 0xee, 0x04, 0xf0, 0x74, + 0x0d, 0xa7, 0xf0, 0x74, 0x01, 0xc5, 0x4a, 0x11, + 0x4a, 0x16, 0x72, 0x11, 0x2a, 0xe6, 0x10, 0xf8, + 0x00, 0x11, 0xfa, 0x45, 0x01, 0xdb, 0xf4, 0x95, + 0xee, 0xff, 0x48, 0x11, 0xf0, 0x00, 0x2a, 0xc6, + 0x88, 0x16, 0xf4, 0x95, 0xf4, 0x95, 0x10, 0xee, + 0xff, 0xff, 0xf4, 0xe3, 0x6c, 0xe9, 0xff, 0xff, + 0x01, 0xd5, 0x10, 0xf8, 0x2a, 0xe7, 0xf8, 0x45, + 0x01, 0xe2, 0x10, 0xf8, 0x2a, 0xe7, 0xf4, 0xe3, + 0xf0, 0x74, 0x01, 0xff, 0xee, 0x01, 0x8a, 0x16, + 0x8a, 0x11, 0xfc, 0x00, 0xf7, 0xb8, 0xe9, 0x20, + 0x4a, 0x11, 0x09, 0xf8, 0x2a, 0xe6, 0xf8, 0x4e, + 0x01, 0xf3, 0xf2, 0x73, 0x01, 0xfd, 0xf4, 0x95, + 0xe8, 0x01, 0x72, 0x11, 0x2a, 0xe6, 0x49, 0x11, + 0x80, 0xe1, 0x2a, 0xc6, 0xf3, 0x00, 0x00, 0x01, + 0xe8, 0x00, 0x81, 0xf8, 0x2a, 0xe6, 0x8a, 0x11, + 0xfc, 0x00, 0xf4, 0x95, 0xf0, 0x73, 0x02, 0x00, + 0x10, 0xf8, 0x2a, 0x0f, 0xfc, 0x00, 0x4a, 0x11, + 0xf0, 0x74, 0x02, 0x02, 0x80, 0xf8, 0x2a, 0x10, + 0x73, 0x08, 0x00, 0x09, 0x40, 0xf8, 0x2a, 0x15, + 0x82, 0xf8, 0x00, 0x11, 0xf4, 0x95, 0x77, 0x10, + 0x03, 0xe8, 0xf5, 0xa9, 0xf8, 0x30, 0x02, 0x21, + 0x71, 0xf8, 0x2a, 0x10, 0x2a, 0x15, 0x56, 0xf8, + 0x2a, 0x0c, 0xf0, 0xe3, 0x4e, 0xf8, 0x2a, 0x16, + 0xe8, 0x00, 0x4e, 0xf8, 0x2a, 0x0c, 0x8a, 0x11, + 0xfc, 0x00, 0x4a, 0x06, 0x4a, 0x07, 0x4a, 0x1d, + 0x68, 0xf8, 0x00, 0x07, 0x7d, 0x3f, 0x69, 0xf8, + 0x00, 0x07, 0x40, 0x00, 0x68, 0xf8, 0x00, 0x1d, + 0xff, 0xfc, 0x6b, 0xf8, 0x2a, 0x0f, 0x00, 0x01, + 0x8a, 0x1d, 0x8a, 0x07, 0x8a, 0x06, 0xf4, 0xeb, + 0xee, 0xfd, 0x76, 0xf8, 0x2a, 0x0f, 0x00, 0x00, + 0x76, 0x00, 0x00, 0x00, 0xfb, 0x80, 0x19, 0x4c, + 0xf4, 0x95, 0xe8, 0x00, 0x80, 0xf8, 0x2a, 0x11, + 0xf9, 0x80, 0x19, 0x07, 0x80, 0xf8, 0x2a, 0x0e, + 0xf9, 0x80, 0x16, 0x66, 0x76, 0x00, 0x2a, 0x12, + 0x10, 0xf8, 0x2a, 0x11, 0xf9, 0x80, 0x18, 0xe3, + 0x10, 0xf8, 0x2a, 0x0e, 0xf9, 0x80, 0x16, 0x66, + 0x10, 0xf8, 0x2a, 0x0e, 0xf9, 0x80, 0x16, 0x87, + 0xee, 0x03, 0xfc, 0x00, 0x4a, 0x11, 0xf6, 0xb8, + 0xf4, 0x95, 0xf0, 0x20, 0x80, 0x00, 0x11, 0xf8, + 0x2a, 0x5a, 0xf8, 0x4d, 0x02, 0x93, 0x11, 0xf8, + 0x2a, 0x9f, 0xf8, 0x4c, 0x02, 0x7c, 0x77, 0x12, + 0x2a, 0x39, 0x49, 0x12, 0x01, 0xf8, 0x2a, 0x9f, + 0x89, 0x11, 0xf4, 0x95, 0xf4, 0x95, 0x71, 0x81, + 0x00, 0x11, 0x6c, 0xe1, 0xff, 0xab, 0x02, 0x93, + 0x6b, 0xf8, 0x2a, 0x9f, 0x00, 0x01, 0xe9, 0x05, + 0x01, 0xe2, 0x00, 0x03, 0x81, 0xf8, 0x2a, 0xa0, + 0xf0, 0x73, 0x02, 0x95, 0x72, 0x11, 0x2a, 0x9f, + 0xf4, 0x95, 0x10, 0xe1, 0x2a, 0x39, 0x6b, 0xf8, + 0x2a, 0x9f, 0x00, 0x01, 0x11, 0xf8, 0x2a, 0x9f, + 0x09, 0xf8, 0x2a, 0xa0, 0xf8, 0x4c, 0x02, 0x93, + 0x76, 0xf8, 0x2a, 0x5a, 0x00, 0x00, 0x76, 0xf8, + 0x2a, 0x9f, 0x00, 0x00, 0x76, 0xf8, 0x2a, 0xa0, + 0x00, 0x00, 0x88, 0x11, 0xf4, 0x95, 0x48, 0x11, + 0x8a, 0x11, 0xfc, 0x00, 0x4a, 0x11, 0xee, 0xfe, + 0x10, 0xf8, 0x2a, 0x5a, 0xf8, 0x44, 0x02, 0xb2, + 0x76, 0xf8, 0x2a, 0x5a, 0x00, 0x01, 0xf0, 0x74, + 0x02, 0x58, 0x88, 0x11, 0xf4, 0x95, 0x77, 0x10, + 0x80, 0x00, 0xf4, 0xa9, 0xf8, 0x30, 0x02, 0xb2, + 0x48, 0x11, 0xf0, 0x30, 0x00, 0xff, 0x80, 0x00, + 0x10, 0xf8, 0x2a, 0x5b, 0xf9, 0x80, 0x18, 0xd6, + 0xee, 0x02, 0x8a, 0x11, 0xfc, 0x00, 0xf4, 0x95, + 0x4a, 0x08, 0x4a, 0x09, 0x4a, 0x0a, 0x4a, 0x0b, + 0x4a, 0x0c, 0x4a, 0x0d, 0x4a, 0x10, 0x4a, 0x11, + 0x4a, 0x12, 0x4a, 0x13, 0x4a, 0x14, 0x4a, 0x15, + 0x4a, 0x16, 0x4a, 0x17, 0x4a, 0x17, 0x4a, 0x19, + 0x4a, 0x0e, 0x4a, 0x06, 0x4a, 0x07, 0x4a, 0x1a, + 0x4a, 0x1d, 0x4a, 0x1b, 0x4a, 0x1c, 0x68, 0xf8, + 0x00, 0x07, 0x7d, 0x3f, 0x69, 0xf8, 0x00, 0x07, + 0x40, 0x00, 0x68, 0xf8, 0x00, 0x1d, 0xff, 0xfc, + 0x48, 0x18, 0x68, 0xf8, 0x00, 0x18, 0xff, 0xfe, + 0xf4, 0x95, 0xf4, 0x95, 0x4a, 0x08, 0xee, 0xfd, + 0xf0, 0x74, 0x02, 0x58, 0x88, 0x11, 0xf4, 0x95, + 0x77, 0x10, 0x80, 0x00, 0xf4, 0xa9, 0xf8, 0x30, + 0x02, 0xef, 0x48, 0x11, 0xf0, 0x30, 0x00, 0xff, + 0x80, 0x00, 0x10, 0xf8, 0x2a, 0x5b, 0xf9, 0x80, + 0x18, 0xd6, 0xee, 0x03, 0x8a, 0x18, 0xf4, 0x95, + 0x8a, 0x1c, 0x8a, 0x1b, 0x8a, 0x1d, 0x8a, 0x1a, + 0x8a, 0x07, 0x8a, 0x06, 0x8a, 0x0e, 0x8a, 0x19, + 0x8a, 0x17, 0x8a, 0x17, 0x8a, 0x16, 0x8a, 0x15, + 0x8a, 0x14, 0x8a, 0x13, 0x8a, 0x12, 0x8a, 0x11, + 0x8a, 0x10, 0x8a, 0x0d, 0x8a, 0x0c, 0x8a, 0x0b, + 0x8a, 0x0a, 0x8a, 0x09, 0x8a, 0x08, 0xf4, 0xeb, + 0x4a, 0x11, 0x77, 0x11, 0x2a, 0x39, 0x76, 0x81, + 0x00, 0x55, 0x77, 0x12, 0x2a, 0x18, 0x10, 0xe2, + 0x00, 0x01, 0x80, 0xe1, 0x00, 0x01, 0x10, 0xe2, + 0x00, 0x02, 0x80, 0xe1, 0x00, 0x02, 0x76, 0xe1, + 0x00, 0x03, 0x00, 0x00, 0x76, 0xe1, 0x00, 0x04, + 0x00, 0xaa, 0xf0, 0x74, 0x02, 0x98, 0x8a, 0x11, + 0xfc, 0x00, 0x4a, 0x11, 0x88, 0x11, 0xf4, 0x95, + 0xf4, 0x95, 0x10, 0x81, 0x6f, 0xf8, 0x2a, 0x9e, + 0x0c, 0x88, 0xe8, 0xff, 0x18, 0xe1, 0x00, 0x01, + 0x1a, 0xf8, 0x2a, 0x9e, 0xf0, 0x30, 0x1f, 0xff, + 0x80, 0xf8, 0x2a, 0x9e, 0x8a, 0x11, 0xfc, 0x00, + 0x4a, 0x11, 0x77, 0x11, 0x2a, 0x39, 0x76, 0x81, + 0x00, 0x55, 0x77, 0x12, 0x2a, 0x18, 0x11, 0xe2, + 0x00, 0x01, 0x81, 0xe1, 0x00, 0x01, 0x11, 0xe2, + 0x00, 0x02, 0x81, 0xe1, 0x00, 0x02, 0x76, 0xe1, + 0x00, 0x03, 0x00, 0x02, 0x48, 0x08, 0x6f, 0xe1, + 0x00, 0x04, 0x0c, 0x98, 0xf0, 0x30, 0x00, 0xff, + 0x80, 0xe1, 0x00, 0x05, 0x76, 0xe1, 0x00, 0x06, + 0x00, 0xaa, 0xf0, 0x74, 0x02, 0x98, 0x8a, 0x11, + 0xfc, 0x00, 0x4a, 0x11, 0x77, 0x11, 0x2a, 0x39, + 0x76, 0x81, 0x00, 0x55, 0x77, 0x12, 0x2a, 0x18, + 0x10, 0xe2, 0x00, 0x01, 0x80, 0xe1, 0x00, 0x01, + 0x10, 0xe2, 0x00, 0x02, 0x80, 0xe1, 0x00, 0x02, + 0x76, 0xe1, 0x00, 0x03, 0x00, 0x04, 0x48, 0x11, + 0xf0, 0x00, 0x00, 0x04, 0x88, 0x12, 0xf4, 0x95, + 0x77, 0x13, 0x2a, 0x76, 0xe9, 0x00, 0xe5, 0x98, + 0xf3, 0x00, 0x00, 0x01, 0xf6, 0xb8, 0x48, 0x0b, + 0x08, 0xf8, 0x2a, 0x3c, 0xf8, 0x43, 0x03, 0x71, + 0x76, 0x82, 0x00, 0xaa, 0xf0, 0x74, 0x02, 0x98, + 0x8a, 0x11, 0xfc, 0x00, 0x4a, 0x11, 0xee, 0xf0, + 0x88, 0x11, 0xf4, 0x95, 0xf4, 0x95, 0x71, 0x81, + 0x00, 0x14, 0x71, 0xe1, 0x00, 0x01, 0x00, 0x15, + 0x49, 0x11, 0xf3, 0x00, 0x00, 0x02, 0x89, 0x11, + 0xe7, 0x82, 0x6d, 0xea, 0x00, 0x04, 0xe7, 0x83, + 0x6d, 0xeb, 0x00, 0x0a, 0x77, 0x1a, 0x00, 0x05, + 0xf0, 0x72, 0x03, 0xaa, 0x11, 0x81, 0xf2, 0xe8, + 0x80, 0x82, 0xe9, 0xff, 0x19, 0xe1, 0x00, 0x01, + 0xf1, 0xa0, 0x81, 0x92, 0x11, 0xe1, 0x00, 0x0c, + 0xf2, 0xe8, 0x80, 0x83, 0xe9, 0xff, 0x19, 0xe1, + 0x00, 0x0d, 0xf1, 0xa0, 0x81, 0x93, 0x6d, 0xe9, + 0x00, 0x02, 0x48, 0x18, 0x49, 0x18, 0x70, 0x00, + 0x00, 0x15, 0xf0, 0x00, 0x00, 0x04, 0xf3, 0x00, + 0x00, 0x0a, 0x80, 0x01, 0x81, 0x02, 0xf2, 0x74, + 0x0e, 0x54, 0xf4, 0x95, 0x48, 0x14, 0xee, 0x10, + 0x8a, 0x11, 0xfc, 0x00, 0x4a, 0x11, 0xf0, 0x74, + 0x0c, 0x5e, 0x80, 0xf8, 0x2a, 0x5c, 0x77, 0x12, + 0x2a, 0x39, 0x76, 0x82, 0x00, 0x55, 0x77, 0x11, + 0x2a, 0x18, 0x10, 0xe1, 0x00, 0x01, 0x80, 0xe2, + 0x00, 0x01, 0x10, 0xe1, 0x00, 0x02, 0x80, 0xe2, + 0x00, 0x02, 0x76, 0xe2, 0x00, 0x03, 0x00, 0x1c, + 0xf6, 0xb8, 0x56, 0xf8, 0x2a, 0x16, 0xf0, 0xf0, + 0xf0, 0xf8, 0x80, 0xe2, 0x00, 0x07, 0x56, 0xf8, + 0x2a, 0x16, 0xf1, 0xf0, 0xe8, 0xff, 0xf2, 0x80, + 0x80, 0xe2, 0x00, 0x06, 0x56, 0xf8, 0x2a, 0x16, + 0xf1, 0xf8, 0xe8, 0xff, 0xf2, 0x80, 0x80, 0xe2, + 0x00, 0x05, 0x57, 0xf8, 0x2a, 0x16, 0xe8, 0xff, + 0xf2, 0x80, 0x80, 0xe2, 0x00, 0x04, 0x56, 0xf8, + 0x27, 0x6c, 0xf0, 0xf0, 0xf0, 0xf8, 0x80, 0xe2, + 0x00, 0x0b, 0x56, 0xf8, 0x27, 0x6c, 0xf1, 0xf0, + 0xe8, 0xff, 0xf2, 0x80, 0x80, 0xe2, 0x00, 0x0a, + 0x56, 0xf8, 0x27, 0x6c, 0xf1, 0xf8, 0xe8, 0xff, + 0xf2, 0x80, 0x80, 0xe2, 0x00, 0x09, 0xe8, 0xff, + 0x57, 0xf8, 0x27, 0x6c, 0xf2, 0x80, 0x80, 0xe2, + 0x00, 0x08, 0x56, 0xf8, 0x27, 0x6a, 0xf0, 0xf0, + 0xf0, 0xf8, 0x80, 0xe2, 0x00, 0x0f, 0x56, 0xf8, + 0x27, 0x6a, 0xf1, 0xf0, 0xe8, 0xff, 0xf2, 0x80, + 0x80, 0xe2, 0x00, 0x0e, 0x56, 0xf8, 0x27, 0x6a, + 0xf1, 0xf8, 0xe8, 0xff, 0xf2, 0x80, 0x80, 0xe2, + 0x00, 0x0d, 0x57, 0xf8, 0x27, 0x6a, 0xe8, 0xff, + 0xf2, 0x80, 0x80, 0xe2, 0x00, 0x0c, 0x76, 0xe2, + 0x00, 0x13, 0x00, 0x00, 0x76, 0xe2, 0x00, 0x12, + 0x00, 0x00, 0x6f, 0xf8, 0x2a, 0x5c, 0x0c, 0x58, + 0x80, 0xe2, 0x00, 0x11, 0xe8, 0xff, 0x18, 0xf8, + 0x2a, 0x5c, 0x80, 0xe2, 0x00, 0x10, 0x76, 0xe2, + 0x00, 0x17, 0x00, 0x00, 0x76, 0xe2, 0x00, 0x16, + 0x00, 0x00, 0x6f, 0xf8, 0x2a, 0x9e, 0x0c, 0x58, + 0x80, 0xe2, 0x00, 0x15, 0xe8, 0xff, 0x18, 0xf8, + 0x2a, 0x9e, 0x80, 0xe2, 0x00, 0x14, 0x76, 0xe2, + 0x00, 0x1b, 0x00, 0x00, 0x76, 0xe2, 0x00, 0x1a, + 0x00, 0x00, 0x76, 0xe2, 0x00, 0x19, 0x00, 0x00, + 0x70, 0xe2, 0x00, 0x18, 0x27, 0x6e, 0x76, 0xe2, + 0x00, 0x1f, 0x00, 0x00, 0x76, 0xe2, 0x00, 0x1e, + 0x00, 0x00, 0x76, 0xe2, 0x00, 0x1d, 0x00, 0x00, + 0x76, 0xe2, 0x00, 0x1c, 0x00, 0x00, 0x76, 0xe2, + 0x00, 0x20, 0x00, 0xaa, 0xf0, 0x74, 0x02, 0x98, + 0x8a, 0x11, 0xfc, 0x00, 0x4a, 0x11, 0xee, 0xfe, + 0x10, 0xf8, 0x2a, 0x38, 0xf8, 0x45, 0x04, 0xed, + 0x77, 0x12, 0x2a, 0x18, 0x10, 0xe2, 0x00, 0x02, + 0x88, 0x11, 0xf4, 0x95, 0x77, 0x10, 0x00, 0x08, + 0x6d, 0xe9, 0xff, 0xdf, 0xf6, 0xa9, 0xf8, 0x20, + 0x04, 0x75, 0xf0, 0x73, 0x04, 0x7d, 0xf0, 0x10, + 0x00, 0x21, 0xf0, 0x00, 0x1a, 0x83, 0x48, 0x08, + 0x7e, 0xf8, 0x00, 0x08, 0xf4, 0xe2, 0xf0, 0x74, + 0x03, 0x0a, 0xf0, 0x73, 0x04, 0xea, 0x48, 0x12, + 0xf2, 0x74, 0x03, 0x23, 0xf0, 0x00, 0x00, 0x04, + 0xf2, 0x74, 0x03, 0x36, 0xf4, 0x95, 0xe8, 0x00, + 0xf0, 0x73, 0x04, 0xea, 0x77, 0x11, 0x2a, 0x18, + 0xe8, 0xff, 0x6f, 0xe1, 0x00, 0x04, 0x0d, 0x48, + 0x18, 0xe1, 0x00, 0x05, 0xf2, 0x74, 0x09, 0x69, + 0xf4, 0x95, 0xf2, 0xa0, 0xf0, 0x74, 0x03, 0x36, + 0xf0, 0x73, 0x04, 0xea, 0x77, 0x11, 0x2a, 0x18, + 0xe8, 0xff, 0x6f, 0xe1, 0x00, 0x04, 0x0d, 0x48, + 0x18, 0xe1, 0x00, 0x05, 0xf2, 0x74, 0x09, 0x41, + 0xf4, 0x95, 0xf2, 0xa0, 0xf0, 0x74, 0x03, 0x36, + 0xf0, 0x73, 0x04, 0xea, 0xf0, 0x74, 0x03, 0x57, + 0xf0, 0x73, 0x04, 0xea, 0x10, 0xf8, 0x2a, 0x1c, + 0xf0, 0x74, 0x12, 0xa4, 0xf2, 0x74, 0x03, 0x36, + 0xf4, 0x95, 0xe8, 0x00, 0xf0, 0x73, 0x04, 0xea, + 0x48, 0x12, 0xf2, 0x74, 0x03, 0x80, 0xf0, 0x00, + 0x00, 0x04, 0xf2, 0x74, 0x03, 0x36, 0xf4, 0x95, + 0xe8, 0x00, 0xf0, 0x73, 0x04, 0xea, 0x10, 0xf8, + 0x2a, 0x1c, 0xf0, 0x74, 0x12, 0xc5, 0xf2, 0x74, + 0x03, 0x36, 0xf4, 0x95, 0xe8, 0x00, 0xf0, 0x73, + 0x04, 0xea, 0x77, 0x11, 0x2a, 0x18, 0xe8, 0xff, + 0x6f, 0xe1, 0x00, 0x06, 0x0d, 0x48, 0x18, 0xe1, + 0x00, 0x07, 0x71, 0xe1, 0x00, 0x05, 0x00, 0x12, + 0xf2, 0xa0, 0x70, 0x00, 0x00, 0x12, 0x80, 0x01, + 0x10, 0xe1, 0x00, 0x04, 0xf0, 0x74, 0x0e, 0x7a, + 0xf2, 0x74, 0x03, 0x36, 0xf4, 0x95, 0xe8, 0x00, + 0xf0, 0x73, 0x04, 0xea, 0xf0, 0x74, 0x03, 0xbc, + 0x76, 0xf8, 0x2a, 0x38, 0x00, 0x00, 0xee, 0x02, + 0x8a, 0x11, 0xfc, 0x00, 0x4a, 0x11, 0x77, 0x11, + 0x2a, 0x39, 0x76, 0x81, 0x00, 0x55, 0x77, 0x12, + 0x2a, 0x18, 0x10, 0xe2, 0x00, 0x01, 0x80, 0xe1, + 0x00, 0x01, 0x10, 0xe2, 0x00, 0x02, 0x80, 0xe1, + 0x00, 0x02, 0x76, 0xe1, 0x00, 0x03, 0x00, 0x09, + 0x48, 0x11, 0xf0, 0x00, 0x00, 0x04, 0x88, 0x12, + 0xf4, 0x95, 0x77, 0x13, 0x2a, 0x86, 0xe9, 0x00, + 0xe5, 0x98, 0xf3, 0x00, 0x00, 0x01, 0xf6, 0xb8, + 0x48, 0x0b, 0x08, 0xf8, 0x2a, 0x3c, 0xf8, 0x43, + 0x05, 0x0a, 0x76, 0x82, 0x00, 0xaa, 0xf0, 0x74, + 0x02, 0x98, 0x8a, 0x11, 0xfc, 0x00, 0x4a, 0x11, + 0x77, 0x11, 0x2a, 0x39, 0x76, 0x81, 0x00, 0x55, + 0x77, 0x13, 0x2a, 0x18, 0x10, 0xe3, 0x00, 0x01, + 0x80, 0xe1, 0x00, 0x01, 0x10, 0xe3, 0x00, 0x02, + 0x80, 0xe1, 0x00, 0x02, 0x13, 0xe3, 0x00, 0x03, + 0x81, 0xe1, 0x00, 0x03, 0x48, 0x11, 0x77, 0x11, + 0x00, 0x00, 0xf8, 0x4d, 0x05, 0x44, 0xf0, 0x00, + 0x00, 0x04, 0x88, 0x12, 0x48, 0x13, 0xf0, 0x00, + 0x00, 0x04, 0x88, 0x13, 0xf4, 0x95, 0xf4, 0x95, + 0xe5, 0x98, 0x6d, 0x91, 0xf6, 0xb8, 0x48, 0x11, + 0x08, 0xf8, 0x2a, 0x3c, 0xf8, 0x43, 0x05, 0x3a, + 0xf0, 0x20, 0x2a, 0x39, 0x49, 0x11, 0xf5, 0x00, + 0x89, 0x11, 0xf4, 0x95, 0xf4, 0x95, 0x76, 0xe1, + 0x00, 0x04, 0x00, 0xaa, 0xf0, 0x74, 0x02, 0x98, + 0x8a, 0x11, 0xfc, 0x00, 0x4a, 0x11, 0x77, 0x11, + 0x2a, 0x39, 0x76, 0x81, 0x00, 0x55, 0x77, 0x12, + 0x2a, 0x18, 0x10, 0xe2, 0x00, 0x01, 0x80, 0xe1, + 0x00, 0x01, 0x10, 0xe2, 0x00, 0x02, 0x80, 0xe1, + 0x00, 0x02, 0x76, 0xe1, 0x00, 0x03, 0x00, 0x0c, + 0x48, 0x11, 0xf0, 0x00, 0x00, 0x04, 0x88, 0x12, + 0xf4, 0x95, 0x77, 0x13, 0x2a, 0x7a, 0xe9, 0x00, + 0xe5, 0x98, 0xf3, 0x00, 0x00, 0x01, 0xf6, 0xb8, + 0x48, 0x0b, 0x08, 0xf8, 0x2a, 0x3c, 0xf8, 0x43, + 0x05, 0x6a, 0x76, 0x82, 0x00, 0xaa, 0xf0, 0x74, + 0x02, 0x98, 0x8a, 0x11, 0xfc, 0x00, 0x4a, 0x11, + 0x77, 0x11, 0x2a, 0x39, 0x76, 0x81, 0x00, 0x55, + 0x77, 0x12, 0x2a, 0x18, 0x10, 0xe2, 0x00, 0x01, + 0x80, 0xe1, 0x00, 0x01, 0x10, 0xe2, 0x00, 0x02, + 0x80, 0xe1, 0x00, 0x02, 0x76, 0xe1, 0x00, 0x03, + 0x00, 0x19, 0x48, 0x11, 0xf0, 0x00, 0x00, 0x04, + 0x88, 0x12, 0xf4, 0x95, 0x77, 0x13, 0x2a, 0x5d, + 0xe9, 0x00, 0xe5, 0x98, 0xf3, 0x00, 0x00, 0x01, + 0xf6, 0xb8, 0x48, 0x0b, 0x08, 0xf8, 0x2a, 0x3c, + 0xf8, 0x43, 0x05, 0x93, 0x76, 0x82, 0x00, 0xaa, + 0xf0, 0x74, 0x02, 0x98, 0x8a, 0x11, 0xfc, 0x00, + 0x4a, 0x11, 0x88, 0x11, 0x10, 0xf8, 0x2a, 0x38, + 0xf8, 0x44, 0x05, 0xe3, 0x10, 0xf8, 0x2a, 0xa1, + 0xf8, 0x44, 0x05, 0xba, 0x6c, 0xe1, 0xff, 0x56, + 0x05, 0xe3, 0x72, 0x12, 0x2a, 0xa1, 0xf4, 0x95, + 0x70, 0xe2, 0x2a, 0x18, 0x00, 0x11, 0x6b, 0xf8, + 0x2a, 0xa1, 0x00, 0x01, 0xf0, 0x73, 0x05, 0xe3, + 0x72, 0x12, 0x2a, 0xa1, 0xf4, 0x95, 0x70, 0xe2, + 0x2a, 0x18, 0x00, 0x11, 0x10, 0xf8, 0x2a, 0xa1, + 0xf0, 0x00, 0x00, 0x01, 0x88, 0x12, 0xf4, 0x95, + 0xf4, 0x95, 0x6e, 0xe2, 0xff, 0xfc, 0x05, 0xd1, + 0x73, 0x12, 0x2a, 0xa1, 0x48, 0x11, 0xf0, 0x00, + 0x00, 0x05, 0x80, 0xf8, 0x2a, 0xa2, 0x10, 0xf8, + 0x2a, 0xa1, 0x08, 0xf8, 0x2a, 0xa2, 0xf8, 0x44, + 0x05, 0xe3, 0x6c, 0xe1, 0xff, 0xab, 0x05, 0xdd, + 0x76, 0xf8, 0x2a, 0x38, 0x00, 0x01, 0x76, 0xf8, + 0x2a, 0xa1, 0x00, 0x00, 0x76, 0xf8, 0x2a, 0xa2, + 0x00, 0x00, 0x8a, 0x11, 0xfc, 0x00, 0xf4, 0x95, + 0x4a, 0x08, 0x4a, 0x09, 0x4a, 0x0a, 0x4a, 0x0b, + 0x4a, 0x0c, 0x4a, 0x0d, 0x4a, 0x10, 0x4a, 0x11, + 0x4a, 0x12, 0x4a, 0x13, 0x4a, 0x14, 0x4a, 0x15, + 0x4a, 0x16, 0x4a, 0x17, 0x4a, 0x17, 0x4a, 0x19, + 0x4a, 0x0e, 0x4a, 0x06, 0x4a, 0x07, 0x4a, 0x1a, + 0x4a, 0x1d, 0x4a, 0x1b, 0x4a, 0x1c, 0x68, 0xf8, + 0x00, 0x07, 0x7d, 0x3f, 0x69, 0xf8, 0x00, 0x07, + 0x40, 0x00, 0x68, 0xf8, 0x00, 0x1d, 0xff, 0xfc, + 0x48, 0x18, 0x68, 0xf8, 0x00, 0x18, 0xff, 0xfe, + 0xf4, 0x95, 0xf4, 0x95, 0x4a, 0x08, 0xee, 0xff, + 0x10, 0xf8, 0x2a, 0x5b, 0xf9, 0x80, 0x18, 0x04, + 0xf0, 0x74, 0x05, 0xa2, 0xee, 0x01, 0x8a, 0x18, + 0xf4, 0x95, 0x8a, 0x1c, 0x8a, 0x1b, 0x8a, 0x1d, + 0x8a, 0x1a, 0x8a, 0x07, 0x8a, 0x06, 0x8a, 0x0e, + 0x8a, 0x19, 0x8a, 0x17, 0x8a, 0x17, 0x8a, 0x16, + 0x8a, 0x15, 0x8a, 0x14, 0x8a, 0x13, 0x8a, 0x12, + 0x8a, 0x11, 0x8a, 0x10, 0x8a, 0x0d, 0x8a, 0x0c, + 0x8a, 0x0b, 0x8a, 0x0a, 0x8a, 0x09, 0x8a, 0x08, + 0xf4, 0xeb, 0xee, 0xfd, 0x76, 0xf8, 0x2a, 0x38, + 0x00, 0x00, 0x76, 0xf8, 0x2a, 0x5a, 0x00, 0x00, + 0xe8, 0x01, 0x4e, 0x00, 0xfb, 0x80, 0x17, 0xd6, + 0xf4, 0x95, 0xe8, 0x01, 0x80, 0xf8, 0x2a, 0x5b, + 0x76, 0x00, 0x2a, 0x8f, 0xf9, 0x80, 0x16, 0xaa, + 0x10, 0xf8, 0x2a, 0x5b, 0xf9, 0x80, 0x17, 0x5c, + 0x10, 0xf8, 0x2a, 0x5b, 0xf9, 0x80, 0x17, 0x6f, + 0xfb, 0x80, 0x16, 0x66, 0xf4, 0x95, 0xe8, 0x1a, + 0xfb, 0x80, 0x16, 0x87, 0xf4, 0x95, 0xe8, 0x1a, + 0xfb, 0x80, 0x16, 0x66, 0xf4, 0x95, 0xe8, 0x1b, + 0xfb, 0x80, 0x16, 0x87, 0xf4, 0x95, 0xe8, 0x1b, + 0xee, 0x03, 0xfc, 0x00, 0x4a, 0x11, 0xf4, 0x95, + 0x13, 0x02, 0x88, 0x11, 0xe8, 0x00, 0xf8, 0x4d, + 0x06, 0x6a, 0xf3, 0x10, 0x00, 0x01, 0x89, 0x1a, + 0xf4, 0x95, 0xf0, 0x72, 0x06, 0x69, 0x1c, 0x91, + 0x8a, 0x11, 0xfc, 0x00, 0x4a, 0x11, 0x88, 0x11, + 0x12, 0x03, 0x11, 0x02, 0xf8, 0x45, 0x06, 0x79, + 0xf0, 0x10, 0x00, 0x01, 0x88, 0x1a, 0xf4, 0x95, + 0xf0, 0x72, 0x06, 0x78, 0x81, 0x91, 0x8a, 0x11, + 0xfc, 0x00, 0x4a, 0x11, 0xf4, 0x95, 0x71, 0x02, + 0x00, 0x11, 0x11, 0x03, 0x61, 0xf8, 0x00, 0x11, + 0x00, 0x01, 0xf8, 0x30, 0x06, 0x91, 0xf6, 0xb8, + 0x6f, 0xf8, 0x00, 0x11, 0x0c, 0x1f, 0x88, 0x11, + 0xf3, 0xe8, 0xe8, 0xff, 0x18, 0x81, 0xf1, 0xa0, + 0x81, 0x81, 0xf0, 0x73, 0x06, 0x9d, 0xf6, 0xb8, + 0x6f, 0xf8, 0x00, 0x11, 0x0c, 0x1f, 0x88, 0x11, + 0xf3, 0x30, 0x00, 0xff, 0xf0, 0x20, 0xff, 0x00, + 0x18, 0x81, 0xf1, 0xa0, 0x81, 0x81, 0x8a, 0x11, + 0xfc, 0x00, 0x4a, 0x11, 0xf4, 0x95, 0x11, 0x02, + 0x61, 0xf8, 0x00, 0x0b, 0x00, 0x01, 0xf8, 0x20, + 0x06, 0xb1, 0x49, 0x0b, 0xf6, 0x1f, 0x88, 0x11, + 0xf4, 0x95, 0xf4, 0x95, 0x10, 0x81, 0xf2, 0x73, + 0x06, 0xb8, 0xf0, 0x30, 0x00, 0xff, 0x49, 0x0b, + 0xf6, 0x1f, 0x88, 0x11, 0xf4, 0x95, 0xf4, 0x95, + 0x12, 0x81, 0xf4, 0x78, 0x8a, 0x11, 0xfc, 0x00, + 0x4a, 0x11, 0xf4, 0x95, 0x71, 0x02, 0x00, 0x12, + 0x13, 0x03, 0x88, 0x11, 0xe8, 0x00, 0xf8, 0x4d, + 0x06, 0xcc, 0xf3, 0x10, 0x00, 0x01, 0x89, 0x1a, + 0xf4, 0x95, 0xf0, 0x72, 0x06, 0xcb, 0x11, 0x92, + 0xf2, 0xc0, 0x81, 0x91, 0x8a, 0x11, 0xfc, 0x00, + 0x88, 0x12, 0x12, 0x02, 0x71, 0x01, 0x00, 0x13, + 0xf8, 0x45, 0x06, 0xdb, 0xf0, 0x10, 0x00, 0x01, + 0x88, 0x1a, 0xf4, 0x95, 0xf0, 0x72, 0x06, 0xda, + 0xe5, 0x98, 0xfc, 0x00, 0x4a, 0x11, 0xee, 0xfe, + 0x88, 0x11, 0x11, 0x04, 0x10, 0x06, 0x71, 0x05, + 0x00, 0x12, 0x61, 0xf8, 0x00, 0x12, 0x00, 0x01, + 0xf8, 0x20, 0x06, 0xea, 0xf0, 0x00, 0x00, 0x01, + 0xf6, 0xb8, 0xf0, 0x00, 0x00, 0x01, 0x6f, 0xf8, + 0x00, 0x12, 0x0f, 0x1f, 0x48, 0x08, 0x81, 0x00, + 0xf4, 0x7f, 0x80, 0x01, 0xf2, 0x74, 0x06, 0xba, + 0xf4, 0x95, 0x48, 0x11, 0xee, 0x02, 0x8a, 0x11, + 0xfc, 0x00, 0x4a, 0x11, 0xee, 0xfe, 0x88, 0x12, + 0x11, 0x04, 0x10, 0x06, 0x71, 0x05, 0x00, 0x13, + 0x61, 0xf8, 0x00, 0x13, 0x00, 0x01, 0xf8, 0x20, + 0x07, 0x09, 0xf0, 0x00, 0x00, 0x01, 0xf0, 0x00, + 0x00, 0x01, 0x88, 0x11, 0xf6, 0xb8, 0x6f, 0xf8, + 0x00, 0x13, 0x0f, 0x1f, 0x81, 0x00, 0x48, 0x11, + 0xf4, 0x7f, 0x80, 0x01, 0xf2, 0x74, 0x06, 0xce, + 0xf4, 0x95, 0x48, 0x12, 0x48, 0x11, 0xf0, 0x30, + 0xff, 0xfe, 0xee, 0x02, 0x8a, 0x11, 0xfc, 0x00, + 0x4a, 0x11, 0x4a, 0x16, 0x4a, 0x17, 0xee, 0xfc, + 0xf4, 0x95, 0x80, 0x02, 0x71, 0x08, 0x00, 0x16, + 0x10, 0x09, 0x71, 0x0b, 0x00, 0x17, 0x80, 0x03, + 0x71, 0x0a, 0x00, 0x11, 0x48, 0x17, 0xf8, 0x45, + 0x07, 0x3f, 0x70, 0x00, 0x00, 0x11, 0x10, 0x03, + 0xf0, 0x74, 0x06, 0x9f, 0x80, 0x01, 0x70, 0x00, + 0x00, 0x16, 0x10, 0x02, 0xf0, 0x74, 0x06, 0x7b, + 0x6d, 0x91, 0x6d, 0x96, 0x6c, 0xef, 0xff, 0xff, + 0x07, 0x2f, 0xee, 0x04, 0x8a, 0x17, 0x8a, 0x16, + 0x8a, 0x11, 0xfc, 0x00, 0x4a, 0x11, 0xee, 0xfe, + 0x10, 0xf8, 0x2a, 0xe8, 0x08, 0xf8, 0x2a, 0xe9, + 0xf8, 0x45, 0x07, 0x64, 0x76, 0x00, 0x00, 0x01, + 0x62, 0xf8, 0x2a, 0xe9, 0x00, 0x5e, 0xf2, 0x74, + 0x12, 0x0b, 0xf0, 0x00, 0x30, 0x40, 0x72, 0x11, + 0x2a, 0xe9, 0x77, 0x10, 0x00, 0x0f, 0xf5, 0xa9, + 0xf8, 0x20, 0x07, 0x61, 0x6b, 0xf8, 0x2a, 0xe9, + 0x00, 0x01, 0xf0, 0x73, 0x07, 0x64, 0x76, 0xf8, + 0x2a, 0xe9, 0x00, 0x00, 0xee, 0x02, 0x8a, 0x11, + 0xfc, 0x00, 0x4a, 0x11, 0x88, 0x11, 0xe8, 0x00, + 0x75, 0xf8, 0x00, 0x08, 0x00, 0x08, 0xe8, 0x00, + 0x75, 0xf8, 0x00, 0x08, 0x00, 0x09, 0xf6, 0xb8, + 0xf4, 0x95, 0xf0, 0x20, 0xfc, 0x3f, 0x75, 0xf8, + 0x00, 0x08, 0x00, 0x0d, 0xf0, 0x20, 0x0c, 0x30, + 0x75, 0xf8, 0x00, 0x08, 0x00, 0x0c, 0x76, 0xf8, + 0x2a, 0xe8, 0x00, 0x00, 0x76, 0xf8, 0x2a, 0xe9, + 0x00, 0x00, 0x6c, 0x81, 0x07, 0x92, 0x76, 0xf8, + 0x2a, 0xea, 0x00, 0x00, 0xfb, 0x80, 0x16, 0x76, + 0xf4, 0x95, 0xe8, 0x10, 0xe8, 0x00, 0x75, 0xf8, + 0x00, 0x08, 0x00, 0x00, 0xf0, 0x73, 0x07, 0xa8, + 0x76, 0xf8, 0x2a, 0xea, 0x00, 0x01, 0xfb, 0x80, + 0x16, 0x66, 0xf4, 0x95, 0xe8, 0x10, 0xfb, 0x80, + 0x16, 0x87, 0xf4, 0x95, 0xe8, 0x10, 0xe8, 0x00, + 0x75, 0xf8, 0x00, 0x08, 0x00, 0x00, 0xf6, 0xb8, + 0xf4, 0x95, 0xf0, 0x20, 0xff, 0xff, 0x75, 0xf8, + 0x00, 0x08, 0x00, 0x00, 0x8a, 0x11, 0xfc, 0x00, + 0xf4, 0x95, 0x4a, 0x08, 0x4a, 0x09, 0x4a, 0x0a, + 0x4a, 0x06, 0x4a, 0x07, 0x4a, 0x1d, 0x68, 0xf8, + 0x00, 0x07, 0x7d, 0x3f, 0x69, 0xf8, 0x00, 0x07, + 0x40, 0x00, 0x68, 0xf8, 0x00, 0x1d, 0xff, 0xfc, + 0x10, 0xf8, 0x2a, 0xea, 0xf8, 0x45, 0x07, 0xe1, + 0x10, 0xf8, 0x2a, 0xe8, 0xf0, 0x00, 0x00, 0x01, + 0xf0, 0x30, 0x00, 0x0f, 0x80, 0xf8, 0x2a, 0xe8, + 0x10, 0xf8, 0x2a, 0xe8, 0xf8, 0x44, 0x07, 0xd6, + 0xf6, 0xb8, 0xf4, 0x95, 0xf0, 0x20, 0xfc, 0x3f, + 0x75, 0xf8, 0x00, 0x08, 0x00, 0x0d, 0xf0, 0x20, + 0x0c, 0x30, 0x75, 0xf8, 0x00, 0x08, 0x00, 0x0c, + 0xe8, 0x00, 0x75, 0xf8, 0x00, 0x08, 0x00, 0x00, + 0xf6, 0xb8, 0xf4, 0x95, 0xf0, 0x20, 0xff, 0xff, + 0x75, 0xf8, 0x00, 0x08, 0x00, 0x00, 0x8a, 0x1d, + 0x8a, 0x07, 0x8a, 0x06, 0x8a, 0x0a, 0x8a, 0x09, + 0x8a, 0x08, 0xf4, 0xeb, 0xee, 0xff, 0xf2, 0x74, + 0x07, 0x67, 0xf4, 0x95, 0xe8, 0x01, 0xee, 0x01, + 0xfc, 0x00, 0x4a, 0x07, 0x4a, 0x1d, 0x68, 0xf8, + 0x00, 0x07, 0x7d, 0x3f, 0x69, 0xf8, 0x00, 0x07, + 0x40, 0x00, 0x68, 0xf8, 0x00, 0x1d, 0xff, 0xfc, + 0x8a, 0x1d, 0x8a, 0x07, 0xf4, 0xeb, 0x4a, 0x11, + 0x77, 0x11, 0x00, 0x28, 0x76, 0x81, 0x24, 0x00, + 0xe8, 0x00, 0x75, 0xf8, 0x00, 0x08, 0x00, 0x01, + 0xf2, 0x74, 0x07, 0x67, 0xf4, 0x95, 0xe8, 0x00, + 0x77, 0x11, 0x00, 0x1d, 0x68, 0x81, 0x00, 0x7f, + 0xf6, 0xb8, 0xf4, 0x95, 0xf0, 0x20, 0xff, 0x80, + 0x77, 0x11, 0x00, 0x1d, 0xf0, 0x30, 0x01, 0x00, + 0x1a, 0x81, 0x80, 0x81, 0xf0, 0x74, 0x0a, 0x33, + 0xf0, 0x74, 0x11, 0xac, 0xf9, 0x80, 0x13, 0x25, + 0xf9, 0x80, 0x16, 0x53, 0xf9, 0x80, 0x17, 0x82, + 0xf0, 0x74, 0x06, 0x2f, 0xf9, 0x80, 0x14, 0xb2, + 0xf9, 0x80, 0x19, 0x10, 0xf0, 0x74, 0x0d, 0xe3, + 0xf0, 0x74, 0x07, 0xe8, 0xf0, 0x74, 0x02, 0x36, + 0x8a, 0x11, 0xfc, 0x00, 0x4a, 0x11, 0x60, 0xf8, + 0x27, 0x7b, 0xff, 0xff, 0xf8, 0x30, 0x08, 0x39, + 0x71, 0xf8, 0x27, 0x7b, 0x27, 0x79, 0x60, 0xf8, + 0x27, 0x79, 0xff, 0xff, 0xf8, 0x30, 0x08, 0xb2, + 0x10, 0xf8, 0x29, 0x86, 0x08, 0xf8, 0x27, 0x79, + 0xf0, 0x30, 0x7f, 0xff, 0x88, 0x11, 0xf4, 0x95, + 0x77, 0x10, 0x40, 0x00, 0xf6, 0xa9, 0xf8, 0x30, + 0x08, 0x58, 0x10, 0xf8, 0x27, 0x79, 0x08, 0xf8, + 0x27, 0x7a, 0xf0, 0x30, 0x7f, 0xff, 0x88, 0x11, + 0xf4, 0x95, 0x77, 0x10, 0x40, 0x00, 0xf6, 0xa9, + 0xf8, 0x20, 0x08, 0x63, 0x76, 0xf8, 0x27, 0x79, + 0xff, 0xff, 0x76, 0xf8, 0x27, 0x7b, 0xff, 0xff, + 0xf7, 0xb8, 0xf2, 0x73, 0x08, 0xd9, 0xf0, 0x20, + 0xff, 0xff, 0xf6, 0xb8, 0x56, 0xf8, 0x27, 0x74, + 0xf0, 0xf9, 0x88, 0x11, 0x56, 0xf8, 0x27, 0x72, + 0xf0, 0xf9, 0x88, 0x12, 0xf4, 0x95, 0xf4, 0x95, + 0xe7, 0x20, 0xf4, 0xa9, 0xf8, 0x30, 0x08, 0x8f, + 0xf1, 0x20, 0x27, 0x7c, 0x48, 0x11, 0xf6, 0x00, + 0x88, 0x13, 0xf4, 0x95, 0xf4, 0x95, 0x10, 0x83, + 0x08, 0xf8, 0x27, 0x79, 0xf0, 0x30, 0x7f, 0xff, + 0x88, 0x13, 0xf4, 0x95, 0x77, 0x10, 0x40, 0x00, + 0xf5, 0xab, 0xf8, 0x30, 0x08, 0x8f, 0x6d, 0x91, + 0x48, 0x11, 0xf0, 0x30, 0x01, 0xff, 0x88, 0x11, + 0xf4, 0x95, 0xe7, 0x20, 0xf7, 0xa9, 0xf8, 0x30, + 0x08, 0x74, 0x6d, 0x89, 0x48, 0x11, 0xf0, 0x30, + 0x01, 0xff, 0xf0, 0xe7, 0xf4, 0x95, 0x48, 0x08, + 0x4e, 0xf8, 0x27, 0x74, 0x48, 0x08, 0xf1, 0xf9, + 0x89, 0x11, 0xf4, 0x95, 0xf4, 0x95, 0x71, 0xe1, + 0x27, 0x7c, 0x27, 0x7a, 0x60, 0xf8, 0x27, 0x7b, + 0xff, 0xff, 0xf8, 0x30, 0x08, 0xab, 0x48, 0x08, + 0x4e, 0xf8, 0x27, 0x72, 0x76, 0xf8, 0x27, 0x7b, + 0xff, 0xff, 0x76, 0xf8, 0x27, 0x79, 0xff, 0xff, + 0xf2, 0x73, 0x08, 0xd9, 0xf4, 0x95, 0xe8, 0x00, + 0x44, 0xf8, 0x27, 0x73, 0x40, 0xf8, 0x27, 0x75, + 0x82, 0xf8, 0x00, 0x11, 0xf4, 0x95, 0x77, 0x10, + 0x80, 0x00, 0xf6, 0xa9, 0xf8, 0x20, 0x08, 0xd8, + 0xf6, 0xb8, 0x10, 0xf8, 0x27, 0x73, 0xf0, 0x00, + 0x80, 0x00, 0x48, 0x08, 0x4e, 0xf8, 0x27, 0x74, + 0x48, 0x08, 0xf0, 0xf9, 0x88, 0x11, 0xf4, 0x95, + 0xf4, 0x95, 0x71, 0xe1, 0x27, 0x7c, 0x27, 0x7a, + 0xf7, 0xb8, 0x57, 0xf8, 0x27, 0x74, 0xf0, 0x62, + 0xff, 0xff, 0xf0, 0x40, 0xff, 0x80, 0xf2, 0x80, + 0x4e, 0xf8, 0x27, 0x74, 0xe8, 0x00, 0x8a, 0x11, + 0xfc, 0x00, 0x4a, 0x11, 0x4a, 0x16, 0xee, 0xfb, + 0x11, 0xf8, 0x27, 0x71, 0x09, 0xf8, 0x27, 0x73, + 0x89, 0x11, 0x88, 0x10, 0xf4, 0x95, 0xf4, 0x95, + 0xf6, 0xa9, 0xf8, 0x20, 0x08, 0xed, 0xf2, 0x73, + 0x09, 0x0e, 0xf4, 0x95, 0xe8, 0x00, 0xf6, 0x20, + 0x76, 0x00, 0x00, 0x41, 0xf0, 0x74, 0x12, 0xee, + 0x88, 0x16, 0xf4, 0x95, 0xf7, 0xb8, 0x6d, 0x96, + 0x10, 0xf8, 0x00, 0x16, 0xf8, 0x47, 0x09, 0x0a, + 0xe7, 0x61, 0x76, 0x00, 0x00, 0x00, 0x76, 0x01, + 0x00, 0x80, 0x76, 0x02, 0x00, 0xff, 0x76, 0x03, + 0x00, 0x00, 0xf2, 0x74, 0x0c, 0xb9, 0xf4, 0x95, + 0xe8, 0x00, 0x6c, 0xe9, 0xff, 0xff, 0x08, 0xfb, + 0x73, 0x16, 0x00, 0x0e, 0xf0, 0x66, 0x00, 0x41, + 0xee, 0x05, 0x8a, 0x16, 0x8a, 0x11, 0xfc, 0x00, + 0x4a, 0x11, 0xf4, 0x95, 0x71, 0x02, 0x00, 0x13, + 0xf6, 0xb8, 0x77, 0x11, 0x7f, 0xff, 0x57, 0xf8, + 0x27, 0x72, 0x48, 0x11, 0xf2, 0x80, 0xf0, 0x00, + 0x80, 0x00, 0x88, 0x11, 0xf6, 0x40, 0xf0, 0xe0, + 0xf1, 0xf1, 0xe8, 0x01, 0xf2, 0x80, 0x80, 0xf8, + 0x27, 0x78, 0x77, 0x12, 0x80, 0x00, 0x57, 0xf8, + 0x27, 0x72, 0x48, 0x12, 0xf2, 0x80, 0x88, 0x12, + 0xf4, 0x95, 0xf4, 0x95, 0x6c, 0x82, 0x09, 0x38, + 0xe8, 0x00, 0x75, 0xf8, 0x00, 0x08, 0x00, 0x01, + 0xf0, 0x73, 0x09, 0x3d, 0xf0, 0x20, 0x80, 0x01, + 0x75, 0xf8, 0x00, 0x08, 0x00, 0x01, 0x70, 0x81, + 0x00, 0x13, 0x8a, 0x11, 0xfc, 0x00, 0x4a, 0x11, + 0xf0, 0x30, 0x7f, 0xff, 0x11, 0xf8, 0x29, 0x86, + 0xf5, 0x20, 0xf3, 0x30, 0x7f, 0xff, 0x89, 0x11, + 0xf4, 0x95, 0x77, 0x10, 0x40, 0x00, 0xf6, 0xa9, + 0xf8, 0x20, 0x09, 0x54, 0xf2, 0x73, 0x09, 0x67, + 0xf4, 0x95, 0xe8, 0x02, 0x6f, 0xf8, 0x27, 0x7a, + 0x0d, 0x20, 0xf3, 0x30, 0x7f, 0xff, 0x89, 0x11, + 0xf4, 0x95, 0x77, 0x10, 0x40, 0x00, 0xf6, 0xa9, + 0xf8, 0x20, 0x09, 0x64, 0xf2, 0x73, 0x09, 0x67, + 0xf4, 0x95, 0xe8, 0x01, 0x80, 0xf8, 0x27, 0x7b, + 0xe8, 0x00, 0x8a, 0x11, 0xfc, 0x00, 0x4a, 0x11, + 0x11, 0xf8, 0x29, 0x86, 0xf5, 0x20, 0xf3, 0x30, + 0x7f, 0xff, 0x89, 0x11, 0xf4, 0x95, 0x77, 0x10, + 0x40, 0x00, 0xf6, 0xa9, 0xf8, 0x20, 0x09, 0x7a, + 0xf2, 0x73, 0x09, 0x8d, 0xf4, 0x95, 0xe8, 0x02, + 0x6f, 0xf8, 0x27, 0x7a, 0x0d, 0x20, 0xf3, 0x30, + 0x7f, 0xff, 0x89, 0x11, 0xf4, 0x95, 0x77, 0x10, + 0x40, 0x00, 0xf6, 0xa9, 0xf8, 0x20, 0x09, 0x8a, + 0xf2, 0x73, 0x09, 0x8d, 0xf4, 0x95, 0xe8, 0x01, + 0x80, 0xf8, 0x27, 0x79, 0xe8, 0x00, 0x8a, 0x11, + 0xfc, 0x00, 0x4a, 0x11, 0xf4, 0x95, 0x71, 0x02, + 0x00, 0x12, 0x88, 0x11, 0xf6, 0xb8, 0x57, 0xf8, + 0x27, 0x72, 0xf0, 0x20, 0x7f, 0xff, 0xf2, 0x80, + 0xf0, 0x00, 0x80, 0x00, 0x80, 0x81, 0x57, 0xf8, + 0x27, 0x72, 0xe8, 0x01, 0xf3, 0xf1, 0xf2, 0x80, + 0x80, 0xf8, 0x27, 0x78, 0x77, 0x11, 0x80, 0x00, + 0x48, 0x11, 0x57, 0xf8, 0x27, 0x72, 0xf2, 0x80, + 0x88, 0x11, 0xf4, 0x95, 0xf4, 0x95, 0x6c, 0x81, + 0x09, 0xb5, 0xe8, 0x00, 0x75, 0xf8, 0x00, 0x08, + 0x00, 0x01, 0xf0, 0x73, 0x09, 0xba, 0xf0, 0x20, + 0x80, 0x01, 0x75, 0xf8, 0x00, 0x08, 0x00, 0x01, + 0x45, 0xf8, 0x27, 0x71, 0x43, 0xf8, 0x27, 0x73, + 0x83, 0xf8, 0x00, 0x11, 0xf4, 0x95, 0xe7, 0x20, + 0xf6, 0xa9, 0xf8, 0x30, 0x09, 0xc9, 0xf2, 0x73, + 0x09, 0xe4, 0x77, 0x12, 0x00, 0x00, 0x57, 0xf8, + 0x27, 0x72, 0xf0, 0x20, 0x7f, 0xff, 0xf2, 0x80, + 0x49, 0x12, 0xf5, 0x00, 0xf3, 0x00, 0x80, 0x00, + 0x61, 0xf8, 0x00, 0x0b, 0x80, 0x00, 0xf8, 0x30, + 0x09, 0xdc, 0xf1, 0x20, 0x80, 0x00, 0xf5, 0x20, + 0x89, 0x12, 0xf4, 0x95, 0x48, 0x12, 0x6f, 0xf8, + 0x27, 0x73, 0x0d, 0x00, 0xf4, 0x95, 0x49, 0x0b, + 0x4f, 0xf8, 0x27, 0x72, 0x8a, 0x11, 0xfe, 0x00, + 0x48, 0x12, 0xf4, 0x95, 0x4a, 0x11, 0x4a, 0x16, + 0x4a, 0x17, 0xee, 0xfc, 0xf4, 0x95, 0x71, 0x08, + 0x00, 0x16, 0x88, 0x17, 0xf0, 0x74, 0x08, 0x30, + 0x48, 0x18, 0x70, 0x00, 0x00, 0x16, 0xf2, 0x74, + 0x09, 0x8f, 0xf0, 0x00, 0x00, 0x02, 0x88, 0x11, + 0xf4, 0x95, 0xf4, 0x95, 0x6c, 0x81, 0x0a, 0x0a, + 0xf2, 0x74, 0x08, 0xdb, 0xf4, 0x95, 0x48, 0x16, + 0x48, 0x18, 0x70, 0x00, 0x00, 0x16, 0xf2, 0x74, + 0x09, 0x8f, 0xf0, 0x00, 0x00, 0x02, 0x88, 0x11, + 0x10, 0x02, 0x70, 0x01, 0x00, 0x11, 0x80, 0x00, + 0xf2, 0x74, 0x06, 0xce, 0xf4, 0x95, 0x48, 0x17, + 0x49, 0x11, 0x48, 0x17, 0xf6, 0x00, 0x88, 0x17, + 0xe7, 0x60, 0xf5, 0xa9, 0xf8, 0x20, 0x0a, 0x2d, + 0x48, 0x16, 0xf6, 0x20, 0x88, 0x11, 0x48, 0x18, + 0x70, 0x00, 0x00, 0x11, 0xf2, 0x74, 0x09, 0x8f, + 0xf0, 0x00, 0x00, 0x02, 0x88, 0x11, 0x70, 0x01, + 0x00, 0x11, 0x10, 0x02, 0x80, 0x00, 0xf2, 0x74, + 0x06, 0xce, 0xf4, 0x95, 0x48, 0x17, 0xee, 0x04, + 0x48, 0x16, 0x8a, 0x17, 0x8a, 0x16, 0x8a, 0x11, + 0xfc, 0x00, 0xee, 0xfd, 0xe8, 0x00, 0x4e, 0xf8, + 0x27, 0x70, 0xe8, 0x00, 0x4e, 0xf8, 0x27, 0x72, + 0xe8, 0x00, 0x4e, 0xf8, 0x27, 0x74, 0xe8, 0x00, + 0x4e, 0xf8, 0x27, 0x76, 0x76, 0xf8, 0x27, 0x79, + 0xff, 0xff, 0x76, 0xf8, 0x27, 0x7a, 0x00, 0x00, + 0x76, 0xf8, 0x27, 0x7b, 0xff, 0xff, 0x76, 0xf8, + 0x27, 0x78, 0x00, 0x00, 0xe8, 0x00, 0x75, 0xf8, + 0x00, 0x08, 0x00, 0x01, 0x76, 0x00, 0x00, 0x00, + 0x76, 0x01, 0x02, 0x00, 0xf2, 0x74, 0x12, 0xdc, + 0xf0, 0x20, 0x27, 0x7c, 0xee, 0x03, 0xfc, 0x00, + 0x4a, 0x11, 0xee, 0xfc, 0xf4, 0x95, 0x4e, 0x00, + 0x77, 0x12, 0x7f, 0xff, 0xf6, 0xb8, 0x49, 0x12, + 0xf1, 0x80, 0xf3, 0x00, 0x80, 0x00, 0x89, 0x12, + 0xf0, 0xe0, 0xf1, 0xf1, 0x4f, 0x02, 0xe9, 0x01, + 0xf4, 0x95, 0x48, 0x0b, 0xf5, 0x40, 0x56, 0x02, + 0xf1, 0x80, 0x81, 0xf8, 0x27, 0x78, 0x77, 0x11, + 0x80, 0x00, 0x56, 0x00, 0x49, 0x11, 0xf1, 0x80, + 0x89, 0x11, 0xf4, 0x95, 0xf4, 0x95, 0x6c, 0x81, + 0x0a, 0x81, 0xe8, 0x00, 0x75, 0xf8, 0x00, 0x08, + 0x00, 0x01, 0xf0, 0x73, 0x0a, 0x86, 0xf0, 0x20, + 0x80, 0x01, 0x75, 0xf8, 0x00, 0x08, 0x00, 0x01, + 0x10, 0x82, 0xee, 0x04, 0x8a, 0x11, 0xfc, 0x00, + 0x4a, 0x11, 0xee, 0xfe, 0xf4, 0x95, 0x4e, 0x00, + 0x77, 0x11, 0x7f, 0xff, 0xf6, 0xb8, 0x49, 0x11, + 0xf1, 0x80, 0xf3, 0x00, 0x80, 0x00, 0x89, 0x11, + 0xf0, 0xe0, 0xf1, 0xf1, 0xe8, 0x01, 0xf2, 0x80, + 0x80, 0xf8, 0x27, 0x78, 0x56, 0x00, 0xf1, 0x20, + 0x80, 0x00, 0xf1, 0x80, 0xf4, 0x95, 0x49, 0x0b, + 0xf8, 0x4d, 0x0a, 0xab, 0xf0, 0x20, 0x80, 0x01, + 0x75, 0xf8, 0x00, 0x08, 0x00, 0x01, 0xf0, 0x73, + 0x0a, 0xaf, 0xe8, 0x00, 0x75, 0xf8, 0x00, 0x08, + 0x00, 0x01, 0xee, 0x02, 0x48, 0x11, 0x8a, 0x11, + 0xfc, 0x00, 0x4a, 0x11, 0x88, 0x12, 0x13, 0x02, + 0x77, 0x11, 0x00, 0x00, 0xf8, 0x4d, 0x0a, 0xcb, + 0xf3, 0x10, 0x00, 0x01, 0x89, 0x1a, 0xf4, 0x95, + 0xf0, 0x72, 0x0a, 0xca, 0x48, 0x11, 0x1c, 0xf8, + 0x29, 0x7e, 0x88, 0x11, 0x11, 0xf8, 0x29, 0x7e, + 0xf2, 0x00, 0x00, 0x01, 0x80, 0xf8, 0x29, 0x7e, + 0x81, 0x92, 0x48, 0x11, 0x8a, 0x11, 0xfc, 0x00, + 0x4a, 0x11, 0xf4, 0x95, 0x71, 0x02, 0x00, 0x11, + 0x88, 0x12, 0xf6, 0xb8, 0xf0, 0x20, 0x7f, 0xff, + 0x57, 0xf8, 0x27, 0x70, 0xf2, 0x80, 0xf0, 0x00, + 0x80, 0x00, 0x80, 0x82, 0x57, 0xf8, 0x27, 0x70, + 0xe8, 0x01, 0xf3, 0xf1, 0xf2, 0x80, 0x80, 0xf8, + 0x27, 0x78, 0x77, 0x12, 0x80, 0x00, 0x48, 0x12, + 0x57, 0xf8, 0x27, 0x70, 0xf2, 0x80, 0x88, 0x12, + 0xf4, 0x95, 0xf4, 0x95, 0x6c, 0x82, 0x0a, 0xf4, + 0xe8, 0x00, 0x75, 0xf8, 0x00, 0x08, 0x00, 0x01, + 0xf0, 0x73, 0x0a, 0xf9, 0xf0, 0x20, 0x80, 0x01, + 0x75, 0xf8, 0x00, 0x08, 0x00, 0x01, 0x45, 0xf8, + 0x27, 0x75, 0xe7, 0x10, 0x43, 0xf8, 0x27, 0x71, + 0x83, 0xf8, 0x00, 0x12, 0x6d, 0xe8, 0x00, 0x04, + 0x6d, 0x8a, 0xf6, 0xaa, 0xf8, 0x30, 0x0b, 0x0a, + 0xf2, 0x73, 0x0b, 0x25, 0x77, 0x11, 0x00, 0x00, + 0x57, 0xf8, 0x27, 0x70, 0xf0, 0x20, 0x7f, 0xff, + 0xf2, 0x80, 0x49, 0x11, 0xf5, 0x00, 0xf3, 0x00, + 0x80, 0x00, 0x61, 0xf8, 0x00, 0x0b, 0x80, 0x00, + 0xf8, 0x30, 0x0b, 0x1d, 0xf1, 0x20, 0x80, 0x00, + 0xf5, 0x20, 0x89, 0x11, 0xf4, 0x95, 0x48, 0x11, + 0x6f, 0xf8, 0x27, 0x71, 0x0d, 0x00, 0xf4, 0x95, + 0x49, 0x0b, 0x4f, 0xf8, 0x27, 0x70, 0x48, 0x11, + 0x8a, 0x11, 0xfc, 0x00, 0x4a, 0x11, 0x4a, 0x16, + 0x4a, 0x17, 0xee, 0xf0, 0x88, 0x17, 0x10, 0x17, + 0x80, 0x05, 0x10, 0x16, 0x80, 0x06, 0x10, 0x15, + 0x80, 0x07, 0x71, 0x14, 0x00, 0x11, 0x10, 0x05, + 0xf0, 0x30, 0x00, 0x01, 0x88, 0x10, 0x10, 0x06, + 0xf0, 0x30, 0x00, 0x01, 0x80, 0x08, 0x49, 0x11, + 0x10, 0x05, 0xf6, 0x01, 0x80, 0x09, 0x10, 0x06, + 0x61, 0xf8, 0x00, 0x08, 0x00, 0x01, 0xf8, 0x20, + 0x0b, 0x4b, 0x10, 0x09, 0xf0, 0x00, 0x00, 0x01, + 0x80, 0x09, 0x71, 0x08, 0x00, 0x12, 0xf4, 0xaa, + 0xf8, 0x30, 0x0b, 0x54, 0x10, 0x09, 0xf0, 0x00, + 0x00, 0x01, 0x80, 0x09, 0x12, 0x09, 0x49, 0x11, + 0xf4, 0x7f, 0x80, 0x09, 0xf6, 0x20, 0x80, 0x0a, + 0x56, 0xf8, 0x27, 0x70, 0x4e, 0x0c, 0x10, 0x09, + 0x80, 0x00, 0x48, 0x18, 0xf2, 0x74, 0x0a, 0xce, + 0xf0, 0x00, 0x00, 0x04, 0x88, 0x16, 0xf4, 0x95, + 0xf4, 0x95, 0x6c, 0x86, 0x0b, 0x6d, 0xf2, 0x73, + 0x0c, 0x59, 0xf4, 0x95, 0xe8, 0x00, 0xf6, 0xb8, + 0xf4, 0x95, 0x56, 0x0c, 0xf0, 0xf9, 0x88, 0x12, + 0xf4, 0x95, 0xf4, 0x95, 0x70, 0xe2, 0x27, 0x7c, + 0x29, 0x86, 0xe8, 0x00, 0x80, 0x0e, 0x48, 0x11, + 0xf8, 0x45, 0x0b, 0xcc, 0x77, 0x10, 0x00, 0x01, + 0xf4, 0xa9, 0xf8, 0x30, 0x0b, 0x89, 0x6c, 0xe1, + 0xff, 0xfd, 0x0b, 0x8b, 0x10, 0xe7, 0x00, 0x02, + 0x80, 0x0e, 0xf0, 0x73, 0x0b, 0x8b, 0x10, 0x87, + 0x80, 0x0e, 0xe7, 0x10, 0xf5, 0xae, 0xf8, 0x20, + 0x0b, 0xb2, 0x70, 0x00, 0x00, 0x17, 0x70, 0x01, + 0x00, 0x16, 0x10, 0x04, 0xf0, 0x74, 0x06, 0xce, + 0x48, 0x17, 0x49, 0x16, 0xf6, 0x00, 0x88, 0x17, + 0x48, 0x11, 0xf6, 0x20, 0x88, 0x11, 0x10, 0x09, + 0xf6, 0x20, 0x80, 0x00, 0x48, 0x18, 0xf2, 0x74, + 0x0a, 0xce, 0xf0, 0x00, 0x00, 0x04, 0x88, 0x16, + 0x10, 0x04, 0x70, 0x00, 0x00, 0x17, 0x70, 0x01, + 0x00, 0x11, 0xf0, 0x74, 0x06, 0xce, 0x48, 0x11, + 0x00, 0x04, 0x80, 0x04, 0xf0, 0x73, 0x0b, 0xbc, + 0x70, 0x00, 0x00, 0x17, 0x70, 0x01, 0x00, 0x11, + 0x10, 0x04, 0xf0, 0x74, 0x06, 0xce, 0x48, 0x11, + 0x00, 0x04, 0x80, 0x04, 0x49, 0x11, 0x48, 0x16, + 0xf6, 0x20, 0x88, 0x16, 0xf4, 0x95, 0xf4, 0x95, + 0x6c, 0x86, 0x0b, 0xcc, 0x10, 0x0a, 0x80, 0x00, + 0x48, 0x18, 0xf2, 0x74, 0x0a, 0xce, 0xf0, 0x00, + 0x00, 0x04, 0x88, 0x16, 0x12, 0x0a, 0xf8, 0x45, + 0x0c, 0x33, 0x71, 0x0a, 0x00, 0x10, 0xf4, 0xae, + 0xf8, 0x30, 0x0c, 0x1c, 0x48, 0x16, 0xf0, 0xe1, + 0x88, 0x11, 0x12, 0x08, 0xf8, 0x45, 0x0b, 0xdb, + 0x6d, 0x89, 0x12, 0x07, 0xf8, 0x45, 0x0b, 0xe9, + 0x10, 0x07, 0x80, 0x00, 0x70, 0x02, 0x00, 0x11, + 0x10, 0x06, 0x80, 0x01, 0x10, 0x04, 0xf0, 0x74, + 0x06, 0xdc, 0xf0, 0x73, 0x0b, 0xef, 0x48, 0x11, + 0x6f, 0x00, 0x0c, 0x9f, 0x10, 0x04, 0xf0, 0x74, + 0x0a, 0xb3, 0x11, 0x0e, 0xf1, 0xc0, 0x81, 0x0e, + 0x10, 0x06, 0x49, 0x11, 0xf6, 0x00, 0x80, 0x06, + 0x10, 0x05, 0xf6, 0x20, 0x88, 0x11, 0xf0, 0x00, + 0x00, 0x01, 0x48, 0x08, 0x6f, 0x00, 0x0c, 0x9f, + 0x48, 0x18, 0xf2, 0x74, 0x0a, 0xce, 0xf0, 0x00, + 0x00, 0x04, 0x12, 0x07, 0xf8, 0x45, 0x0c, 0x11, + 0x10, 0x07, 0x80, 0x00, 0x70, 0x02, 0x00, 0x11, + 0x10, 0x06, 0x80, 0x01, 0x10, 0x04, 0xf0, 0x74, + 0x06, 0xdc, 0xf0, 0x73, 0x0c, 0x17, 0x48, 0x11, + 0x6f, 0x00, 0x0c, 0x9f, 0x10, 0x04, 0xf0, 0x74, + 0x0a, 0xb3, 0x11, 0x0e, 0xf1, 0xc0, 0x81, 0x0e, + 0xf0, 0x73, 0x0c, 0x33, 0x12, 0x07, 0xf8, 0x45, + 0x0c, 0x2a, 0x10, 0x07, 0x80, 0x00, 0x10, 0x06, + 0x80, 0x01, 0x10, 0x05, 0x80, 0x02, 0x10, 0x04, + 0xf0, 0x74, 0x06, 0xdc, 0xf0, 0x73, 0x0c, 0x30, + 0x12, 0x05, 0x6f, 0x00, 0x0c, 0x9f, 0x10, 0x04, + 0xf0, 0x74, 0x0a, 0xb3, 0x11, 0x0e, 0xf1, 0xc0, + 0x81, 0x0e, 0x76, 0x00, 0x00, 0x01, 0x48, 0x18, + 0xf2, 0x74, 0x0a, 0xce, 0xf0, 0x00, 0x00, 0x04, + 0x71, 0x04, 0x00, 0x11, 0x70, 0x81, 0x29, 0x86, + 0x10, 0x0e, 0x1c, 0xf8, 0x29, 0x86, 0x80, 0x0e, + 0x76, 0x00, 0x00, 0x01, 0x48, 0x18, 0xf2, 0x74, + 0x0a, 0xce, 0xf0, 0x00, 0x00, 0x04, 0x10, 0x0e, + 0x71, 0x04, 0x00, 0x11, 0x80, 0x81, 0x10, 0xf8, + 0x29, 0x86, 0xf0, 0x00, 0x00, 0x01, 0xf0, 0x30, + 0x7f, 0xff, 0x80, 0xf8, 0x29, 0x86, 0x10, 0x09, + 0xf0, 0x00, 0x00, 0x02, 0x80, 0x09, 0xee, 0x10, + 0x8a, 0x17, 0x8a, 0x16, 0x8a, 0x11, 0xfc, 0x00, + 0x10, 0xf8, 0x27, 0x75, 0x08, 0xf8, 0x27, 0x71, + 0xf0, 0x10, 0x00, 0x01, 0x48, 0x08, 0xfc, 0x00, + 0x4a, 0x11, 0x4a, 0x16, 0xee, 0xff, 0xf4, 0x95, + 0x71, 0x04, 0x00, 0x16, 0xf0, 0x00, 0x00, 0x01, + 0x48, 0x08, 0x4e, 0xf8, 0x29, 0x7c, 0x6d, 0xee, + 0xff, 0xfd, 0x48, 0x16, 0xf8, 0x45, 0x0c, 0x99, + 0x56, 0xf8, 0x29, 0x7c, 0xf0, 0x74, 0x0a, 0x5a, + 0x88, 0x11, 0x10, 0xf8, 0x29, 0x7d, 0xf0, 0x00, + 0x00, 0x01, 0x48, 0x08, 0x4e, 0xf8, 0x29, 0x7c, + 0x10, 0xf8, 0x29, 0x82, 0xf0, 0x00, 0x00, 0x01, + 0x88, 0x10, 0xf4, 0x95, 0xf4, 0x95, 0xf4, 0xa9, + 0xfa, 0x30, 0x0c, 0x96, 0x80, 0xf8, 0x29, 0x82, + 0x56, 0xf8, 0x29, 0x80, 0xf0, 0x00, 0x00, 0x01, + 0x4e, 0xf8, 0x29, 0x80, 0x73, 0x11, 0x29, 0x82, + 0x6c, 0xee, 0xff, 0xff, 0x0c, 0x76, 0xee, 0x01, + 0x8a, 0x16, 0x8a, 0x11, 0xfc, 0x00, 0x4a, 0x11, + 0x76, 0xf8, 0x29, 0x84, 0x00, 0x00, 0x76, 0xf8, + 0x29, 0x85, 0x00, 0x01, 0xe8, 0x00, 0x4e, 0xf8, + 0x2a, 0x0c, 0x76, 0xf8, 0x29, 0x86, 0x00, 0x00, + 0x76, 0xf8, 0x29, 0x87, 0x00, 0x00, 0x77, 0x11, + 0x29, 0x88, 0x76, 0x81, 0xaa, 0xaa, 0x76, 0xe1, + 0x00, 0x01, 0xaa, 0xaa, 0x76, 0xe1, 0x00, 0x02, + 0x00, 0x00, 0x8a, 0x11, 0xfc, 0x00, 0x4a, 0x11, + 0xee, 0xfc, 0xf4, 0x95, 0x71, 0x06, 0x00, 0x14, + 0x71, 0x07, 0x00, 0x13, 0x71, 0x08, 0x00, 0x12, + 0x71, 0x09, 0x00, 0x15, 0x77, 0x10, 0x00, 0xff, + 0xf4, 0xaa, 0xf8, 0x30, 0x0d, 0x44, 0x49, 0x13, + 0x53, 0xf8, 0x2a, 0x0c, 0x4f, 0xf8, 0x2a, 0x0c, + 0x73, 0x12, 0x00, 0x0e, 0xf1, 0x66, 0x00, 0x0d, + 0x89, 0x11, 0xf4, 0x95, 0x77, 0x10, 0x00, 0x01, + 0x71, 0xe1, 0x24, 0x00, 0x00, 0x11, 0xf4, 0xa9, + 0xf8, 0x30, 0x0d, 0x17, 0x77, 0x10, 0x00, 0x02, + 0xf4, 0xa9, 0xf8, 0x30, 0x0c, 0xec, 0x77, 0x11, + 0x29, 0x8a, 0x76, 0x81, 0x00, 0x00, 0xe8, 0x00, + 0x77, 0x14, 0x00, 0x00, 0x77, 0x13, 0x00, 0x00, + 0xf0, 0x73, 0x0d, 0x48, 0x6c, 0x83, 0x0c, 0xfa, + 0x77, 0x11, 0x29, 0x8a, 0x48, 0x12, 0xf0, 0xe8, + 0xf0, 0x40, 0x80, 0x00, 0x80, 0x81, 0xe8, 0x00, + 0x77, 0x14, 0x00, 0x00, 0xf0, 0x73, 0x0d, 0x48, + 0x49, 0x13, 0xf3, 0x40, 0x80, 0x00, 0x81, 0xf8, + 0x29, 0x8a, 0x61, 0xf8, 0x00, 0x15, 0x00, 0x01, + 0xf8, 0x20, 0x0d, 0x07, 0x69, 0xf8, 0x29, 0x8a, + 0x40, 0x00, 0x61, 0xf8, 0x00, 0x14, 0x00, 0x01, + 0xf8, 0x20, 0x0d, 0x0f, 0x69, 0xf8, 0x29, 0x8a, + 0x20, 0x00, 0x77, 0x11, 0x29, 0x8a, 0x49, 0x12, + 0xf3, 0xe8, 0x1b, 0x81, 0x81, 0x81, 0xf0, 0x73, + 0x0d, 0x48, 0x11, 0xf8, 0x29, 0x84, 0xf8, 0x4c, + 0x0d, 0x37, 0x77, 0x11, 0x29, 0x88, 0x76, 0x81, + 0xaa, 0xaa, 0x11, 0xf8, 0x29, 0x85, 0xf3, 0x10, + 0x00, 0x01, 0xf3, 0x40, 0xaa, 0x00, 0x81, 0xe1, + 0x00, 0x01, 0x76, 0x00, 0x00, 0x02, 0x80, 0x01, + 0x70, 0x02, 0x00, 0x14, 0x70, 0x03, 0x00, 0x13, + 0xf2, 0x74, 0x0b, 0x28, 0xf4, 0x95, 0x48, 0x11, + 0x71, 0xf8, 0x29, 0x85, 0x29, 0x84, 0xf0, 0x73, + 0x0d, 0x73, 0x76, 0x00, 0x00, 0x00, 0x80, 0x01, + 0x76, 0x02, 0x00, 0x00, 0x70, 0x03, 0x00, 0x13, + 0xf2, 0x74, 0x0b, 0x28, 0xf4, 0x95, 0xe8, 0x00, + 0xf0, 0x73, 0x0d, 0x73, 0x77, 0x11, 0x29, 0x8a, + 0x70, 0x81, 0x00, 0x13, 0x11, 0xf8, 0x29, 0x84, + 0xf8, 0x4c, 0x0d, 0x68, 0x77, 0x11, 0x29, 0x88, + 0x76, 0x81, 0xaa, 0xaa, 0x11, 0xf8, 0x29, 0x85, + 0xf3, 0x10, 0x00, 0x01, 0xf3, 0x40, 0xaa, 0x00, + 0x81, 0xe1, 0x00, 0x01, 0x76, 0x00, 0x00, 0x03, + 0x80, 0x01, 0x70, 0x02, 0x00, 0x14, 0x70, 0x03, + 0x00, 0x13, 0xf2, 0x74, 0x0b, 0x28, 0xf4, 0x95, + 0x48, 0x11, 0x71, 0xf8, 0x29, 0x85, 0x29, 0x84, + 0xf0, 0x73, 0x0d, 0x73, 0x76, 0x00, 0x00, 0x01, + 0x80, 0x01, 0x70, 0x02, 0x00, 0x14, 0x70, 0x03, + 0x00, 0x13, 0xf2, 0x74, 0x0b, 0x28, 0xf4, 0x95, + 0x48, 0x11, 0x6b, 0xf8, 0x29, 0x84, 0xff, 0xff, + 0xee, 0x04, 0x8a, 0x11, 0xfc, 0x00, 0x4a, 0x11, + 0xf5, 0x40, 0xf4, 0x95, 0x48, 0x0b, 0xf4, 0x78, + 0x88, 0x11, 0xf4, 0x95, 0xf4, 0x95, 0x6c, 0xe1, + 0xff, 0xb9, 0x0d, 0x88, 0xf2, 0x73, 0x0d, 0xa5, + 0xf4, 0x95, 0xe8, 0x60, 0xf2, 0x00, 0x00, 0x06, + 0x61, 0xf8, 0x00, 0x11, 0x00, 0x20, 0xf8, 0x30, + 0x0d, 0x98, 0x61, 0xf8, 0x00, 0x0b, 0x00, 0x01, + 0xf8, 0x20, 0x0d, 0xa3, 0xf2, 0x00, 0x00, 0x07, + 0xf0, 0x73, 0x0d, 0xa3, 0x61, 0xf8, 0x00, 0x0b, + 0x00, 0x01, 0xf8, 0x20, 0x0d, 0xa1, 0xf2, 0x73, + 0x0d, 0xa3, 0xf0, 0x00, 0x00, 0x01, 0xf0, 0x00, + 0x00, 0x02, 0x48, 0x08, 0xf4, 0x7f, 0x8a, 0x11, + 0xfc, 0x00, 0xee, 0xff, 0xf0, 0x74, 0x07, 0xfd, + 0xf0, 0x74, 0x07, 0x44, 0xf0, 0x74, 0x0d, 0xb4, + 0xf0, 0x74, 0x02, 0x05, 0xf0, 0x74, 0x04, 0x60, + 0xf0, 0x73, 0x0d, 0xaa, 0xee, 0xfd, 0x10, 0xf8, + 0x2a, 0xa3, 0xf8, 0x44, 0x0d, 0xcb, 0x10, 0xf8, + 0x2a, 0xa4, 0xf8, 0x45, 0x0d, 0xd7, 0x76, 0x00, + 0x02, 0x00, 0xf2, 0x74, 0x09, 0xe8, 0xf0, 0x20, + 0x22, 0x00, 0x76, 0xf8, 0x2a, 0xa4, 0x00, 0x00, + 0x76, 0xf8, 0x2a, 0xa7, 0x00, 0x00, 0xf0, 0x73, + 0x0d, 0xd7, 0x76, 0x00, 0x02, 0x00, 0xf2, 0x74, + 0x09, 0xe8, 0xf0, 0x20, 0x20, 0x00, 0x76, 0xf8, + 0x2a, 0xa3, 0x00, 0x00, 0x76, 0xf8, 0x2a, 0xa7, + 0x00, 0x01, 0xf0, 0x74, 0x0c, 0x5e, 0xf0, 0xe0, + 0xf0, 0x10, 0x3a, 0x98, 0xf8, 0x47, 0x0d, 0xe1, + 0x76, 0xf8, 0x27, 0x6e, 0x00, 0x00, 0xee, 0x03, + 0xfc, 0x00, 0x4a, 0x11, 0xee, 0xfe, 0x77, 0x11, + 0x20, 0x00, 0x76, 0x00, 0xaa, 0xaa, 0x76, 0x01, + 0x02, 0x00, 0xf2, 0x74, 0x06, 0x6c, 0xf4, 0x95, + 0x48, 0x11, 0x76, 0x00, 0x55, 0x55, 0x76, 0x01, + 0x02, 0x00, 0x48, 0x11, 0xf2, 0x74, 0x06, 0x6c, + 0xf0, 0x00, 0x02, 0x00, 0x76, 0xf8, 0x2a, 0xa3, + 0x00, 0x00, 0x76, 0xf8, 0x2a, 0xa4, 0x00, 0x00, + 0xe8, 0x00, 0x4e, 0x00, 0xfb, 0x80, 0x15, 0x3e, + 0xf4, 0x95, 0xe8, 0x04, 0x80, 0xf8, 0x2a, 0xa5, + 0x76, 0x00, 0x2a, 0xa8, 0xf9, 0x80, 0x14, 0x87, + 0x76, 0x00, 0x2a, 0xad, 0xfb, 0x80, 0x13, 0x62, + 0xf4, 0x95, 0xe8, 0x02, 0x10, 0xf8, 0x2a, 0xa5, + 0xf9, 0x80, 0x14, 0x63, 0xfb, 0x80, 0x16, 0x66, + 0xf4, 0x95, 0xe8, 0x1c, 0xfb, 0x80, 0x16, 0x87, + 0xf4, 0x95, 0xe8, 0x1c, 0xe8, 0x01, 0x4e, 0x00, + 0xfb, 0x80, 0x17, 0xd6, 0xf4, 0x95, 0xe8, 0x00, + 0x80, 0xf8, 0x2a, 0xa6, 0x76, 0x00, 0x2a, 0xb7, + 0xf9, 0x80, 0x16, 0xaa, 0x10, 0xf8, 0x2a, 0xa6, + 0xf9, 0x80, 0x17, 0x5c, 0x10, 0xf8, 0x2a, 0xa6, + 0xf9, 0x80, 0x17, 0x6f, 0xee, 0x02, 0x8a, 0x11, + 0xfc, 0x00, 0xf4, 0x95, 0x4a, 0x08, 0x4a, 0x09, + 0x4a, 0x0a, 0x4a, 0x07, 0x4a, 0x1d, 0x68, 0xf8, + 0x00, 0x07, 0x7d, 0x3f, 0x69, 0xf8, 0x00, 0x07, + 0x40, 0x00, 0x68, 0xf8, 0x00, 0x1d, 0xff, 0xfc, + 0x10, 0xf8, 0x2a, 0xa7, 0xf8, 0x44, 0x0e, 0x4b, + 0x76, 0xf8, 0x2a, 0xa3, 0x00, 0x01, 0xf0, 0x73, + 0x0e, 0x4e, 0x76, 0xf8, 0x2a, 0xa4, 0x00, 0x01, + 0x8a, 0x1d, 0x8a, 0x07, 0x8a, 0x0a, 0x8a, 0x09, + 0x8a, 0x08, 0xf4, 0xeb, 0x4a, 0x11, 0x4a, 0x16, + 0x4a, 0x17, 0xee, 0xfe, 0x88, 0x0e, 0x71, 0x08, + 0x00, 0x16, 0x71, 0x06, 0x00, 0x17, 0x11, 0x07, + 0xf0, 0x66, 0x00, 0x0d, 0xf0, 0x00, 0x25, 0xa0, + 0x88, 0x11, 0x76, 0x01, 0x00, 0x06, 0x81, 0x00, + 0xf2, 0x74, 0x06, 0xce, 0xf0, 0x00, 0x00, 0x01, + 0x76, 0x01, 0x00, 0x06, 0x70, 0x00, 0x00, 0x16, + 0x48, 0x11, 0xf2, 0x74, 0x06, 0xce, 0xf0, 0x00, + 0x00, 0x07, 0x70, 0x81, 0x00, 0x17, 0xee, 0x02, + 0x8a, 0x17, 0x8a, 0x16, 0x8a, 0x11, 0xfc, 0x00, + 0x4a, 0x11, 0x88, 0x0e, 0x71, 0x02, 0x00, 0x12, + 0x11, 0x03, 0xf0, 0x66, 0x00, 0x0d, 0xf0, 0x00, + 0x24, 0x00, 0x88, 0x11, 0xf4, 0x95, 0x70, 0x81, + 0x00, 0x12, 0x6e, 0xe2, 0xff, 0xfe, 0x0e, 0x8d, + 0xf4, 0x95, 0xe8, 0x00, 0xe8, 0x01, 0x80, 0xe1, + 0x00, 0x02, 0x76, 0xe1, 0x00, 0x03, 0x00, 0xff, + 0x76, 0xe1, 0x00, 0x04, 0x00, 0x00, 0x76, 0xe1, + 0x00, 0x0b, 0x00, 0x00, 0x76, 0xe1, 0x00, 0x0c, + 0x00, 0x00, 0x81, 0xe1, 0x00, 0x01, 0x8a, 0x11, + 0xfc, 0x00, 0x4a, 0x11, 0xee, 0xfc, 0x88, 0x0e, + 0xf4, 0x95, 0xf1, 0x66, 0x00, 0x0d, 0xf3, 0x00, + 0x24, 0x00, 0x89, 0x11, 0xf4, 0x95, 0xf4, 0x95, + 0x76, 0xe1, 0x00, 0x0c, 0x00, 0x00, 0x76, 0xe1, + 0x00, 0x0b, 0x00, 0x00, 0x76, 0xe1, 0x00, 0x02, + 0x00, 0x01, 0x76, 0x00, 0x00, 0x00, 0x76, 0x01, + 0x00, 0x00, 0x80, 0x02, 0x76, 0x03, 0x00, 0x00, + 0xf2, 0x74, 0x0c, 0xb9, 0xf4, 0x95, 0xe8, 0x00, + 0xee, 0x04, 0x8a, 0x11, 0xfc, 0x00, 0x4a, 0x11, + 0x88, 0x19, 0xf4, 0x95, 0x73, 0x19, 0x00, 0x0e, + 0xf1, 0x66, 0x00, 0x0d, 0xf2, 0x00, 0x24, 0x00, + 0x77, 0x15, 0x25, 0xa0, 0x77, 0x14, 0x00, 0x00, + 0x77, 0x1a, 0x00, 0x1f, 0xf0, 0x72, 0x0f, 0x14, + 0xf6, 0xb8, 0x49, 0x19, 0x09, 0x85, 0xf8, 0x4c, + 0x0f, 0x13, 0xf1, 0x00, 0x00, 0x05, 0x89, 0x11, + 0x49, 0x15, 0xf3, 0x00, 0x00, 0x01, 0x89, 0x13, + 0x49, 0x15, 0xf3, 0x00, 0x00, 0x07, 0x89, 0x12, + 0x11, 0x93, 0x1d, 0x91, 0x19, 0x92, 0x89, 0x10, + 0xf4, 0x95, 0xf4, 0x95, 0x6c, 0x80, 0x0f, 0x13, + 0x11, 0x93, 0x1d, 0x91, 0x19, 0x92, 0x89, 0x10, + 0xf4, 0x95, 0xf4, 0x95, 0x6c, 0x80, 0x0f, 0x13, + 0x11, 0x93, 0x1d, 0x91, 0x19, 0x92, 0x89, 0x10, + 0xf4, 0x95, 0xf4, 0x95, 0x6c, 0x80, 0x0f, 0x13, + 0x11, 0x93, 0x1d, 0x91, 0x19, 0x92, 0x89, 0x10, + 0xf4, 0x95, 0xf4, 0x95, 0x6c, 0x80, 0x0f, 0x13, + 0x11, 0x93, 0x1d, 0x91, 0x19, 0x92, 0x89, 0x10, + 0xf4, 0x95, 0xf4, 0x95, 0x6c, 0x80, 0x0f, 0x13, + 0x11, 0x93, 0x1d, 0x91, 0x19, 0x92, 0x89, 0x11, + 0xf4, 0x95, 0xf4, 0x95, 0x6c, 0x81, 0x0f, 0x13, + 0x6d, 0x94, 0x6d, 0xed, 0x00, 0x0d, 0x48, 0x14, + 0x8a, 0x11, 0xfc, 0x00, 0x4a, 0x11, 0x4a, 0x16, + 0x4a, 0x17, 0xee, 0xf8, 0x88, 0x17, 0x10, 0x0d, + 0x80, 0x04, 0x10, 0x0c, 0x80, 0x05, 0x71, 0x0e, + 0x00, 0x16, 0x73, 0x17, 0x00, 0x0e, 0xf0, 0x66, + 0x00, 0x0d, 0xf0, 0x00, 0x24, 0x00, 0x88, 0x11, + 0x10, 0xf8, 0x27, 0x63, 0xf8, 0x45, 0x0f, 0x32, + 0xf2, 0x74, 0x0e, 0x9f, 0xf4, 0x95, 0x48, 0x17, + 0x10, 0xf8, 0x27, 0x60, 0xf8, 0x44, 0x0f, 0x3d, + 0x60, 0xe1, 0x00, 0x02, 0x00, 0x01, 0xf8, 0x20, + 0x0f, 0x6d, 0xf0, 0x73, 0x11, 0x33, 0x10, 0x04, + 0x80, 0x00, 0x10, 0x05, 0xf0, 0x74, 0x06, 0x9f, + 0x11, 0x04, 0xf3, 0x00, 0x00, 0x01, 0x81, 0x04, + 0x6d, 0x8e, 0x77, 0x10, 0x00, 0x01, 0x71, 0xe1, + 0x00, 0x02, 0x00, 0x12, 0xf4, 0xaa, 0xf8, 0x30, + 0x0f, 0x62, 0x77, 0x10, 0x00, 0x02, 0xf4, 0xaa, + 0xf8, 0x30, 0x0f, 0x6d, 0x45, 0xe1, 0x00, 0x0b, + 0x88, 0x10, 0x43, 0xe1, 0x00, 0x0c, 0x83, 0xf8, + 0x00, 0x12, 0xf4, 0x95, 0xf4, 0x95, 0xf4, 0xaa, + 0xf8, 0x30, 0x0f, 0x6d, 0xf0, 0x73, 0x0f, 0x96, + 0xf5, 0x00, 0x81, 0x04, 0x49, 0x16, 0xf5, 0x20, + 0x89, 0x16, 0x76, 0xe1, 0x00, 0x0c, 0x00, 0x00, + 0x76, 0xe1, 0x00, 0x04, 0x00, 0x00, 0x48, 0x16, + 0xf8, 0x45, 0x11, 0x33, 0xf7, 0xb8, 0x71, 0xe1, + 0x00, 0x02, 0x00, 0x12, 0x10, 0xf8, 0x00, 0x12, + 0xf0, 0x10, 0x00, 0x03, 0xf8, 0x46, 0x0f, 0x8c, + 0x10, 0xf8, 0x00, 0x12, 0xf0, 0x10, 0x00, 0x03, + 0xf8, 0x45, 0x10, 0x16, 0x77, 0x10, 0x00, 0x01, + 0xf4, 0xaa, 0xf8, 0x30, 0x0f, 0x9c, 0x77, 0x10, + 0x00, 0x02, 0xf4, 0xaa, 0xf8, 0x30, 0x0f, 0xa8, + 0xf0, 0x73, 0x0f, 0x96, 0x77, 0x10, 0x00, 0x04, + 0xf4, 0xaa, 0xf8, 0x30, 0x10, 0xb7, 0x77, 0x10, + 0x00, 0x05, 0xf4, 0xaa, 0xf8, 0x30, 0x10, 0xbc, + 0xf2, 0x74, 0x0e, 0x9f, 0xf4, 0x95, 0x48, 0x17, + 0xf0, 0x73, 0x11, 0x31, 0x76, 0xe1, 0x00, 0x0c, + 0x00, 0x00, 0x76, 0xe1, 0x00, 0x0b, 0x00, 0x00, + 0x76, 0xe1, 0x00, 0x04, 0x00, 0x00, 0x76, 0xe1, + 0x00, 0x02, 0x00, 0x02, 0x11, 0xe1, 0x00, 0x0c, + 0xe8, 0x03, 0xf6, 0x20, 0x89, 0x12, 0xf4, 0x95, + 0x77, 0x10, 0x00, 0x03, 0xf5, 0xaa, 0xf8, 0x30, + 0x0f, 0xb6, 0x6b, 0xf8, 0x27, 0x6f, 0x00, 0x01, + 0x88, 0x10, 0xf4, 0x95, 0xf4, 0x95, 0xf5, 0xae, + 0xf8, 0x20, 0x0f, 0xbd, 0x48, 0x16, 0x80, 0x06, + 0x88, 0x13, 0xf4, 0x95, 0x77, 0x10, 0x00, 0x03, + 0xf6, 0xab, 0xf8, 0x20, 0x0f, 0xc8, 0x6b, 0xf8, + 0x27, 0x6f, 0x00, 0x01, 0x12, 0x06, 0xf8, 0x45, + 0x10, 0x00, 0x10, 0xe1, 0x00, 0x04, 0x80, 0x00, + 0x10, 0x05, 0x80, 0x01, 0x10, 0x04, 0x80, 0x02, + 0x10, 0x06, 0x80, 0x03, 0x48, 0x11, 0xf2, 0x74, + 0x07, 0x1e, 0xf0, 0x00, 0x00, 0x05, 0x10, 0x06, + 0x00, 0xe1, 0x00, 0x04, 0x80, 0xe1, 0x00, 0x04, + 0x10, 0x06, 0x00, 0xe1, 0x00, 0x0c, 0x80, 0xe1, + 0x00, 0x0c, 0x88, 0x12, 0x11, 0x06, 0x10, 0x04, + 0xf6, 0x00, 0x80, 0x04, 0x48, 0x16, 0xf6, 0x20, + 0x88, 0x16, 0x89, 0x13, 0xf4, 0x95, 0x77, 0x10, + 0x00, 0x03, 0xf6, 0xab, 0xf8, 0x20, 0x0f, 0xf5, + 0x6b, 0xf8, 0x27, 0x6f, 0x00, 0x01, 0x77, 0x10, + 0x00, 0x0c, 0x71, 0xe1, 0x00, 0x04, 0x00, 0x13, + 0xf6, 0xab, 0xf8, 0x20, 0x10, 0x00, 0x6b, 0xf8, + 0x27, 0x6f, 0x00, 0x01, 0x6c, 0xe2, 0xff, 0xfd, + 0x11, 0x31, 0xf6, 0xb8, 0x6f, 0xe1, 0x00, 0x05, + 0x0c, 0x48, 0x6f, 0xe1, 0x00, 0x06, 0x0c, 0x18, + 0xf0, 0x30, 0x0f, 0xff, 0xf0, 0x00, 0x00, 0x03, + 0x80, 0xe1, 0x00, 0x0b, 0x76, 0xe1, 0x00, 0x02, + 0x00, 0x03, 0x48, 0x16, 0xf8, 0x45, 0x11, 0x33, + 0x71, 0xe1, 0x00, 0x0c, 0x00, 0x12, 0x10, 0xe1, + 0x00, 0x0b, 0x49, 0x12, 0xf6, 0x20, 0x88, 0x13, + 0xe8, 0x0c, 0xf6, 0x20, 0x88, 0x10, 0xf4, 0x95, + 0xf4, 0x95, 0xf5, 0xab, 0xf8, 0x20, 0x10, 0x27, + 0x48, 0x13, 0x80, 0x06, 0x88, 0x10, 0xf4, 0x95, + 0xf4, 0x95, 0xf5, 0xae, 0xf8, 0x20, 0x10, 0x30, + 0x70, 0x06, 0x00, 0x16, 0x12, 0x06, 0xf8, 0x45, + 0x10, 0x5f, 0x10, 0xe1, 0x00, 0x04, 0x80, 0x00, + 0x10, 0x05, 0x80, 0x01, 0x10, 0x04, 0x80, 0x02, + 0x10, 0x06, 0x80, 0x03, 0x48, 0x11, 0xf2, 0x74, + 0x07, 0x1e, 0xf0, 0x00, 0x00, 0x05, 0x10, 0x06, + 0x00, 0xe1, 0x00, 0x04, 0x80, 0xe1, 0x00, 0x04, + 0x10, 0x06, 0x00, 0xe1, 0x00, 0x0c, 0x80, 0xe1, + 0x00, 0x0c, 0x88, 0x12, 0x11, 0x06, 0x10, 0x04, + 0xf6, 0x00, 0x80, 0x04, 0x48, 0x16, 0xf6, 0x20, + 0x88, 0x16, 0xf4, 0x95, 0x77, 0x10, 0x00, 0x0c, + 0x71, 0xe1, 0x00, 0x04, 0x00, 0x13, 0xf6, 0xab, + 0xf8, 0x20, 0x10, 0x5f, 0x6b, 0xf8, 0x27, 0x6f, + 0x00, 0x01, 0x77, 0x10, 0x00, 0x0c, 0xf6, 0xaa, + 0xf8, 0x20, 0x10, 0x6b, 0xf2, 0x74, 0x0e, 0x9f, + 0xf4, 0x95, 0x48, 0x17, 0x71, 0xe1, 0x00, 0x0c, + 0x00, 0x12, 0x77, 0x10, 0x00, 0x0c, 0xf4, 0xaa, + 0xf8, 0x30, 0x10, 0x7c, 0x77, 0x10, 0x00, 0x0c, + 0x71, 0xe1, 0x00, 0x0b, 0x00, 0x13, 0xf6, 0xab, + 0xf8, 0x30, 0x10, 0xb4, 0xe7, 0x30, 0xf7, 0xaa, + 0xf8, 0x30, 0x10, 0xb4, 0xf2, 0x74, 0x0e, 0xc1, + 0xf4, 0x95, 0x48, 0x17, 0x88, 0x12, 0xf4, 0x95, + 0xf4, 0x95, 0x6c, 0x82, 0x10, 0x8d, 0x76, 0xe1, + 0x00, 0x04, 0x00, 0x00, 0x76, 0xe1, 0x00, 0x02, + 0x00, 0x05, 0xf0, 0x73, 0x10, 0xb4, 0x76, 0xe1, + 0x00, 0x02, 0x00, 0x04, 0x77, 0x10, 0x00, 0x0c, + 0x71, 0xe1, 0x00, 0x0b, 0x00, 0x12, 0xf5, 0xaa, + 0xf8, 0x20, 0x10, 0x9a, 0xf0, 0x73, 0x10, 0x9c, + 0x77, 0x12, 0x00, 0x0c, 0x76, 0x00, 0x00, 0x00, + 0x70, 0x01, 0x00, 0x12, 0x70, 0x02, 0x00, 0x17, + 0x76, 0x03, 0x00, 0x01, 0x48, 0x11, 0xf2, 0x74, + 0x0c, 0xb9, 0xf0, 0x00, 0x00, 0x05, 0x76, 0xe1, + 0x00, 0x04, 0x00, 0x00, 0x77, 0x10, 0x00, 0x0c, + 0x71, 0xe1, 0x00, 0x0b, 0x00, 0x12, 0xf6, 0xaa, + 0xf8, 0x20, 0x11, 0x1c, 0x48, 0x16, 0xf8, 0x45, + 0x11, 0x33, 0x60, 0xe1, 0x00, 0x02, 0x00, 0x05, + 0xf8, 0x20, 0x10, 0xdf, 0x10, 0xe1, 0x00, 0x0b, + 0x08, 0xe1, 0x00, 0x0c, 0x11, 0xe1, 0x00, 0x04, + 0xf8, 0x4d, 0x10, 0xc7, 0x6b, 0xf8, 0x27, 0x6f, + 0x00, 0x01, 0x88, 0x10, 0xf4, 0x95, 0xf4, 0x95, + 0xf5, 0xae, 0xf8, 0x20, 0x10, 0xcf, 0x48, 0x16, + 0xf4, 0x95, 0x48, 0x08, 0xf8, 0x45, 0x11, 0x16, + 0x6f, 0xe1, 0x00, 0x0c, 0x0d, 0x00, 0x81, 0xe1, + 0x00, 0x0c, 0x11, 0x04, 0xf5, 0x00, 0x81, 0x04, + 0x49, 0x16, 0xf5, 0x20, 0x89, 0x16, 0xf0, 0x73, + 0x11, 0x0e, 0x10, 0xe1, 0x00, 0x0b, 0x71, 0xe1, + 0x00, 0x0c, 0x00, 0x12, 0x88, 0x10, 0xf4, 0x95, + 0xf4, 0x95, 0xf6, 0xaa, 0xf8, 0x30, 0x11, 0x16, + 0x49, 0x12, 0xf6, 0x20, 0x88, 0x10, 0xf4, 0x95, + 0xf4, 0x95, 0xf5, 0xae, 0xf8, 0x20, 0x10, 0xf3, + 0x48, 0x16, 0x80, 0x06, 0x48, 0x08, 0xf8, 0x45, + 0x11, 0x16, 0x10, 0x04, 0x70, 0x02, 0x00, 0x17, + 0x80, 0x00, 0x76, 0x03, 0x00, 0x00, 0x10, 0x06, + 0x80, 0x01, 0x10, 0x05, 0xf0, 0x74, 0x0c, 0xb9, + 0x10, 0x06, 0x00, 0xe1, 0x00, 0x0c, 0x80, 0xe1, + 0x00, 0x0c, 0x11, 0x06, 0x10, 0x04, 0xf6, 0x00, + 0x80, 0x04, 0x48, 0x16, 0xf6, 0x20, 0x88, 0x16, + 0x10, 0xe1, 0x00, 0x0c, 0x08, 0xe1, 0x00, 0x0b, + 0xf8, 0x45, 0x11, 0x1c, 0xf0, 0x73, 0x11, 0x31, + 0xf2, 0x74, 0x0e, 0x9f, 0xf4, 0x95, 0x48, 0x17, + 0xf0, 0x73, 0x11, 0x33, 0x76, 0xe1, 0x00, 0x0c, + 0x00, 0x00, 0x76, 0xe1, 0x00, 0x0b, 0x00, 0x00, + 0x76, 0xe1, 0x00, 0x02, 0x00, 0x01, 0x10, 0x04, + 0x80, 0x00, 0x10, 0x05, 0xf0, 0x74, 0x06, 0x9f, + 0x88, 0x12, 0xf4, 0x95, 0x77, 0x10, 0x00, 0xff, + 0xf4, 0xaa, 0xf8, 0x30, 0x11, 0x33, 0x6c, 0x86, + 0x0f, 0x70, 0xee, 0x08, 0x8a, 0x17, 0x8a, 0x16, + 0x8a, 0x11, 0xfc, 0x00, 0x4a, 0x11, 0xee, 0xfc, + 0xf4, 0x95, 0x71, 0x06, 0x00, 0x12, 0x88, 0x11, + 0x73, 0x12, 0x00, 0x0e, 0xf1, 0x66, 0x00, 0x0d, + 0xf3, 0x00, 0x24, 0x00, 0x89, 0x14, 0x13, 0x81, + 0xf7, 0x7a, 0xf3, 0x30, 0x00, 0x01, 0x81, 0xf8, + 0x27, 0x60, 0x13, 0xe1, 0x00, 0x01, 0xf7, 0x7c, + 0xf3, 0x30, 0x00, 0x03, 0x81, 0xf8, 0x27, 0x61, + 0xe9, 0x0f, 0x19, 0xe1, 0x00, 0x01, 0x81, 0xf8, + 0x27, 0x62, 0x71, 0xe4, 0x00, 0x03, 0x00, 0x13, + 0xf6, 0xb8, 0x49, 0x13, 0xf3, 0x00, 0x00, 0x01, + 0xf3, 0x30, 0x00, 0x0f, 0x49, 0x0b, 0x09, 0xf8, + 0x27, 0x62, 0xf8, 0x4d, 0x11, 0x75, 0x77, 0x10, + 0x00, 0xff, 0xf4, 0xab, 0xf8, 0x30, 0x11, 0x75, + 0x57, 0xf8, 0x27, 0x6c, 0xf3, 0x00, 0x00, 0x01, + 0x4f, 0xf8, 0x27, 0x6c, 0x76, 0xf8, 0x27, 0x63, + 0x00, 0x01, 0xf0, 0x73, 0x11, 0x78, 0x76, 0xf8, + 0x27, 0x63, 0x00, 0x00, 0x70, 0xe4, 0x00, 0x03, + 0x27, 0x62, 0x76, 0xf8, 0x27, 0x64, 0x00, 0x00, + 0x11, 0xf8, 0x27, 0x61, 0x61, 0xf8, 0x00, 0x0b, + 0x00, 0x02, 0xf8, 0x20, 0x11, 0x8d, 0xe9, 0x01, + 0x6f, 0xe1, 0x00, 0x02, 0x0f, 0x18, 0x81, 0xf8, + 0x27, 0x64, 0x11, 0xf8, 0x27, 0x61, 0x61, 0xf8, + 0x00, 0x0b, 0x00, 0x01, 0xf8, 0x20, 0x11, 0xa9, + 0x10, 0xf8, 0x27, 0x64, 0xf1, 0x00, 0x00, 0x04, + 0x89, 0x13, 0xe9, 0xb8, 0xf5, 0x20, 0x81, 0xf8, + 0x27, 0x65, 0x60, 0x84, 0x00, 0x02, 0xf8, 0x20, + 0x11, 0xa9, 0x70, 0x00, 0x00, 0x11, 0x70, 0x01, + 0x00, 0x13, 0x70, 0x02, 0x27, 0x65, 0xf2, 0x74, + 0x0f, 0x18, 0xf4, 0x95, 0x48, 0x12, 0xee, 0x04, + 0x8a, 0x11, 0xfc, 0x00, 0x4a, 0x11, 0x4a, 0x16, + 0x4a, 0x17, 0xee, 0xfc, 0xe8, 0x00, 0x4e, 0xf8, + 0x27, 0x66, 0xe8, 0x00, 0x4e, 0xf8, 0x27, 0x68, + 0xe8, 0x00, 0x4e, 0xf8, 0x27, 0x6c, 0xe8, 0x00, + 0x4e, 0xf8, 0x27, 0x6a, 0x77, 0x12, 0x27, 0x40, + 0x77, 0x11, 0x24, 0x00, 0x77, 0x1a, 0x00, 0x1f, + 0xf0, 0x72, 0x11, 0xdb, 0x70, 0x92, 0x00, 0x11, + 0x76, 0xe1, 0x00, 0x01, 0xff, 0xff, 0x76, 0x81, + 0x00, 0x00, 0x76, 0xe1, 0x00, 0x02, 0x00, 0x00, + 0x76, 0xe1, 0x00, 0x03, 0x00, 0xff, 0x76, 0xe1, + 0x00, 0x0c, 0x00, 0x00, 0x76, 0xe1, 0x00, 0x0b, + 0x00, 0x00, 0x76, 0xe1, 0x00, 0x04, 0x00, 0x00, + 0x6d, 0xe9, 0x00, 0x0d, 0xf0, 0x20, 0x25, 0xa0, + 0xf1, 0x00, 0x00, 0x07, 0x89, 0x11, 0xf1, 0x00, + 0x00, 0x01, 0x81, 0x02, 0x88, 0x16, 0xf4, 0x95, + 0x77, 0x17, 0x00, 0x20, 0x76, 0x86, 0x00, 0xff, + 0x76, 0x00, 0x00, 0x00, 0x76, 0x01, 0x00, 0x06, + 0x10, 0x02, 0xf0, 0x74, 0x06, 0x6c, 0x76, 0x00, + 0x00, 0x00, 0x76, 0x01, 0x00, 0x06, 0xf2, 0x74, + 0x06, 0x6c, 0xf4, 0x95, 0x48, 0x11, 0x10, 0x02, + 0xf0, 0x00, 0x00, 0x0d, 0x80, 0x02, 0x6d, 0xe9, + 0x00, 0x0d, 0x6d, 0xee, 0x00, 0x0d, 0x6c, 0xef, + 0xff, 0xff, 0x11, 0xe8, 0xf0, 0x74, 0x0c, 0x9d, + 0xee, 0x04, 0x8a, 0x17, 0x8a, 0x16, 0x8a, 0x11, + 0xfc, 0x00, 0x4a, 0x11, 0x4a, 0x16, 0x4a, 0x17, + 0xee, 0xfa, 0x88, 0x11, 0x10, 0x0a, 0x49, 0x11, + 0xf8, 0x4d, 0x12, 0x9f, 0x48, 0x08, 0xf8, 0x45, + 0x12, 0x9f, 0x80, 0x04, 0x12, 0x81, 0xf5, 0x78, + 0x89, 0x12, 0xf4, 0x95, 0xf4, 0x95, 0x6c, 0xe2, + 0xff, 0xb9, 0x12, 0x8a, 0x61, 0xf8, 0x00, 0x08, + 0x00, 0x80, 0xf8, 0x30, 0x12, 0x8a, 0x13, 0xe1, + 0x00, 0x01, 0xf0, 0xe8, 0xf7, 0x78, 0xf1, 0xa0, + 0xf2, 0x30, 0x1f, 0xff, 0x88, 0x17, 0xf4, 0x95, + 0x77, 0x12, 0x24, 0x00, 0x77, 0x16, 0x00, 0x00, + 0x77, 0x13, 0x00, 0x20, 0xf6, 0xb8, 0x48, 0x17, + 0x08, 0xe2, 0x00, 0x01, 0xf8, 0x45, 0x12, 0x42, + 0x6d, 0xea, 0x00, 0x0d, 0x6d, 0x96, 0x6c, 0xeb, + 0xff, 0xff, 0x12, 0x34, 0xf0, 0x73, 0x12, 0x90, + 0x56, 0xf8, 0x27, 0x6a, 0xf0, 0x00, 0x00, 0x01, + 0x4e, 0xf8, 0x27, 0x6a, 0x60, 0x82, 0x00, 0x01, + 0xf8, 0x30, 0x12, 0x54, 0x70, 0x00, 0x00, 0x16, + 0xf2, 0x74, 0x11, 0x38, 0xf4, 0x95, 0x48, 0x11, + 0xf0, 0x73, 0x12, 0x90, 0x70, 0x00, 0x00, 0x16, + 0xf2, 0x74, 0x11, 0x38, 0xf4, 0x95, 0x48, 0x11, + 0x72, 0x10, 0x2a, 0x9e, 0xf4, 0x95, 0xf4, 0xaf, + 0xf8, 0x30, 0x12, 0x6e, 0x76, 0x00, 0x00, 0x00, + 0x76, 0x01, 0x00, 0xbc, 0x70, 0x02, 0x00, 0x16, + 0x76, 0x03, 0x00, 0x00, 0xf2, 0x74, 0x0c, 0xb9, + 0xf4, 0x95, 0x48, 0x11, 0xf0, 0x73, 0x12, 0x90, + 0x10, 0xf8, 0x27, 0x6e, 0xf8, 0x44, 0x12, 0x90, + 0x76, 0x00, 0x00, 0x00, 0x76, 0x01, 0x00, 0xbc, + 0x70, 0x02, 0x00, 0x16, 0x76, 0x03, 0x00, 0x00, + 0xf2, 0x74, 0x0c, 0xb9, 0xf4, 0x95, 0x48, 0x11, + 0xf0, 0x74, 0x0c, 0x5e, 0xf0, 0xe0, 0xf0, 0x10, + 0x13, 0x88, 0xf8, 0x42, 0x12, 0x90, 0x76, 0xf8, + 0x27, 0x6e, 0x00, 0x01, 0xf0, 0x73, 0x12, 0x90, + 0x56, 0xf8, 0x27, 0x66, 0xf0, 0x00, 0x00, 0x01, + 0x4e, 0xf8, 0x27, 0x66, 0x6d, 0xe9, 0x00, 0x5e, + 0x56, 0xf8, 0x27, 0x68, 0xf0, 0x00, 0x00, 0x01, + 0x4e, 0xf8, 0x27, 0x68, 0x71, 0x04, 0x00, 0x12, + 0x6e, 0xea, 0xff, 0xff, 0x12, 0x18, 0x70, 0x04, + 0x00, 0x12, 0xee, 0x06, 0x8a, 0x17, 0x8a, 0x16, + 0x8a, 0x11, 0xfc, 0x00, 0x4a, 0x11, 0xee, 0xfe, + 0x88, 0x0e, 0xf4, 0x95, 0xf0, 0x66, 0x00, 0x0d, + 0xf0, 0x00, 0x25, 0xa0, 0x88, 0x11, 0xf4, 0x95, + 0xf4, 0x95, 0x76, 0x81, 0x00, 0xff, 0x76, 0x00, + 0x00, 0x00, 0x76, 0x01, 0x00, 0x06, 0xf2, 0x74, + 0x06, 0x6c, 0xf0, 0x00, 0x00, 0x01, 0x76, 0x00, + 0x00, 0x00, 0x76, 0x01, 0x00, 0x06, 0x48, 0x11, + 0xf2, 0x74, 0x06, 0x6c, 0xf0, 0x00, 0x00, 0x07, + 0xee, 0x02, 0x8a, 0x11, 0xfc, 0x00, 0x4a, 0x11, + 0x88, 0x0e, 0xf4, 0x95, 0xf0, 0x66, 0x00, 0x0d, + 0xf0, 0x00, 0x24, 0x00, 0x88, 0x11, 0xf4, 0x95, + 0xf4, 0x95, 0x76, 0xe1, 0x00, 0x01, 0xff, 0xff, + 0x76, 0x81, 0x00, 0x00, 0x76, 0xe1, 0x00, 0x02, + 0x00, 0x00, 0x76, 0xe1, 0x00, 0x03, 0x00, 0xff, + 0x8a, 0x11, 0xfc, 0x00, 0x4a, 0x11, 0xf4, 0x95, + 0x13, 0x03, 0x88, 0x11, 0xfa, 0x4d, 0x12, 0xec, + 0x71, 0x02, 0x00, 0x12, 0xf3, 0x10, 0x00, 0x01, + 0x89, 0x1a, 0xf4, 0x95, 0xf0, 0x72, 0x12, 0xeb, + 0x70, 0x91, 0x00, 0x12, 0x8a, 0x11, 0xfc, 0x00, + 0xf4, 0x95, 0x4a, 0x0b, 0x4a, 0x0c, 0x4a, 0x0d, + 0xf7, 0xb8, 0xee, 0xfe, 0x10, 0xf8, 0x00, 0x08, + 0x11, 0x06, 0xf1, 0xc0, 0x83, 0x00, 0xf4, 0x85, + 0x11, 0x06, 0xf7, 0x85, 0x81, 0x06, 0xf6, 0xb8, + 0xec, 0x0f, 0x1e, 0x06, 0x61, 0x00, 0x80, 0x00, + 0xf8, 0x20, 0x13, 0x05, 0xf4, 0x84, 0xee, 0x02, + 0x8a, 0x0d, 0x8a, 0x0c, 0x8a, 0x0b, 0xfc, 0x00, + 0xf4, 0x95, 0x4a, 0x0b, 0x4a, 0x0c, 0x4a, 0x0d, + 0xee, 0xfe, 0xf7, 0xb8, 0x80, 0x00, 0x10, 0xf8, + 0x00, 0x08, 0xf4, 0x85, 0x11, 0x06, 0xf7, 0x85, + 0x81, 0x06, 0xf6, 0xb8, 0xec, 0x0f, 0x1e, 0x06, + 0xf0, 0xf0, 0x61, 0x00, 0x80, 0x00, 0xf8, 0x20, + 0x13, 0x20, 0xf4, 0x84, 0xee, 0x02, 0x8a, 0x0d, + 0x8a, 0x0c, 0x8a, 0x0b, 0xfc, 0x00, 0x4a, 0x11, + 0x77, 0x11, 0x00, 0x7b, 0x76, 0x81, 0x2e, 0xec, + 0x77, 0x11, 0x00, 0x7b, 0xee, 0xff, 0x71, 0x81, + 0x00, 0x11, 0xee, 0x01, 0x76, 0xe1, 0x00, 0x01, + 0x00, 0x00, 0x76, 0xe1, 0x00, 0x04, 0x00, 0x00, + 0x76, 0xe1, 0x00, 0x06, 0x00, 0x00, 0x76, 0xe1, + 0x00, 0x62, 0x00, 0x00, 0x76, 0xe1, 0x00, 0x76, + 0x00, 0x00, 0x76, 0xe1, 0x00, 0x92, 0x00, 0x00, + 0x76, 0xe1, 0x00, 0x94, 0x00, 0x00, 0x76, 0xe1, + 0x00, 0xb0, 0x00, 0x00, 0x76, 0xe1, 0x00, 0xb3, + 0x00, 0x00, 0x76, 0xe1, 0x00, 0xbe, 0x00, 0x00, + 0x76, 0xe1, 0x00, 0xbf, 0x00, 0x00, 0x76, 0xe1, + 0x00, 0xc1, 0x00, 0x00, 0x76, 0xe1, 0x00, 0xc3, + 0x00, 0x00, 0x76, 0xe1, 0x00, 0xc5, 0x00, 0x00, + 0x76, 0xe1, 0x00, 0xc7, 0x00, 0x00, 0x76, 0x81, + 0x00, 0x00, 0x8a, 0x11, 0xf4, 0x95, 0xf4, 0xe4, + 0x4a, 0x11, 0x4a, 0x16, 0x4a, 0x17, 0xee, 0xff, + 0xf4, 0x95, 0x71, 0x06, 0x00, 0x16, 0xfb, 0x80, + 0x16, 0xa2, 0x88, 0x17, 0xf4, 0x95, 0xf7, 0xb8, + 0x10, 0xf8, 0x00, 0x17, 0xf0, 0x10, 0x00, 0x02, + 0xfa, 0x46, 0x13, 0x88, 0x77, 0x11, 0x00, 0x00, + 0x10, 0xf8, 0x00, 0x17, 0xf0, 0x10, 0x00, 0x02, + 0xf8, 0x45, 0x13, 0xf9, 0x10, 0xf8, 0x00, 0x17, + 0xf8, 0x45, 0x14, 0x39, 0x10, 0xf8, 0x00, 0x17, + 0xf0, 0x10, 0x00, 0x01, 0xf8, 0x45, 0x14, 0x1f, + 0xf0, 0x73, 0x14, 0x52, 0x10, 0xf8, 0x00, 0x17, + 0xf0, 0x10, 0x00, 0x03, 0xf8, 0x45, 0x13, 0xd3, + 0x10, 0xf8, 0x00, 0x17, 0xf0, 0x10, 0x00, 0x06, + 0xf8, 0x44, 0x14, 0x52, 0x77, 0x12, 0x00, 0x7b, + 0x71, 0x82, 0x00, 0x14, 0x61, 0xe4, 0x00, 0x07, + 0x00, 0x40, 0xf8, 0x30, 0x14, 0x52, 0x49, 0x14, + 0x48, 0x17, 0xf6, 0x00, 0x88, 0x12, 0xf4, 0x95, + 0x77, 0x13, 0x00, 0x55, 0x77, 0x11, 0x00, 0x57, + 0x6d, 0xea, 0x00, 0x3b, 0xe5, 0x01, 0x10, 0xe6, + 0x00, 0x06, 0x80, 0x81, 0x48, 0x14, 0x00, 0xf8, + 0x00, 0x17, 0x88, 0x12, 0xf4, 0x95, 0x77, 0x11, + 0x00, 0x55, 0x10, 0xe2, 0x00, 0x40, 0x80, 0x81, + 0x77, 0x11, 0x00, 0x57, 0x10, 0xe6, 0x00, 0x07, + 0x80, 0x81, 0x77, 0x11, 0x00, 0x55, 0x10, 0xe2, + 0x00, 0x45, 0x80, 0x81, 0x10, 0xe6, 0x00, 0x08, + 0x77, 0x11, 0x00, 0x57, 0x80, 0x81, 0x77, 0x11, + 0x00, 0x55, 0x10, 0xe2, 0x00, 0x4a, 0x80, 0x81, + 0x77, 0x11, 0x00, 0x57, 0x10, 0xe6, 0x00, 0x09, + 0x80, 0x81, 0xf2, 0x73, 0x14, 0x52, 0x77, 0x11, + 0x03, 0xc0, 0x77, 0x12, 0x00, 0x7b, 0x10, 0x82, + 0xf0, 0x00, 0x00, 0x07, 0x88, 0x13, 0xf4, 0x95, + 0xf4, 0x95, 0x96, 0x1b, 0xf8, 0x30, 0x14, 0x52, + 0x10, 0xe3, 0x00, 0x35, 0x77, 0x12, 0x00, 0x55, + 0x80, 0x82, 0x77, 0x12, 0x00, 0x57, 0x10, 0xe6, + 0x00, 0x04, 0x80, 0x82, 0x77, 0x12, 0x00, 0x55, + 0x10, 0xe3, 0x00, 0x37, 0x80, 0x82, 0x77, 0x12, + 0x00, 0x57, 0x10, 0xe6, 0x00, 0x05, 0x80, 0x82, + 0x48, 0x11, 0xf0, 0x40, 0x00, 0x10, 0xf2, 0x73, + 0x14, 0x50, 0xf0, 0x40, 0x00, 0x20, 0x77, 0x12, + 0x00, 0x7b, 0x10, 0x82, 0xf0, 0x00, 0x00, 0x07, + 0x88, 0x12, 0xf4, 0x95, 0xf4, 0x95, 0x96, 0x0d, + 0xf8, 0x30, 0x14, 0x52, 0x10, 0xe2, 0x00, 0x34, + 0x77, 0x13, 0x00, 0x55, 0x80, 0x83, 0x77, 0x13, + 0x00, 0x57, 0x10, 0xe6, 0x00, 0x02, 0x80, 0x83, + 0x10, 0xe2, 0x00, 0x36, 0x77, 0x12, 0x00, 0x55, + 0x80, 0x82, 0x77, 0x12, 0x00, 0x57, 0x10, 0xe6, + 0x00, 0x03, 0x80, 0x82, 0x48, 0x11, 0xf0, 0x40, + 0x00, 0x04, 0xf2, 0x73, 0x14, 0x50, 0xf0, 0x40, + 0x00, 0x08, 0x77, 0x12, 0x00, 0x7b, 0x10, 0x82, + 0xf0, 0x00, 0x00, 0x07, 0x88, 0x12, 0xf4, 0x95, + 0xf4, 0x95, 0x96, 0x0e, 0xf8, 0x30, 0x14, 0x52, + 0x10, 0xe2, 0x00, 0x33, 0x77, 0x12, 0x00, 0x55, + 0x80, 0x82, 0x77, 0x12, 0x00, 0x57, 0x10, 0xe6, + 0x00, 0x01, 0x80, 0x82, 0x48, 0x11, 0xf2, 0x73, + 0x14, 0x50, 0xf0, 0x40, 0x00, 0x02, 0x77, 0x12, + 0x00, 0x7b, 0x10, 0x82, 0xf0, 0x00, 0x00, 0x07, + 0x88, 0x12, 0xf4, 0x95, 0xf4, 0x95, 0x96, 0x0f, + 0xf8, 0x30, 0x14, 0x52, 0x10, 0xe2, 0x00, 0x32, + 0x77, 0x12, 0x00, 0x55, 0x77, 0x13, 0x00, 0x57, + 0x80, 0x82, 0x48, 0x11, 0xe7, 0x62, 0xf0, 0x40, + 0x00, 0x01, 0xe5, 0x01, 0x88, 0x11, 0xf4, 0x95, + 0x77, 0x12, 0x00, 0x7b, 0x48, 0x11, 0x71, 0x82, + 0x00, 0x12, 0x1a, 0xe2, 0x00, 0x07, 0x80, 0xe2, + 0x00, 0x07, 0xf9, 0x80, 0x16, 0x9a, 0xee, 0x01, + 0x8a, 0x17, 0x48, 0x11, 0x8a, 0x16, 0x8a, 0x11, + 0xf4, 0xe4, 0x4a, 0x11, 0x88, 0x11, 0x77, 0x0e, + 0x00, 0x05, 0x77, 0x12, 0x00, 0x55, 0xe8, 0x04, + 0xf6, 0xb8, 0x28, 0xe1, 0x00, 0x02, 0xee, 0xff, + 0x80, 0x82, 0x77, 0x12, 0x00, 0x57, 0xf0, 0x20, + 0x80, 0x00, 0xee, 0x01, 0x1a, 0x82, 0x77, 0x12, + 0x00, 0x57, 0x80, 0x82, 0xe8, 0x01, 0x32, 0xe1, + 0x00, 0x02, 0xf5, 0x82, 0x77, 0x11, 0x00, 0x54, + 0xf6, 0x93, 0x18, 0x81, 0x77, 0x11, 0x00, 0x54, + 0xf2, 0xa0, 0x80, 0x81, 0x8a, 0x11, 0xf4, 0x95, + 0xf4, 0xe4, 0x4a, 0x11, 0x4a, 0x16, 0xf4, 0x95, + 0x71, 0x04, 0x00, 0x11, 0xfb, 0x80, 0x16, 0xa2, + 0x88, 0x16, 0xf4, 0x95, 0x77, 0x12, 0x00, 0x55, + 0x10, 0xe6, 0x00, 0x03, 0x80, 0x82, 0x77, 0x12, + 0x00, 0x56, 0x10, 0xe1, 0x00, 0x02, 0x77, 0x13, + 0x00, 0x56, 0x80, 0x82, 0x77, 0x12, 0x00, 0x56, + 0x10, 0xe1, 0x00, 0x03, 0x80, 0x82, 0x10, 0xe1, + 0x00, 0x04, 0x77, 0x12, 0x00, 0x56, 0x80, 0x82, + 0x77, 0x12, 0x00, 0x56, 0x10, 0xe1, 0x00, 0x01, + 0x80, 0x82, 0xe7, 0x12, 0xe5, 0x01, 0xf9, 0x80, + 0x16, 0x9a, 0x8a, 0x16, 0x8a, 0x11, 0xf4, 0xe4, + 0x4a, 0x11, 0x4a, 0x16, 0x4a, 0x17, 0xee, 0xf9, + 0x77, 0x11, 0x00, 0x7b, 0x76, 0x00, 0x00, 0x16, + 0x76, 0x01, 0x00, 0x17, 0x76, 0x02, 0x00, 0x1a, + 0x76, 0x03, 0x00, 0x1b, 0x76, 0x04, 0x00, 0x1c, + 0x76, 0x05, 0x00, 0x1d, 0x71, 0x81, 0x00, 0x17, + 0x71, 0xe7, 0x00, 0x06, 0x00, 0x11, 0x10, 0x81, + 0xf8, 0x44, 0x14, 0xdf, 0xf9, 0x80, 0x16, 0x53, + 0xf6, 0xb8, 0xfb, 0x80, 0x15, 0x85, 0xf0, 0x20, + 0xff, 0xff, 0xf6, 0xb8, 0xfb, 0x80, 0x16, 0x08, + 0xf0, 0x20, 0xff, 0xff, 0x77, 0x11, 0x00, 0x7b, + 0x71, 0x81, 0x00, 0x17, 0x76, 0xe7, 0x00, 0x06, + 0x00, 0x01, 0x48, 0x17, 0x77, 0x16, 0x00, 0x00, + 0x77, 0x10, 0x00, 0x04, 0x77, 0x15, 0x00, 0x03, + 0x77, 0x14, 0x00, 0x02, 0x77, 0x13, 0x00, 0x01, + 0xf0, 0x00, 0x00, 0x39, 0x76, 0xe7, 0x00, 0x08, + 0x00, 0x1f, 0x76, 0xe7, 0x00, 0x07, 0x00, 0x00, + 0x88, 0x0e, 0x77, 0x1a, 0x00, 0x05, 0x48, 0x17, + 0xf0, 0x00, 0x00, 0x09, 0x88, 0x12, 0x48, 0x18, + 0x88, 0x19, 0xe8, 0x00, 0xf0, 0x72, 0x15, 0x2c, + 0x73, 0x19, 0x00, 0x11, 0x76, 0x82, 0x00, 0x00, + 0x11, 0x91, 0x73, 0x11, 0x00, 0x19, 0x70, 0xe2, + 0x00, 0x03, 0x00, 0x16, 0x70, 0xe2, 0x00, 0x04, + 0x00, 0x13, 0x70, 0xe2, 0x00, 0x05, 0x00, 0x14, + 0x81, 0xe2, 0x00, 0x01, 0x70, 0xe2, 0x00, 0x06, + 0x00, 0x15, 0x70, 0xe2, 0x00, 0x07, 0x00, 0x10, + 0x80, 0xe2, 0x00, 0x02, 0x73, 0x0e, 0x00, 0x11, + 0xf1, 0x00, 0x00, 0x1e, 0x6d, 0xee, 0x00, 0x05, + 0x6d, 0xeb, 0x00, 0x05, 0x6d, 0xec, 0x00, 0x05, + 0x6d, 0xed, 0x00, 0x05, 0x6d, 0xe8, 0x00, 0x05, + 0xf0, 0x00, 0x00, 0x01, 0x81, 0x91, 0x6d, 0xea, + 0x00, 0x08, 0x73, 0x11, 0x00, 0x0e, 0xee, 0x07, + 0x76, 0xe7, 0x00, 0x41, 0x00, 0x24, 0x76, 0xe7, + 0x00, 0x46, 0x00, 0x25, 0x76, 0xe7, 0x00, 0x4b, + 0x00, 0x26, 0x76, 0xe7, 0x00, 0x50, 0x00, 0x27, + 0x8a, 0x17, 0x8a, 0x16, 0x8a, 0x11, 0xf4, 0xe4, + 0x4a, 0x11, 0x4a, 0x16, 0xee, 0xfe, 0x88, 0x11, + 0x56, 0x06, 0x4e, 0x00, 0xf9, 0x80, 0x16, 0xa2, + 0xf7, 0xb8, 0x10, 0xf8, 0x00, 0x11, 0xf0, 0x10, + 0xff, 0xff, 0xfa, 0x45, 0x15, 0x60, 0x77, 0x16, + 0xff, 0xff, 0x77, 0x12, 0x00, 0x7b, 0x49, 0x11, + 0x10, 0x82, 0xf6, 0x03, 0xf0, 0x00, 0x00, 0x09, + 0x88, 0x11, 0xf4, 0x95, 0xf4, 0x95, 0x10, 0x81, + 0xf8, 0x44, 0x15, 0x71, 0xf2, 0x73, 0x15, 0x71, + 0xf4, 0x95, 0xe7, 0x16, 0x77, 0x11, 0x00, 0x7b, + 0x10, 0x81, 0xf0, 0x00, 0x00, 0x09, 0x88, 0x11, + 0xf4, 0x95, 0x77, 0x12, 0x00, 0x06, 0x10, 0x81, + 0xf8, 0x45, 0x15, 0x5c, 0x6e, 0xea, 0xff, 0xff, + 0x15, 0x69, 0x6d, 0xe9, 0x00, 0x08, 0x76, 0x86, + 0x00, 0x01, 0xe9, 0x01, 0x56, 0x00, 0xf1, 0x80, + 0x10, 0xf8, 0x00, 0x0b, 0xf8, 0x45, 0x15, 0x7e, + 0xfb, 0x80, 0x15, 0x85, 0xf4, 0x95, 0x48, 0x16, + 0xf9, 0x80, 0x16, 0x9a, 0xee, 0x02, 0x48, 0x16, + 0x8a, 0x16, 0x8a, 0x11, 0xf4, 0xe4, 0x4a, 0x11, + 0xee, 0xff, 0xfb, 0x80, 0x16, 0xa2, 0x88, 0x11, + 0xf4, 0x95, 0x77, 0x10, 0xff, 0xff, 0xf4, 0xa9, + 0xf8, 0x30, 0x15, 0xc4, 0x10, 0xe1, 0x00, 0x03, + 0x77, 0x12, 0x00, 0x55, 0x80, 0x82, 0x77, 0x12, + 0x00, 0x56, 0x76, 0x82, 0x00, 0x00, 0x77, 0x12, + 0x00, 0x56, 0x76, 0x82, 0x00, 0x00, 0x77, 0x12, + 0x00, 0x56, 0x76, 0x82, 0x00, 0x00, 0x77, 0x12, + 0x00, 0x56, 0x76, 0x82, 0x00, 0x00, 0x77, 0x12, + 0x00, 0x56, 0x76, 0x82, 0x00, 0x00, 0x10, 0xe1, + 0x00, 0x02, 0xf0, 0x00, 0x00, 0x08, 0x32, 0xf8, + 0x00, 0x08, 0x77, 0x12, 0x00, 0x54, 0xe8, 0x01, + 0xf4, 0x82, 0xf4, 0x93, 0x18, 0x82, 0x77, 0x12, + 0x00, 0x54, 0xf0, 0x40, 0x00, 0x00, 0x80, 0x82, + 0x10, 0xe1, 0x00, 0x01, 0xf9, 0x80, 0x16, 0x76, + 0x10, 0xe1, 0x00, 0x01, 0xf9, 0x80, 0x16, 0x66, + 0xf0, 0x73, 0x16, 0x03, 0x77, 0x11, 0x00, 0x7b, + 0x71, 0x81, 0x00, 0x11, 0x71, 0xe1, 0x00, 0x07, + 0x00, 0x12, 0x76, 0x82, 0x00, 0x00, 0x10, 0xe1, + 0x00, 0x09, 0xf9, 0x80, 0x15, 0x85, 0x77, 0x11, + 0x00, 0x7b, 0x71, 0x81, 0x00, 0x11, 0x10, 0xe1, + 0x00, 0x09, 0xfb, 0x80, 0x15, 0x85, 0xf0, 0x00, + 0x00, 0x08, 0x77, 0x11, 0x00, 0x7b, 0x71, 0x81, + 0x00, 0x11, 0x10, 0xe1, 0x00, 0x09, 0xfb, 0x80, + 0x15, 0x85, 0xf0, 0x00, 0x00, 0x10, 0x77, 0x11, + 0x00, 0x7b, 0x71, 0x81, 0x00, 0x11, 0x10, 0xe1, + 0x00, 0x09, 0xfb, 0x80, 0x15, 0x85, 0xf0, 0x00, + 0x00, 0x18, 0x77, 0x11, 0x00, 0x7b, 0x71, 0x81, + 0x00, 0x11, 0x10, 0xe1, 0x00, 0x09, 0xfb, 0x80, + 0x15, 0x85, 0xf0, 0x00, 0x00, 0x20, 0x77, 0x11, + 0x00, 0x7b, 0x71, 0x81, 0x00, 0x11, 0x10, 0xe1, + 0x00, 0x09, 0xfb, 0x80, 0x15, 0x85, 0xf0, 0x00, + 0x00, 0x28, 0xf9, 0x80, 0x16, 0x9a, 0xee, 0x01, + 0x8a, 0x11, 0xf4, 0xe4, 0x4a, 0x11, 0xee, 0xff, + 0xfb, 0x80, 0x16, 0xa2, 0x88, 0x11, 0xf4, 0x95, + 0x77, 0x10, 0xff, 0xff, 0xf4, 0xa9, 0xf8, 0x30, + 0x16, 0x41, 0x77, 0x11, 0x00, 0x55, 0x76, 0x81, + 0x00, 0x1e, 0x77, 0x11, 0x00, 0x56, 0x76, 0x81, + 0x00, 0x00, 0x77, 0x11, 0x00, 0x56, 0x76, 0x81, + 0x00, 0x00, 0x77, 0x11, 0x00, 0x56, 0x76, 0x81, + 0x00, 0x00, 0x77, 0x11, 0x00, 0x56, 0x76, 0x81, + 0x00, 0x00, 0x77, 0x11, 0x00, 0x56, 0x76, 0x81, + 0x00, 0x00, 0x77, 0x11, 0x00, 0x56, 0x76, 0x81, + 0x00, 0x00, 0x77, 0x11, 0x00, 0x56, 0x76, 0x81, + 0x00, 0x00, 0x77, 0x11, 0x00, 0x56, 0x76, 0x81, + 0x00, 0x00, 0x77, 0x11, 0x00, 0x56, 0x76, 0x81, + 0x00, 0x00, 0x77, 0x11, 0x00, 0x56, 0xf2, 0x73, + 0x16, 0x4e, 0x76, 0x81, 0x00, 0x00, 0x77, 0x11, + 0x00, 0x7b, 0x71, 0x81, 0x00, 0x11, 0x71, 0xe1, + 0x00, 0x07, 0x00, 0x12, 0x76, 0x82, 0x00, 0x00, + 0x10, 0xe1, 0x00, 0x39, 0xf9, 0x80, 0x16, 0x08, + 0xf9, 0x80, 0x16, 0x9a, 0xee, 0x01, 0x8a, 0x11, + 0xf4, 0xe4, 0x4a, 0x11, 0x77, 0x11, 0x00, 0x7b, + 0x10, 0x81, 0xf0, 0x00, 0x00, 0x04, 0x88, 0x11, + 0xf4, 0x95, 0xf4, 0x95, 0x10, 0x81, 0xfa, 0x44, + 0x16, 0x63, 0xf4, 0x95, 0xee, 0xff, 0x76, 0x81, + 0x00, 0x01, 0xee, 0x01, 0x8a, 0x11, 0xf4, 0xe4, + 0xf0, 0x10, 0x00, 0x10, 0x4a, 0x11, 0x32, 0xf8, + 0x00, 0x08, 0xee, 0xff, 0x77, 0x11, 0x00, 0x01, + 0xe8, 0x01, 0xee, 0x01, 0xf4, 0x82, 0x1a, 0x81, + 0x80, 0x81, 0x8a, 0x11, 0xf4, 0x95, 0xf4, 0xe4, + 0xf0, 0x10, 0x00, 0x10, 0x4a, 0x11, 0x32, 0xf8, + 0x00, 0x08, 0xee, 0xff, 0xe8, 0x01, 0x77, 0x11, + 0x00, 0x00, 0xf4, 0x82, 0xee, 0x01, 0xf4, 0x93, + 0x18, 0x81, 0x80, 0x81, 0x8a, 0x11, 0xf4, 0x95, + 0xf4, 0xe4, 0x4a, 0x11, 0xf0, 0x10, 0x00, 0x10, + 0x77, 0x11, 0x00, 0x00, 0x32, 0xf8, 0x00, 0x08, + 0xee, 0xff, 0x11, 0x81, 0xe8, 0x01, 0xee, 0x01, + 0x77, 0x11, 0x00, 0x00, 0xf4, 0x82, 0xf2, 0xa0, + 0x80, 0x81, 0x8a, 0x11, 0xf4, 0x95, 0xf4, 0xe4, + 0xf2, 0x73, 0x16, 0x9e, 0xf6, 0xbb, 0xf4, 0x95, + 0xf4, 0x95, 0xf4, 0x95, 0xf4, 0x95, 0xf4, 0xe4, + 0xf2, 0x73, 0x16, 0xa6, 0xf7, 0xbb, 0xf4, 0x95, + 0xf4, 0x95, 0xf4, 0x95, 0xf4, 0x95, 0xf4, 0xe4, + 0x4a, 0x11, 0x4a, 0x16, 0xf4, 0x95, 0x71, 0x04, + 0x00, 0x16, 0xfb, 0x80, 0x16, 0xa2, 0x88, 0x11, + 0xf4, 0x95, 0x71, 0xe1, 0x00, 0x05, 0x00, 0x12, + 0x76, 0x82, 0x00, 0x0e, 0x10, 0xe6, 0x00, 0x0e, + 0x71, 0xe1, 0x00, 0x06, 0x00, 0x12, 0x80, 0x82, + 0x71, 0xe1, 0x00, 0x05, 0x00, 0x12, 0x76, 0x82, + 0x00, 0x0d, 0x71, 0xe1, 0x00, 0x06, 0x00, 0x12, + 0x10, 0xe6, 0x00, 0x0d, 0x80, 0x82, 0x71, 0xe1, + 0x00, 0x05, 0x00, 0x12, 0x76, 0x82, 0x00, 0x0c, + 0x10, 0xe6, 0x00, 0x0c, 0x71, 0xe1, 0x00, 0x06, + 0x00, 0x12, 0x80, 0x82, 0x71, 0xe1, 0x00, 0x05, + 0x00, 0x12, 0x76, 0x82, 0x00, 0x0b, 0x10, 0xe6, + 0x00, 0x0b, 0x71, 0xe1, 0x00, 0x06, 0x00, 0x12, + 0x80, 0x82, 0x71, 0xe1, 0x00, 0x05, 0x00, 0x12, + 0x76, 0x82, 0x00, 0x0a, 0x71, 0xe1, 0x00, 0x06, + 0x00, 0x12, 0x10, 0xe6, 0x00, 0x0a, 0x80, 0x82, + 0x71, 0xe1, 0x00, 0x05, 0x00, 0x12, 0x76, 0x82, + 0x00, 0x09, 0x10, 0xe6, 0x00, 0x09, 0x71, 0xe1, + 0x00, 0x06, 0x00, 0x12, 0x80, 0x82, 0x71, 0xe1, + 0x00, 0x05, 0x00, 0x12, 0x76, 0x82, 0x00, 0x08, + 0x71, 0xe1, 0x00, 0x06, 0x00, 0x12, 0x10, 0xe6, + 0x00, 0x08, 0x80, 0x82, 0x71, 0xe1, 0x00, 0x05, + 0x00, 0x12, 0x76, 0x82, 0x00, 0x07, 0x10, 0xe6, + 0x00, 0x07, 0x71, 0xe1, 0x00, 0x06, 0x00, 0x12, + 0x80, 0x82, 0x71, 0xe1, 0x00, 0x05, 0x00, 0x12, + 0x76, 0x82, 0x00, 0x06, 0x71, 0xe1, 0x00, 0x06, + 0x00, 0x12, 0x10, 0xe6, 0x00, 0x06, 0x80, 0x82, + 0x71, 0xe1, 0x00, 0x05, 0x00, 0x12, 0x76, 0x82, + 0x00, 0x05, 0x71, 0xe1, 0x00, 0x06, 0x00, 0x12, + 0x10, 0xe6, 0x00, 0x05, 0x80, 0x82, 0x71, 0xe1, + 0x00, 0x05, 0x00, 0x12, 0x76, 0x82, 0x00, 0x04, + 0x71, 0xe1, 0x00, 0x06, 0x00, 0x12, 0x10, 0xe6, + 0x00, 0x04, 0x80, 0x82, 0x71, 0xe1, 0x00, 0x05, + 0x00, 0x12, 0x76, 0x82, 0x00, 0x03, 0x71, 0xe1, + 0x00, 0x06, 0x00, 0x12, 0x10, 0xe6, 0x00, 0x03, + 0x80, 0x82, 0x71, 0xe1, 0x00, 0x05, 0x00, 0x12, + 0x76, 0x82, 0x00, 0x02, 0x10, 0xe6, 0x00, 0x02, + 0x71, 0xe1, 0x00, 0x06, 0x00, 0x12, 0x80, 0x82, + 0x71, 0xe1, 0x00, 0x05, 0x00, 0x12, 0x76, 0x82, + 0x00, 0x01, 0x10, 0xe6, 0x00, 0x01, 0x71, 0xe1, + 0x00, 0x06, 0x00, 0x12, 0x80, 0x82, 0x71, 0xe1, + 0x00, 0x05, 0x00, 0x12, 0x76, 0x82, 0x00, 0x00, + 0x71, 0xe1, 0x00, 0x06, 0x00, 0x13, 0xe7, 0x62, + 0xe5, 0x01, 0xf9, 0x80, 0x16, 0x9a, 0x8a, 0x16, + 0x8a, 0x11, 0xf4, 0xe4, 0x4a, 0x11, 0x88, 0x11, + 0xf4, 0x95, 0xf4, 0x95, 0x71, 0xe1, 0x00, 0x05, + 0x00, 0x12, 0xee, 0xff, 0x76, 0x82, 0x00, 0x00, + 0xee, 0x01, 0x71, 0xe1, 0x00, 0x06, 0x00, 0x11, + 0x69, 0x81, 0x00, 0x01, 0x8a, 0x11, 0xf4, 0x95, + 0xf4, 0xe4, 0x4a, 0x11, 0x88, 0x11, 0xf4, 0x95, + 0xf4, 0x95, 0x71, 0xe1, 0x00, 0x05, 0x00, 0x12, + 0xee, 0xff, 0x76, 0x82, 0x00, 0x01, 0xee, 0x01, + 0x71, 0xe1, 0x00, 0x06, 0x00, 0x11, 0x69, 0x81, + 0x00, 0x01, 0x8a, 0x11, 0xf4, 0x95, 0xf4, 0xe4, + 0x4a, 0x11, 0x77, 0x11, 0x00, 0x7b, 0x10, 0x81, + 0xf0, 0x00, 0x00, 0x94, 0x88, 0x11, 0xf4, 0x95, + 0xf4, 0x95, 0x10, 0x81, 0xfa, 0x44, 0x17, 0x9c, + 0xf4, 0x95, 0xee, 0xff, 0xf9, 0x80, 0x16, 0x53, + 0x77, 0x11, 0x00, 0x7b, 0x10, 0x81, 0xf0, 0x00, + 0x00, 0x94, 0x88, 0x11, 0xf4, 0x95, 0xf4, 0x95, + 0x76, 0x81, 0x00, 0x01, 0xee, 0x01, 0x76, 0xe1, + 0x00, 0x01, 0x00, 0x00, 0x76, 0xe1, 0x00, 0x02, + 0x00, 0x21, 0x76, 0xe1, 0x00, 0x03, 0x00, 0x20, + 0x76, 0xe1, 0x00, 0x04, 0x00, 0x23, 0x76, 0xe1, + 0x00, 0x05, 0x00, 0x22, 0x76, 0xe1, 0x00, 0x06, + 0x00, 0x38, 0x76, 0xe1, 0x00, 0x07, 0x00, 0x39, + 0x76, 0xe1, 0x00, 0x08, 0x00, 0x15, 0x76, 0xe1, + 0x00, 0x09, 0x00, 0x14, 0x76, 0xe1, 0x00, 0x0a, + 0x00, 0x00, 0x76, 0xe1, 0x00, 0x0b, 0x00, 0x41, + 0x76, 0xe1, 0x00, 0x0c, 0x00, 0x40, 0x76, 0xe1, + 0x00, 0x0d, 0x00, 0x43, 0x76, 0xe1, 0x00, 0x0e, + 0x00, 0x42, 0x76, 0xe1, 0x00, 0x0f, 0x00, 0x48, + 0x76, 0xe1, 0x00, 0x10, 0x00, 0x49, 0x76, 0xe1, + 0x00, 0x11, 0x00, 0x1b, 0x76, 0xe1, 0x00, 0x12, + 0x00, 0x1a, 0x8a, 0x11, 0xf4, 0x95, 0xf4, 0xe4, + 0x4a, 0x11, 0xee, 0xfd, 0x88, 0x11, 0x56, 0x06, + 0x4e, 0x00, 0xf9, 0x80, 0x16, 0xa2, 0x77, 0x12, + 0x00, 0x7b, 0x77, 0x0e, 0x00, 0x09, 0x10, 0x82, + 0x28, 0xf8, 0x00, 0x11, 0xf0, 0x00, 0x00, 0x95, + 0x88, 0x11, 0xf4, 0x95, 0xf4, 0x95, 0x10, 0x81, + 0xf8, 0x45, 0x17, 0xf0, 0xf2, 0x73, 0x17, 0xfd, + 0x77, 0x11, 0xff, 0xff, 0x76, 0x81, 0x00, 0x01, + 0xe9, 0x01, 0x56, 0x00, 0xf1, 0x80, 0x10, 0xf8, + 0x00, 0x0b, 0xf8, 0x45, 0x17, 0xfd, 0xfb, 0x80, + 0x18, 0x10, 0xf4, 0x95, 0x48, 0x11, 0xf9, 0x80, + 0x16, 0x9a, 0xee, 0x03, 0x48, 0x11, 0x8a, 0x11, + 0xf4, 0x95, 0xf4, 0xe4, 0x4a, 0x11, 0x88, 0x11, + 0xf4, 0x95, 0xee, 0xff, 0x71, 0xe1, 0x00, 0x01, + 0x00, 0x11, 0xee, 0x01, 0x10, 0x81, 0x8a, 0x11, + 0xf4, 0x95, 0xf4, 0xe4, 0x4a, 0x11, 0xee, 0xff, + 0xfb, 0x80, 0x16, 0xa2, 0x88, 0x11, 0xf4, 0x95, + 0x77, 0x10, 0xff, 0xff, 0xf4, 0xa9, 0xf8, 0x30, + 0x18, 0xc3, 0x71, 0xe1, 0x00, 0x05, 0x00, 0x12, + 0x76, 0x82, 0x00, 0x00, 0x71, 0xe1, 0x00, 0x06, + 0x00, 0x12, 0x76, 0x82, 0x00, 0x00, 0x71, 0xe1, + 0x00, 0x05, 0x00, 0x12, 0x76, 0x82, 0x00, 0x01, + 0x71, 0xe1, 0x00, 0x06, 0x00, 0x12, 0x76, 0x82, + 0x00, 0x00, 0x71, 0xe1, 0x00, 0x05, 0x00, 0x12, + 0x76, 0x82, 0x00, 0x02, 0x71, 0xe1, 0x00, 0x06, + 0x00, 0x12, 0x76, 0x82, 0x00, 0x00, 0x71, 0xe1, + 0x00, 0x05, 0x00, 0x12, 0x76, 0x82, 0x00, 0x03, + 0x71, 0xe1, 0x00, 0x06, 0x00, 0x12, 0x76, 0x82, + 0x00, 0x00, 0x71, 0xe1, 0x00, 0x05, 0x00, 0x12, + 0x76, 0x82, 0x00, 0x04, 0x71, 0xe1, 0x00, 0x06, + 0x00, 0x12, 0x76, 0x82, 0x00, 0x00, 0x71, 0xe1, + 0x00, 0x05, 0x00, 0x12, 0x76, 0x82, 0x00, 0x05, + 0x71, 0xe1, 0x00, 0x06, 0x00, 0x12, 0x76, 0x82, + 0x00, 0x00, 0x71, 0xe1, 0x00, 0x05, 0x00, 0x12, + 0x76, 0x82, 0x00, 0x06, 0x71, 0xe1, 0x00, 0x06, + 0x00, 0x12, 0x76, 0x82, 0x00, 0x01, 0x71, 0xe1, + 0x00, 0x05, 0x00, 0x12, 0x76, 0x82, 0x00, 0x07, + 0x71, 0xe1, 0x00, 0x06, 0x00, 0x12, 0x76, 0x82, + 0x20, 0x00, 0x71, 0xe1, 0x00, 0x05, 0x00, 0x12, + 0x76, 0x82, 0x00, 0x08, 0x71, 0xe1, 0x00, 0x06, + 0x00, 0x12, 0x76, 0x82, 0x00, 0x00, 0x71, 0xe1, + 0x00, 0x05, 0x00, 0x12, 0x76, 0x82, 0x00, 0x09, + 0x71, 0xe1, 0x00, 0x06, 0x00, 0x12, 0x76, 0x82, + 0x00, 0x00, 0x71, 0xe1, 0x00, 0x05, 0x00, 0x12, + 0x76, 0x82, 0x00, 0x0a, 0x71, 0xe1, 0x00, 0x06, + 0x00, 0x12, 0x76, 0x82, 0x00, 0x00, 0x71, 0xe1, + 0x00, 0x05, 0x00, 0x12, 0x76, 0x82, 0x00, 0x0b, + 0x71, 0xe1, 0x00, 0x06, 0x00, 0x12, 0x76, 0x82, + 0x00, 0x00, 0x71, 0xe1, 0x00, 0x05, 0x00, 0x12, + 0x76, 0x82, 0x00, 0x0c, 0x71, 0xe1, 0x00, 0x06, + 0x00, 0x12, 0x76, 0x82, 0x00, 0x00, 0x71, 0xe1, + 0x00, 0x05, 0x00, 0x12, 0x76, 0x82, 0x00, 0x0d, + 0x71, 0xe1, 0x00, 0x06, 0x00, 0x12, 0x76, 0x82, + 0x00, 0x00, 0x71, 0xe1, 0x00, 0x05, 0x00, 0x12, + 0x76, 0x82, 0x00, 0x0e, 0x71, 0xe1, 0x00, 0x06, + 0x00, 0x12, 0x76, 0x82, 0x00, 0x00, 0x10, 0xe1, + 0x00, 0x07, 0xf9, 0x80, 0x16, 0x76, 0x10, 0xe1, + 0x00, 0x08, 0xf9, 0x80, 0x16, 0x76, 0x10, 0xe1, + 0x00, 0x07, 0xf9, 0x80, 0x16, 0x66, 0x10, 0xe1, + 0x00, 0x08, 0xf9, 0x80, 0x16, 0x66, 0xf0, 0x73, + 0x18, 0xd1, 0x77, 0x11, 0x00, 0x7b, 0x10, 0x81, + 0xfb, 0x80, 0x18, 0x10, 0xf0, 0x00, 0x00, 0x95, + 0x77, 0x11, 0x00, 0x7b, 0x10, 0x81, 0xfb, 0x80, + 0x18, 0x10, 0xf0, 0x00, 0x00, 0x9e, 0xf9, 0x80, + 0x16, 0x9a, 0xee, 0x01, 0x8a, 0x11, 0xf4, 0xe4, + 0x4a, 0x11, 0x88, 0x11, 0xee, 0xff, 0xf4, 0x95, + 0x10, 0x04, 0x71, 0xe1, 0x00, 0x03, 0x00, 0x11, + 0xee, 0x01, 0x80, 0x81, 0x8a, 0x11, 0xf4, 0x95, + 0xf4, 0xe4, 0x4a, 0x11, 0x4a, 0x16, 0xf4, 0x95, + 0x71, 0x04, 0x00, 0x16, 0xfb, 0x80, 0x16, 0xa2, + 0x88, 0x11, 0xf4, 0x95, 0x71, 0xe1, 0x00, 0x02, + 0x00, 0x12, 0x76, 0x82, 0x00, 0x10, 0x10, 0xe6, + 0x00, 0x01, 0x71, 0xe1, 0x00, 0x03, 0x00, 0x12, + 0x80, 0x82, 0x71, 0xe1, 0x00, 0x04, 0x00, 0x12, + 0x10, 0xe6, 0x00, 0x02, 0x80, 0x82, 0xe7, 0x62, + 0x71, 0xe1, 0x00, 0x02, 0x00, 0x13, 0xe5, 0x01, + 0xf9, 0x80, 0x16, 0x9a, 0x8a, 0x16, 0x8a, 0x11, + 0xf4, 0xe4, 0x4a, 0x11, 0x88, 0x11, 0xee, 0xff, + 0xee, 0x01, 0x10, 0xe1, 0x00, 0x01, 0x8a, 0x11, + 0xf4, 0x95, 0xf4, 0xe4, 0x4a, 0x11, 0x77, 0x11, + 0x00, 0x7b, 0x10, 0x81, 0xf0, 0x00, 0x00, 0xb3, + 0x88, 0x11, 0xf4, 0x95, 0xf4, 0x95, 0x10, 0x81, + 0xfa, 0x44, 0x19, 0x2a, 0xf4, 0x95, 0xee, 0xff, + 0xf9, 0x80, 0x16, 0x53, 0x77, 0x11, 0x00, 0x7b, + 0x10, 0x81, 0xf0, 0x00, 0x00, 0xb3, 0x88, 0x11, + 0xf4, 0x95, 0xf4, 0x95, 0x76, 0x81, 0x00, 0x01, + 0xee, 0x01, 0x76, 0xe1, 0x00, 0x01, 0x00, 0x00, + 0x76, 0xe1, 0x00, 0x02, 0x00, 0x13, 0x76, 0xe1, + 0x00, 0x03, 0x00, 0x26, 0x76, 0xe1, 0x00, 0x04, + 0x00, 0x25, 0x76, 0xe1, 0x00, 0x05, 0x00, 0x24, + 0x76, 0xe1, 0x00, 0x06, 0x00, 0x00, 0x76, 0xe1, + 0x00, 0x07, 0x00, 0x17, 0x76, 0xe1, 0x00, 0x08, + 0x00, 0x32, 0x76, 0xe1, 0x00, 0x09, 0x00, 0x31, + 0x76, 0xe1, 0x00, 0x0a, 0x00, 0x30, 0x8a, 0x11, + 0xf4, 0x95, 0xf4, 0xe4, 0x4a, 0x11, 0x4a, 0x16, + 0x4a, 0x17, 0xee, 0xff, 0xf4, 0x95, 0x71, 0x06, + 0x00, 0x17, 0xfb, 0x80, 0x16, 0xa2, 0x88, 0x11, + 0xf4, 0x95, 0xf7, 0xb8, 0x10, 0xf8, 0x00, 0x11, + 0xf0, 0x10, 0xff, 0xff, 0xfa, 0x45, 0x19, 0x73, + 0x77, 0x16, 0xff, 0xff, 0x77, 0x12, 0x00, 0x7b, + 0x77, 0x0e, 0x00, 0x05, 0x10, 0x82, 0x28, 0xf8, + 0x00, 0x11, 0xf0, 0x00, 0x00, 0xb4, 0x88, 0x11, + 0xf4, 0x95, 0xf4, 0x95, 0x10, 0x81, 0xf8, 0x44, + 0x19, 0x84, 0xf2, 0x73, 0x19, 0x84, 0xf4, 0x95, + 0xe7, 0x16, 0x77, 0x11, 0x00, 0x7b, 0x10, 0x81, + 0xf0, 0x00, 0x00, 0xb4, 0x88, 0x11, 0xf4, 0x95, + 0x77, 0x12, 0x00, 0x02, 0x10, 0x81, 0xf8, 0x45, + 0x19, 0x6f, 0x6e, 0xea, 0xff, 0xff, 0x19, 0x7c, + 0x6d, 0xe9, 0x00, 0x05, 0x61, 0xf8, 0x00, 0x17, + 0x00, 0x01, 0xfa, 0x20, 0x19, 0x8f, 0x76, 0x86, + 0x00, 0x01, 0xfb, 0x80, 0x19, 0x97, 0xf4, 0x95, + 0x48, 0x16, 0xf9, 0x80, 0x16, 0x9a, 0xee, 0x01, + 0x8a, 0x17, 0x48, 0x16, 0x8a, 0x16, 0x8a, 0x11, + 0xf4, 0xe4, 0x4a, 0x11, 0xee, 0xff, 0xfb, 0x80, + 0x16, 0xa2, 0x88, 0x11, 0xf4, 0x95, 0x77, 0x10, + 0xff, 0xff, 0xf4, 0xa9, 0xf8, 0x30, 0x19, 0xcc, + 0x71, 0xe1, 0x00, 0x02, 0x00, 0x12, 0x69, 0x82, + 0x00, 0x10, 0x71, 0xe1, 0x00, 0x02, 0x00, 0x12, + 0x68, 0x82, 0xf7, 0xff, 0x71, 0xe1, 0x00, 0x02, + 0x00, 0x12, 0x68, 0x82, 0xfb, 0xff, 0x71, 0xe1, + 0x00, 0x02, 0x00, 0x12, 0x68, 0x82, 0xff, 0xf0, + 0x71, 0xe1, 0x00, 0x03, 0x00, 0x12, 0x76, 0x82, + 0xff, 0xff, 0x71, 0xe1, 0x00, 0x04, 0x00, 0x12, + 0x76, 0x82, 0xff, 0xff, 0x71, 0xe1, 0x00, 0x02, + 0x00, 0x12, 0x69, 0x82, 0x00, 0x20, 0x71, 0xe1, + 0x00, 0x02, 0x00, 0x11, 0xf2, 0x73, 0x19, 0xda, + 0x68, 0x81, 0xff, 0xef, 0x77, 0x11, 0x00, 0x7b, + 0x10, 0x81, 0xfb, 0x80, 0x19, 0x97, 0xf0, 0x00, + 0x00, 0xb4, 0x77, 0x11, 0x00, 0x7b, 0x10, 0x81, + 0xfb, 0x80, 0x19, 0x97, 0xf0, 0x00, 0x00, 0xb9, + 0xf9, 0x80, 0x16, 0x9a, 0xee, 0x01, 0x8a, 0x11, + 0xf4, 0xe4, 0x00, 0xa4, 0x00, 0x00, 0x19, 0xdf, + 0x00, 0x01, 0x2a, 0xe6, 0x00, 0x00, 0x00, 0x01, + 0x2a, 0xe7, 0x00, 0x00, 0x00, 0x03, 0x2a, 0x12, + 0x0c, 0x01, 0xc3, 0x4f, 0x00, 0x00, 0x00, 0x01, + 0x2a, 0x15, 0x00, 0x00, 0x00, 0x02, 0x2a, 0x16, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x2a, 0x5d, + 0x00, 0x43, 0x00, 0x6f, 0x00, 0x70, 0x00, 0x79, + 0x00, 0x72, 0x00, 0x69, 0x00, 0x67, 0x00, 0x68, + 0x00, 0x74, 0x00, 0x20, 0x00, 0x54, 0x00, 0x65, + 0x00, 0x63, 0x00, 0x68, 0x00, 0x6e, 0x00, 0x6f, + 0x00, 0x54, 0x00, 0x72, 0x00, 0x65, 0x00, 0x6e, + 0x00, 0x64, 0x00, 0x20, 0x00, 0x41, 0x00, 0x47, + 0x00, 0x00, 0x00, 0x04, 0x2a, 0x76, 0x00, 0x30, + 0x00, 0x2e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x0c, + 0x2a, 0x7a, 0x00, 0x46, 0x00, 0x65, 0x00, 0x62, + 0x00, 0x20, 0x00, 0x32, 0x00, 0x37, 0x00, 0x20, + 0x00, 0x32, 0x00, 0x30, 0x00, 0x30, 0x00, 0x31, + 0x00, 0x00, 0x00, 0x09, 0x2a, 0x86, 0x00, 0x31, + 0x00, 0x34, 0x00, 0x3a, 0x00, 0x33, 0x00, 0x35, + 0x00, 0x3a, 0x00, 0x33, 0x00, 0x33, 0x00, 0x00, + 0x00, 0x0f, 0x2a, 0x8f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x2a, 0x9e, 0x00, 0x00, + 0x00, 0x01, 0x2a, 0x9f, 0x00, 0x00, 0x00, 0x01, + 0x2a, 0xa0, 0x00, 0x00, 0x00, 0x01, 0x2a, 0xa1, + 0x00, 0x00, 0x00, 0x01, 0x2a, 0xa2, 0x00, 0x00, + 0x00, 0x01, 0x29, 0x7e, 0x00, 0x00, 0x00, 0x02, + 0x29, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x29, 0x82, 0xff, 0xff, 0x00, 0x01, 0x2a, 0xa7, + 0x00, 0x00, 0x00, 0x05, 0x2a, 0xa8, 0x71, 0x41, + 0x20, 0x00, 0x20, 0x00, 0x00, 0x23, 0x04, 0x00, + 0x00, 0x0a, 0x2a, 0xad, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0f, 0x2a, 0xb7, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x40, 0x00, 0xa0, 0x82, 0x40, + 0x00, 0x08, 0x30, 0x7f, 0x00, 0x80, 0x01, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x27, 0x6e, 0x00, 0x00, + 0x00, 0x01, 0x27, 0x6f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x09, 0x00, 0x00, 0x1a, 0x83, 0x04, 0xe8, + 0x04, 0xcf, 0x04, 0xc5, 0x04, 0xba, 0x04, 0xb0, + 0x04, 0xac, 0x04, 0x9c, 0x04, 0x8c, 0x04, 0x81, + 0x00, 0x78, 0x00, 0x00, 0x01, 0x00, 0xf2, 0x73, + 0x07, 0xef, 0xf4, 0x95, 0xf4, 0x95, 0xf2, 0x73, + 0x07, 0xef, 0xf4, 0x95, 0xf4, 0x95, 0xf2, 0x73, + 0x07, 0xef, 0xf4, 0x95, 0xf4, 0x95, 0xf2, 0x73, + 0x07, 0xef, 0xf4, 0x95, 0xf4, 0x95, 0xf2, 0x73, + 0x07, 0xef, 0xf4, 0x95, 0xf4, 0x95, 0xf2, 0x73, + 0x07, 0xef, 0xf4, 0x95, 0xf4, 0x95, 0xf2, 0x73, + 0x07, 0xef, 0xf4, 0x95, 0xf4, 0x95, 0xf2, 0x73, + 0x07, 0xef, 0xf4, 0x95, 0xf4, 0x95, 0xf2, 0x73, + 0x07, 0xef, 0xf4, 0x95, 0xf4, 0x95, 0xf2, 0x73, + 0x07, 0xef, 0xf4, 0x95, 0xf4, 0x95, 0xf2, 0x73, + 0x07, 0xef, 0xf4, 0x95, 0xf4, 0x95, 0xf2, 0x73, + 0x07, 0xef, 0xf4, 0x95, 0xf4, 0x95, 0xf2, 0x73, + 0x07, 0xef, 0xf4, 0x95, 0xf4, 0x95, 0xf2, 0x73, + 0x07, 0xef, 0xf4, 0x95, 0xf4, 0x95, 0xf2, 0x73, + 0x07, 0xef, 0xf4, 0x95, 0xf4, 0x95, 0xf2, 0x73, + 0x07, 0xef, 0xf4, 0x95, 0xf4, 0x95, 0xf2, 0x73, + 0x07, 0xaa, 0xf4, 0x95, 0xf4, 0x95, 0xf2, 0x73, + 0x07, 0xef, 0xf4, 0x95, 0xf4, 0x95, 0xf2, 0x73, + 0x07, 0xef, 0xf4, 0x95, 0xf4, 0x95, 0xf2, 0x73, + 0x02, 0x23, 0xf4, 0x95, 0xf4, 0x95, 0xf2, 0x73, + 0x07, 0xef, 0xf4, 0x95, 0xf4, 0x95, 0xf2, 0x73, + 0x07, 0xef, 0xf4, 0x95, 0xf4, 0x95, 0xf2, 0x73, + 0x07, 0xef, 0xf4, 0x95, 0xf4, 0x95, 0xf2, 0x73, + 0x07, 0xef, 0xf4, 0x95, 0xf4, 0x95, 0xf2, 0x73, + 0x07, 0xef, 0xf4, 0x95, 0xf4, 0x95, 0xf2, 0x73, + 0x07, 0xef, 0xf4, 0x95, 0xf4, 0x95, 0xf2, 0x73, + 0x05, 0xe5, 0xf4, 0x95, 0xf4, 0x95, 0xf2, 0x73, + 0x02, 0xb5, 0xf4, 0x95, 0xf4, 0x95, 0xf2, 0x73, + 0x0e, 0x33, 0xf4, 0x95, 0xf4, 0x95, 0xf2, 0x73, + 0x07, 0xef, 0xf4, 0x95, 0xf4, 0x95, 0x00, 0x00, +}; + diff -Nru a/drivers/media/dvb/ttusb-dec/Kconfig b/drivers/media/dvb/ttusb-dec/Kconfig --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/media/dvb/ttusb-dec/Kconfig Sun Jul 27 10:13:53 2003 @@ -0,0 +1,24 @@ +config DVB_TTUSB_DEC + tristate "Technotrend/Hauppauge USB DEC2000-T devices" + depends on DVB_CORE && USB + help + Support for external USB adapters designed by Technotrend and + produced by Hauppauge, shipped under the brand name 'DEC2000-T'. + + Even if these devices have a MPEG decoder built in, they transmit + only compressed MPEG data over the USB bus, so you need + an external software decoder to watch TV on your computer. + + Say Y if you own such a device and want to use it. + +config DVB_TTUSB_DEC_FIRMWARE_FILE + string "Full pathname of dec2000t.bin firmware file" + depends on DVB_TTUSB_DEC + default "/etc/dvb/dec2000t.bin" + help + The DEC2000-T requires a firmware in order to boot into a mode in + which it is a slave to the PC. The firmware file can obtained as + follows: + wget http://hauppauge.lightpath.net/de/dec215a.exe + unzip -j dec215a.exe Software/Oem/STB/App/Boot/STB_PC_T.bin + mv STB_PC_T.bin /etc/dvb/dec2000t.bin diff -Nru a/drivers/media/dvb/ttusb-dec/Makefile b/drivers/media/dvb/ttusb-dec/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/media/dvb/ttusb-dec/Makefile Sun Jul 27 10:13:53 2003 @@ -0,0 +1,11 @@ + +obj-$(CONFIG_DVB_TTUSB_DEC) += ttusb_dec.o dec2000_frontend.o + +EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ + +host-progs := fdump + +$(obj)/ttusb_dec.o: $(obj)/dsp_dec2000.h + +$(obj)/dsp_dec2000.h: $(patsubst "%", %, $(CONFIG_DVB_TTUSB_DEC_FIRMWARE_FILE)) $(obj)/fdump + $(obj)/fdump $< dsp_dec2000 > $@ diff -Nru a/drivers/media/dvb/ttusb-dec/dec2000_frontend.c b/drivers/media/dvb/ttusb-dec/dec2000_frontend.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/media/dvb/ttusb-dec/dec2000_frontend.c Sun Jul 27 10:13:53 2003 @@ -0,0 +1,180 @@ +/* + * TTUSB DEC-2000-t Frontend + * + * Copyright (C) 2003 Alex Woods + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include + +#include "dvb_frontend.h" +#include "dvb_functions.h" + +static int debug = 0; + +#define dprintk if (debug) printk + +static struct dvb_frontend_info dec2000_frontend_info = { + name: "TechnoTrend/Hauppauge DEC-2000-t Frontend", + type: FE_OFDM, + frequency_min: 51000000, + frequency_max: 858000000, + frequency_stepsize: 62500, + caps: FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_HIERARCHY_AUTO, +}; + +static int dec2000_frontend_ioctl(struct dvb_frontend *fe, unsigned int cmd, + void *arg) +{ + dprintk("%s\n", __FUNCTION__); + + switch (cmd) { + + case FE_GET_INFO: + dprintk("%s: FE_GET_INFO\n", __FUNCTION__); + memcpy(arg, &dec2000_frontend_info, + sizeof (struct dvb_frontend_info)); + break; + + case FE_READ_STATUS: { + fe_status_t *status = (fe_status_t *)arg; + dprintk("%s: FE_READ_STATUS\n", __FUNCTION__); + *status = FE_HAS_SIGNAL | FE_HAS_VITERBI | + FE_HAS_SYNC | FE_HAS_CARRIER | FE_HAS_LOCK; + break; + } + + case FE_READ_BER: { + u32 *ber = (u32 *)arg; + dprintk("%s: FE_READ_BER\n", __FUNCTION__); + *ber = 0; + return -ENOSYS; + break; + } + + case FE_READ_SIGNAL_STRENGTH: { + dprintk("%s: FE_READ_SIGNAL_STRENGTH\n", __FUNCTION__); + *(s32 *)arg = 0xFF; + return -ENOSYS; + break; + } + + case FE_READ_SNR: + dprintk("%s: FE_READ_SNR\n", __FUNCTION__); + *(s32 *)arg = 0; + return -ENOSYS; + break; + + case FE_READ_UNCORRECTED_BLOCKS: + dprintk("%s: FE_READ_UNCORRECTED_BLOCKS\n", __FUNCTION__); + *(u32 *)arg = 0; + return -ENOSYS; + break; + + case FE_SET_FRONTEND:{ + struct dvb_frontend_parameters *p = + (struct dvb_frontend_parameters *)arg; + u8 b[] = { 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0xff, 0x00, 0x00, 0x00, 0xff }; + u32 freq; + struct i2c_msg msg = { addr: 0x71, flags: 0, len:20 }; + + dprintk("%s: FE_SET_FRONTEND\n", __FUNCTION__); + + dprintk(" frequency->%d\n", p->frequency); + dprintk(" symbol_rate->%d\n", + p->u.qam.symbol_rate); + dprintk(" inversion->%d\n", p->inversion); + + freq = htonl(p->frequency / 1000); + memcpy(&b[4], &freq, sizeof (int)); + msg.buf = b; + fe->i2c->xfer(fe->i2c, &msg, 1); + + break; + } + + case FE_GET_FRONTEND: + dprintk("%s: FE_GET_FRONTEND\n", __FUNCTION__); + break; + + case FE_SLEEP: + dprintk("%s: FE_SLEEP\n", __FUNCTION__); + return -ENOSYS; + break; + + case FE_INIT: + dprintk("%s: FE_INIT\n", __FUNCTION__); + break; + + case FE_RESET: + dprintk("%s: FE_RESET\n", __FUNCTION__); + break; + + default: + dprintk("%s: unknown IOCTL (0x%X)\n", __FUNCTION__, cmd); + return -EINVAL; + + } + + return 0; +} + +static int dec2000_frontend_attach(struct dvb_i2c_bus *i2c) +{ + dprintk("%s\n", __FUNCTION__); + + dvb_register_frontend(dec2000_frontend_ioctl, i2c, NULL, + &dec2000_frontend_info); + + return 0; +} + +static void dec2000_frontend_detach(struct dvb_i2c_bus *i2c) +{ + dprintk("%s\n", __FUNCTION__); + + dvb_unregister_frontend(dec2000_frontend_ioctl, i2c); +} + +static int __init dec2000_frontend_init(void) +{ + return dvb_register_i2c_device(THIS_MODULE, dec2000_frontend_attach, + dec2000_frontend_detach); +} + +static void __exit dec2000_frontend_exit(void) +{ + dvb_unregister_i2c_device(dec2000_frontend_attach); +} + +module_init(dec2000_frontend_init); +module_exit(dec2000_frontend_exit); + +MODULE_DESCRIPTION("TechnoTrend/Hauppauge DEC-2000-t Frontend"); +MODULE_AUTHOR("Alex Woods +#include +#include +#include +#include + + +int main (int argc, char **argv) +{ + unsigned char buf[8]; + unsigned int i, count, bytes = 0; + int fd; + + if (argc != 3) { + fprintf (stderr, "\n\tusage: %s \n\n", + argv[0]); + return -1; + } + + fd = open (argv[1], O_RDONLY); + + printf ("\n#include \n\nu8 %s [] __initdata = {", + argv[2]); + + while ((count = read (fd, buf, 8)) > 0) { + printf ("\n\t"); + for (i=0;i + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include + +#include "ttusb_dec.h" +#include "dvb_frontend.h" + +static int debug = 0; + +#define dprintk if (debug) printk + +static int ttusb_dec_send_command(struct ttusb_dec *dec, const u8 command, + int param_length, const u8 params[], + int *result_length, u8 cmd_result[]) +{ + int result, actual_len, i; + u8 b[COMMAND_PACKET_SIZE + 4]; + u8 c[COMMAND_PACKET_SIZE + 4]; + + dprintk("%s\n", __FUNCTION__); + + if ((result = down_interruptible(&dec->usb_sem))) { + printk("%s: Failed to down usb semaphore.\n", __FUNCTION__); + return result; + } + + b[0] = 0xaa; + b[1] = ++dec->trans_count; + b[2] = command; + b[3] = param_length; + + if (params) + memcpy(&b[4], params, param_length); + + if (debug) { + printk("%s: command: ", __FUNCTION__); + for (i = 0; i < param_length + 4; i++) + printk("0x%02X ", b[i]); + printk("\n"); + } + + result = usb_bulk_msg(dec->udev, dec->command_pipe, b, sizeof(b), + &actual_len, HZ); + + if (result) { + printk("%s: command bulk message failed: error %d\n", + __FUNCTION__, result); + up(&dec->usb_sem); + return result; + } + + result = usb_bulk_msg(dec->udev, dec->result_pipe, c, sizeof(c), + &actual_len, HZ); + + if (result) { + printk("%s: result bulk message failed: error %d\n", + __FUNCTION__, result); + up(&dec->usb_sem); + return result; + } else { + if (debug) { + printk("%s: result: ", __FUNCTION__); + for (i = 0; i < actual_len; i++) + printk("0x%02X ", c[i]); + printk("\n"); + } + + if (result_length) + *result_length = c[3]; + if (cmd_result && c[3] > 0) + memcpy(cmd_result, &c[4], c[3]); + + up(&dec->usb_sem); + + return 0; + } +} + +static int ttusb_dec_av_pes2ts_cb(void *priv, unsigned char *data) +{ + struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)priv; + + dvbdmxfeed->cb.ts(data, 188, 0, 0, &dvbdmxfeed->feed.ts, DMX_OK); + + return 0; +} + +static void ttusb_dec_set_pids(struct ttusb_dec *dec) +{ + u8 b[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff }; + + u16 pcr = htons(dec->pid[DMX_PES_PCR]); + u16 audio = htons(dec->pid[DMX_PES_AUDIO]); + u16 video = htons(dec->pid[DMX_PES_VIDEO]); + + dprintk("%s\n", __FUNCTION__); + + memcpy(&b[0], &pcr, 2); + memcpy(&b[2], &audio, 2); + memcpy(&b[4], &video, 2); + + ttusb_dec_send_command(dec, 0x50, sizeof(b), b, NULL, NULL); + + if (!down_interruptible(&dec->pes2ts_sem)) { + dvb_filter_pes2ts_init(&dec->a_pes2ts, dec->pid[DMX_PES_AUDIO], + ttusb_dec_av_pes2ts_cb, dec->demux.feed); + dvb_filter_pes2ts_init(&dec->v_pes2ts, dec->pid[DMX_PES_VIDEO], + ttusb_dec_av_pes2ts_cb, dec->demux.feed); + + up(&dec->pes2ts_sem); + } +} + +static int ttusb_dec_i2c_master_xfer(struct dvb_i2c_bus *i2c, + const struct i2c_msg msgs[], int num) +{ + int result, i; + + dprintk("%s\n", __FUNCTION__); + + for (i = 0; i < num; i++) + if ((result = ttusb_dec_send_command(i2c->data, msgs[i].addr, + msgs[i].len, msgs[i].buf, + NULL, NULL))) + return result; + + return 0; +} + +static void ttusb_dec_process_av_pes(struct ttusb_dec * dec, u8 * av_pes, + int length) +{ + int i; + u16 csum = 0; + u8 c; + + if (length < 16) { + printk("%s: packet too short.\n", __FUNCTION__); + return; + } + + for (i = 0; i < length; i += 2) { + csum ^= le16_to_cpup((u16 *)(av_pes + i)); + c = av_pes[i]; + av_pes[i] = av_pes[i + 1]; + av_pes[i + 1] = c; + } + + if (csum) { + printk("%s: checksum failed.\n", __FUNCTION__); + return; + } + + if (length > 8 + MAX_AV_PES_LENGTH + 4) { + printk("%s: packet too long.\n", __FUNCTION__); + return; + } + + if (!(av_pes[0] == 'A' && av_pes[1] == 'V')) { + printk("%s: invalid AV_PES packet.\n", __FUNCTION__); + return; + } + + switch (av_pes[2]) { + + case 0x01: { /* VideoStream */ + int prebytes = av_pes[5] & 0x03; + int postbytes = (av_pes[5] & 0x0c) >> 2; + u16 v_pes_payload_length; + + if (dec->v_pes_postbytes > 0 && + dec->v_pes_postbytes == prebytes) { + memcpy(&dec->v_pes[dec->v_pes_length], + &av_pes[12], prebytes); + + if (!down_interruptible(&dec->pes2ts_sem)) { + dvb_filter_pes2ts(&dec->v_pes2ts, + dec->v_pes, + dec->v_pes_length + + prebytes); + + up(&dec->pes2ts_sem); + } + } + + if (av_pes[5] & 0x10) { + dec->v_pes[7] = 0x80; + dec->v_pes[8] = 0x05; + + dec->v_pes[9] = 0x21 | + ((av_pes[8] & 0xc0) >> 5); + dec->v_pes[10] = ((av_pes[8] & 0x3f) << 2) | + ((av_pes[9] & 0xc0) >> 6); + dec->v_pes[11] = 0x01 | + ((av_pes[9] & 0x3f) << 2) | + ((av_pes[10] & 0x80) >> 6); + dec->v_pes[12] = ((av_pes[10] & 0x7f) << 1) | + ((av_pes[11] & 0xc0) >> 7); + dec->v_pes[13] = 0x01 | + ((av_pes[11] & 0x7f) << 1); + + memcpy(&dec->v_pes[14], &av_pes[12 + prebytes], + length - 16 - prebytes); + dec->v_pes_length = 14 + length - 16 - prebytes; + } else { + dec->v_pes[7] = 0x00; + dec->v_pes[8] = 0x00; + + memcpy(&dec->v_pes[9], &av_pes[8], length - 12); + dec->v_pes_length = 9 + length - 12; + } + + dec->v_pes_postbytes = postbytes; + + if (dec->v_pes[9 + dec->v_pes[8]] == 0x00 && + dec->v_pes[10 + dec->v_pes[8]] == 0x00 && + dec->v_pes[11 + dec->v_pes[8]] == 0x01) + dec->v_pes[6] = 0x84; + else + dec->v_pes[6] = 0x80; + + v_pes_payload_length = htons(dec->v_pes_length - 6 + + postbytes); + memcpy(&dec->v_pes[4], &v_pes_payload_length, 2); + + if (postbytes == 0) { + if (!down_interruptible(&dec->pes2ts_sem)) { + dvb_filter_pes2ts(&dec->v_pes2ts, + dec->v_pes, + dec->v_pes_length); + + up(&dec->pes2ts_sem); + } + } + + break; + } + + case 0x02: /* MainAudioStream */ + dvb_filter_pes2ts(&dec->a_pes2ts, &av_pes[8], length - 12); + break; + + default: + printk("%s: unknown AV_PES type: %02x.\n", __FUNCTION__, + av_pes[2]); + break; + + } +} + +static void ttusb_dec_process_urb_frame(struct ttusb_dec * dec, u8 * b, + int length) +{ + while (length) { + switch (dec->av_pes_state) { + + case 0: + case 1: + case 3: + if (*b++ == 0xaa) { + dec->av_pes_state++; + if (dec->av_pes_state == 4) + dec->av_pes_length = 0; + } else { + dec->av_pes_state = 0; + } + + length--; + break; + + case 2: + if (*b++ == 0x00) { + dec->av_pes_state++; + } else { + dec->av_pes_state = 0; + } + + length--; + break; + + case 4: + dec->av_pes[dec->av_pes_length++] = *b++; + + if (dec->av_pes_length == 8) { + dec->av_pes_state++; + dec->av_pes_payload_length = le16_to_cpup( + (u16 *)(dec->av_pes + 6)); + } + + length--; + break; + + case 5: { + int remainder = dec->av_pes_payload_length + + 8 - dec->av_pes_length; + + if (length >= remainder) { + memcpy(dec->av_pes + dec->av_pes_length, + b, remainder); + dec->av_pes_length += remainder; + b += remainder; + length -= remainder; + dec->av_pes_state++; + } else { + memcpy(&dec->av_pes[dec->av_pes_length], + b, length); + dec->av_pes_length += length; + length = 0; + } + + break; + } + + case 6: + dec->av_pes[dec->av_pes_length++] = *b++; + + if (dec->av_pes_length == + 8 + dec->av_pes_payload_length + 4) { + ttusb_dec_process_av_pes(dec, dec->av_pes, + dec->av_pes_length); + dec->av_pes_state = 0; + } + + length--; + break; + + default: + printk("%s: illegal packet state encountered.\n", + __FUNCTION__); + dec->av_pes_state = 0; + + } + + } +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +static void ttusb_dec_process_urb(struct urb *urb) +#else +static void ttusb_dec_process_urb(struct urb *urb, struct pt_regs *ptregs) +#endif +{ + struct ttusb_dec *dec = urb->context; + + if (!urb->status) { + int i; + + for (i = 0; i < FRAMES_PER_ISO_BUF; i++) { + struct usb_iso_packet_descriptor *d; + u8 *b; + int length; + + d = &urb->iso_frame_desc[i]; + b = urb->transfer_buffer + d->offset; + length = d->actual_length; + + ttusb_dec_process_urb_frame(dec, b, length); + } + } else { + /* -ENOENT is expected when unlinking urbs */ + if (urb->status != -ENOENT) + dprintk("%s: urb error: %d\n", __FUNCTION__, + urb->status); + } + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) + if (dec->iso_stream_count) + usb_submit_urb(urb, GFP_KERNEL); +#endif +} + +static void ttusb_dec_setup_urbs(struct ttusb_dec *dec) +{ + int i, j, buffer_offset = 0; + + dprintk("%s\n", __FUNCTION__); + + for (i = 0; i < ISO_BUF_COUNT; i++) { + int frame_offset = 0; + struct urb *urb = dec->iso_urb[i]; + + urb->dev = dec->udev; + urb->context = dec; + urb->complete = ttusb_dec_process_urb; + urb->pipe = dec->stream_pipe; + urb->transfer_flags = URB_ISO_ASAP; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) + urb->interval = 1; +#endif + urb->number_of_packets = FRAMES_PER_ISO_BUF; + urb->transfer_buffer_length = ISO_FRAME_SIZE * + FRAMES_PER_ISO_BUF; + urb->transfer_buffer = dec->iso_buffer + buffer_offset; + buffer_offset += ISO_FRAME_SIZE * FRAMES_PER_ISO_BUF; + + for (j = 0; j < FRAMES_PER_ISO_BUF; j++) { + urb->iso_frame_desc[j].offset = frame_offset; + urb->iso_frame_desc[j].length = ISO_FRAME_SIZE; + frame_offset += ISO_FRAME_SIZE; + } + } +} + +static void ttusb_dec_stop_iso_xfer(struct ttusb_dec *dec) +{ + int i; + + dprintk("%s\n", __FUNCTION__); + + if (down_interruptible(&dec->iso_sem)) + return; + + dec->iso_stream_count--; + + if (!dec->iso_stream_count) { + u8 b0[] = { 0x00 }; + + for (i = 0; i < ISO_BUF_COUNT; i++) + usb_unlink_urb(dec->iso_urb[i]); + + ttusb_dec_send_command(dec, 0x81, sizeof(b0), b0, NULL, NULL); + } + + up(&dec->iso_sem); +} + +/* Setting the interface of the DEC tends to take down the USB communications + * for a short period, so it's important not to call this function just before + * trying to talk to it. + */ +static void ttusb_dec_set_streaming_interface(struct ttusb_dec *dec) +{ + if (!dec->interface) { + usb_set_interface(dec->udev, 0, 8); + dec->interface = 8; + } +} + +static int ttusb_dec_start_iso_xfer(struct ttusb_dec *dec) +{ + int i, result; + + dprintk("%s\n", __FUNCTION__); + + if (down_interruptible(&dec->iso_sem)) + return -EAGAIN; + + if (!dec->iso_stream_count) { + u8 b0[] = { 0x05 }; + + ttusb_dec_send_command(dec, 0x80, sizeof(b0), b0, NULL, NULL); + + ttusb_dec_setup_urbs(dec); + + for (i = 0; i < ISO_BUF_COUNT; i++) { + if ((result = usb_submit_urb(dec->iso_urb[i] + , GFP_KERNEL))) { + printk("%s: failed urb submission %d: " + "error %d\n", __FUNCTION__, i, result); + + while (i) { + usb_unlink_urb(dec->iso_urb[i - 1]); + i--; + } + + up(&dec->iso_sem); + return result; + } + } + + dec->av_pes_state = 0; + dec->v_pes_postbytes = 0; + } + + dec->iso_stream_count++; + + up(&dec->iso_sem); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) + ttusb_dec_set_streaming_interface(dec); +#endif + + return 0; +} + +static int ttusb_dec_start_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + struct dvb_demux *dvbdmx = dvbdmxfeed->demux; + struct ttusb_dec *dec = dvbdmx->priv; + + dprintk("%s\n", __FUNCTION__); + + if (!dvbdmx->dmx.frontend) + return -EINVAL; + + dprintk(" pid: 0x%04X\n", dvbdmxfeed->pid); + + switch (dvbdmxfeed->type) { + + case DMX_TYPE_TS: + dprintk(" type: DMX_TYPE_TS\n"); + break; + + case DMX_TYPE_SEC: + dprintk(" type: DMX_TYPE_SEC\n"); + break; + + default: + dprintk(" type: unknown (%d)\n", dvbdmxfeed->type); + return -EINVAL; + + } + + dprintk(" ts_type:"); + + if (dvbdmxfeed->ts_type & TS_DECODER) + dprintk(" TS_DECODER"); + + if (dvbdmxfeed->ts_type & TS_PACKET) + dprintk(" TS_PACKET"); + + if (dvbdmxfeed->ts_type & TS_PAYLOAD_ONLY) + dprintk(" TS_PAYLOAD_ONLY"); + + dprintk("\n"); + + switch (dvbdmxfeed->pes_type) { + + case DMX_TS_PES_VIDEO: + dprintk(" pes_type: DMX_TS_PES_VIDEO\n"); + dec->pid[DMX_PES_PCR] = dvbdmxfeed->pid; + dec->pid[DMX_PES_VIDEO] = dvbdmxfeed->pid; + ttusb_dec_set_pids(dec); + break; + + case DMX_TS_PES_AUDIO: + dprintk(" pes_type: DMX_TS_PES_AUDIO\n"); + dec->pid[DMX_PES_AUDIO] = dvbdmxfeed->pid; + ttusb_dec_set_pids(dec); + break; + + case DMX_TS_PES_TELETEXT: + dec->pid[DMX_PES_TELETEXT] = dvbdmxfeed->pid; + dprintk(" pes_type: DMX_TS_PES_TELETEXT\n"); + break; + + case DMX_TS_PES_PCR: + dprintk(" pes_type: DMX_TS_PES_PCR\n"); + dec->pid[DMX_PES_PCR] = dvbdmxfeed->pid; + ttusb_dec_set_pids(dec); + break; + + case DMX_TS_PES_OTHER: + dprintk(" pes_type: DMX_TS_PES_OTHER\n"); + break; + + default: + dprintk(" pes_type: unknown (%d)\n", dvbdmxfeed->pes_type); + return -EINVAL; + + } + + ttusb_dec_start_iso_xfer(dec); + + return 0; +} + +static int ttusb_dec_stop_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + struct ttusb_dec *dec = dvbdmxfeed->demux->priv; + + dprintk("%s\n", __FUNCTION__); + + ttusb_dec_stop_iso_xfer(dec); + + return 0; +} + +static void ttusb_dec_free_iso_urbs(struct ttusb_dec *dec) +{ + int i; + + dprintk("%s\n", __FUNCTION__); + + for (i = 0; i < ISO_BUF_COUNT; i++) + if (dec->iso_urb[i]) + usb_free_urb(dec->iso_urb[i]); + + pci_free_consistent(NULL, + ISO_FRAME_SIZE * (FRAMES_PER_ISO_BUF * + ISO_BUF_COUNT), + dec->iso_buffer, dec->iso_dma_handle); +} + +static int ttusb_dec_alloc_iso_urbs(struct ttusb_dec *dec) +{ + int i; + + dprintk("%s\n", __FUNCTION__); + + dec->iso_buffer = pci_alloc_consistent(NULL, + ISO_FRAME_SIZE * + (FRAMES_PER_ISO_BUF * + ISO_BUF_COUNT), + &dec->iso_dma_handle); + + memset(dec->iso_buffer, 0, + sizeof(ISO_FRAME_SIZE * (FRAMES_PER_ISO_BUF * ISO_BUF_COUNT))); + + for (i = 0; i < ISO_BUF_COUNT; i++) { + struct urb *urb; + + if (!(urb = usb_alloc_urb(FRAMES_PER_ISO_BUF, GFP_KERNEL))) { + ttusb_dec_free_iso_urbs(dec); + return -ENOMEM; + } + + dec->iso_urb[i] = urb; + } + + ttusb_dec_setup_urbs(dec); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) + for (i = 0; i < ISO_BUF_COUNT; i++) { + int next = (i + 1) % ISO_BUF_COUNT; + dec->iso_urb[i]->next = dec->iso_urb[next]; + } +#endif + + return 0; +} + +static void ttusb_dec_init_v_pes(struct ttusb_dec *dec) +{ + dprintk("%s\n", __FUNCTION__); + + dec->v_pes[0] = 0x00; + dec->v_pes[1] = 0x00; + dec->v_pes[2] = 0x01; + dec->v_pes[3] = 0xe0; +} + +static void ttusb_dec_init_usb(struct ttusb_dec *dec) +{ + dprintk("%s\n", __FUNCTION__); + + sema_init(&dec->usb_sem, 1); + sema_init(&dec->iso_sem, 1); + + dec->command_pipe = usb_sndbulkpipe(dec->udev, COMMAND_PIPE); + dec->result_pipe = usb_rcvbulkpipe(dec->udev, RESULT_PIPE); + dec->stream_pipe = usb_rcvisocpipe(dec->udev, STREAM_PIPE); + + ttusb_dec_alloc_iso_urbs(dec); +} + +#include "dsp_dec2000.h" + +static int ttusb_dec_boot_dsp(struct ttusb_dec *dec) +{ + int i, j, actual_len, result, size, trans_count; + u8 b0[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0xc8, 0x61, + 0x00 }; + u8 b1[] = { 0x61 }; + u8 b[ARM_PACKET_SIZE]; + u32 dsp_length = htonl(sizeof(dsp_dec2000)); + + dprintk("%s\n", __FUNCTION__); + + memcpy(b0, &dsp_length, 4); + + result = ttusb_dec_send_command(dec, 0x41, sizeof(b0), b0, NULL, NULL); + + if (result) + return result; + + trans_count = 0; + j = 0; + + for (i = 0; i < sizeof(dsp_dec2000); i += COMMAND_PACKET_SIZE) { + size = sizeof(dsp_dec2000) - i; + if (size > COMMAND_PACKET_SIZE) + size = COMMAND_PACKET_SIZE; + + b[j + 0] = 0xaa; + b[j + 1] = trans_count++; + b[j + 2] = 0xf0; + b[j + 3] = size; + memcpy(&b[j + 4], &dsp_dec2000[i], size); + + j += COMMAND_PACKET_SIZE + 4; + + if (j >= ARM_PACKET_SIZE) { + result = usb_bulk_msg(dec->udev, dec->command_pipe, b, + ARM_PACKET_SIZE, &actual_len, + HZ / 10); + j = 0; + } else if (size < COMMAND_PACKET_SIZE) { + result = usb_bulk_msg(dec->udev, dec->command_pipe, b, + j - COMMAND_PACKET_SIZE + size, + &actual_len, HZ / 10); + } + } + + result = ttusb_dec_send_command(dec, 0x43, sizeof(b1), b1, NULL, NULL); + + return result; +} + +static void ttusb_dec_init_stb(struct ttusb_dec *dec) +{ + u8 c[COMMAND_PACKET_SIZE]; + int c_length; + int result; + + dprintk("%s\n", __FUNCTION__); + + result = ttusb_dec_send_command(dec, 0x08, 0, NULL, &c_length, c); + + if (!result) + if (c_length != 0x0c || (c_length == 0x0c && c[9] != 0x63)) + ttusb_dec_boot_dsp(dec); +} + +static int ttusb_dec_init_dvb(struct ttusb_dec *dec) +{ + int result; + + dprintk("%s\n", __FUNCTION__); + + if ((result = dvb_register_adapter(&dec->adapter, "dec2000")) < 0) { + printk("%s: dvb_register_adapter failed: error %d\n", + __FUNCTION__, result); + + return result; + } + + if (!(dec->i2c_bus = dvb_register_i2c_bus(ttusb_dec_i2c_master_xfer, + dec, dec->adapter, 0))) { + printk("%s: dvb_register_i2c_bus failed\n", __FUNCTION__); + + dvb_unregister_adapter(dec->adapter); + + return -ENOMEM; + } + + dec->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING; + + dec->demux.priv = (void *)dec; + dec->demux.filternum = 31; + dec->demux.feednum = 31; + dec->demux.start_feed = ttusb_dec_start_feed; + dec->demux.stop_feed = ttusb_dec_stop_feed; + dec->demux.write_to_decoder = NULL; + + if ((result = dvb_dmx_init(&dec->demux)) < 0) { + printk("%s: dvb_dmx_init failed: error %d\n", __FUNCTION__, + result); + + dvb_unregister_i2c_bus(ttusb_dec_i2c_master_xfer, dec->adapter, + 0); + dvb_unregister_adapter(dec->adapter); + + return result; + } + + dec->dmxdev.filternum = 32; + dec->dmxdev.demux = &dec->demux.dmx; + dec->dmxdev.capabilities = 0; + + if ((result = dvb_dmxdev_init(&dec->dmxdev, dec->adapter)) < 0) { + printk("%s: dvb_dmxdev_init failed: error %d\n", + __FUNCTION__, result); + + dvb_dmx_release(&dec->demux); + dvb_unregister_i2c_bus(ttusb_dec_i2c_master_xfer, dec->adapter, + 0); + dvb_unregister_adapter(dec->adapter); + + return result; + } + + dec->frontend.source = DMX_FRONTEND_0; + + if ((result = dec->demux.dmx.add_frontend(&dec->demux.dmx, + &dec->frontend)) < 0) { + printk("%s: dvb_dmx_init failed: error %d\n", __FUNCTION__, + result); + + dvb_dmxdev_release(&dec->dmxdev); + dvb_dmx_release(&dec->demux); + dvb_unregister_i2c_bus(ttusb_dec_i2c_master_xfer, dec->adapter, + 0); + dvb_unregister_adapter(dec->adapter); + + return result; + } + + if ((result = dec->demux.dmx.connect_frontend(&dec->demux.dmx, + &dec->frontend)) < 0) { + printk("%s: dvb_dmx_init failed: error %d\n", __FUNCTION__, + result); + + dec->demux.dmx.remove_frontend(&dec->demux.dmx, &dec->frontend); + dvb_dmxdev_release(&dec->dmxdev); + dvb_dmx_release(&dec->demux); + dvb_unregister_i2c_bus(ttusb_dec_i2c_master_xfer, dec->adapter, + 0); + dvb_unregister_adapter(dec->adapter); + + return result; + } + + sema_init(&dec->pes2ts_sem, 1); + + dvb_net_init(dec->adapter, &dec->dvb_net, &dec->demux.dmx); + + return 0; +} + +static void ttusb_dec_exit_dvb(struct ttusb_dec *dec) +{ + dprintk("%s\n", __FUNCTION__); + + dvb_net_release(&dec->dvb_net); + dec->demux.dmx.close(&dec->demux.dmx); + dec->demux.dmx.remove_frontend(&dec->demux.dmx, &dec->frontend); + dvb_dmxdev_release(&dec->dmxdev); + dvb_dmx_release(&dec->demux); + dvb_unregister_i2c_bus(ttusb_dec_i2c_master_xfer, dec->adapter, 0); + dvb_unregister_adapter(dec->adapter); +} + +static void ttusb_dec_exit_usb(struct ttusb_dec *dec) +{ + int i; + + dprintk("%s\n", __FUNCTION__); + + dec->iso_stream_count = 0; + + for (i = 0; i < ISO_BUF_COUNT; i++) + usb_unlink_urb(dec->iso_urb[i]); + + ttusb_dec_free_iso_urbs(dec); +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +static void *ttusb_dec_probe(struct usb_device *udev, unsigned int ifnum, + const struct usb_device_id *id) +{ + struct ttusb_dec *dec; + + dprintk("%s\n", __FUNCTION__); + + if (ifnum != 0) + return NULL; + + if (!(dec = kmalloc(sizeof(struct ttusb_dec), GFP_KERNEL))) { + printk("%s: couldn't allocate memory.\n", __FUNCTION__); + return NULL; + } + + memset(dec, 0, sizeof(struct ttusb_dec)); + + dec->udev = udev; + + ttusb_dec_init_usb(dec); + ttusb_dec_init_stb(dec); + ttusb_dec_init_dvb(dec); + ttusb_dec_init_v_pes(dec); + + return (void *)dec; +} +#else +static int ttusb_dec_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_device *udev; + struct ttusb_dec *dec; + + dprintk("%s\n", __FUNCTION__); + + udev = interface_to_usbdev(intf); + + if (!(dec = kmalloc(sizeof(struct ttusb_dec), GFP_KERNEL))) { + printk("%s: couldn't allocate memory.\n", __FUNCTION__); + return -ENOMEM; + } + + memset(dec, 0, sizeof(struct ttusb_dec)); + + dec->udev = udev; + + ttusb_dec_init_usb(dec); + ttusb_dec_init_stb(dec); + ttusb_dec_init_dvb(dec); + ttusb_dec_init_v_pes(dec); + + usb_set_intfdata(intf, (void *)dec); + ttusb_dec_set_streaming_interface(dec); + + return 0; +} +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +static void ttusb_dec_disconnect(struct usb_device *udev, void *data) +{ + struct ttusb_dec *dec = data; +#else +static void ttusb_dec_disconnect(struct usb_interface *intf) +{ + struct ttusb_dec *dec = usb_get_intfdata(intf); + + usb_set_intfdata(intf, NULL); +#endif + + dprintk("%s\n", __FUNCTION__); + + ttusb_dec_exit_usb(dec); + ttusb_dec_exit_dvb(dec); + + kfree(dec); +} + +static struct usb_device_id ttusb_dec_table[] = { + {USB_DEVICE(0x0b48, 0x1006)}, /* Unconfirmed */ + {USB_DEVICE(0x0b48, 0x1007)}, /* Unconfirmed */ + {USB_DEVICE(0x0b48, 0x1008)}, /* DEC 2000 t */ + {} +}; + +static struct usb_driver ttusb_dec_driver = { + name: DRIVER_NAME, + probe: ttusb_dec_probe, + disconnect: ttusb_dec_disconnect, + id_table: ttusb_dec_table, +}; + +static int __init ttusb_dec_init(void) +{ + int result; + + if ((result = usb_register(&ttusb_dec_driver)) < 0) { + printk("%s: initialisation failed: error %d.\n", __FUNCTION__, + result); + return result; + } + + return 0; +} + +static void __exit ttusb_dec_exit(void) +{ + usb_deregister(&ttusb_dec_driver); +} + +module_init(ttusb_dec_init); +module_exit(ttusb_dec_exit); + +MODULE_AUTHOR("Alex Woods "); +MODULE_DESCRIPTION(DRIVER_NAME); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(usb, ttusb_dec_table); + +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Debug level"); diff -Nru a/drivers/media/dvb/ttusb-dec/ttusb_dec.h b/drivers/media/dvb/ttusb-dec/ttusb_dec.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/media/dvb/ttusb-dec/ttusb_dec.h Sun Jul 27 10:13:53 2003 @@ -0,0 +1,87 @@ +/* + * TTUSB DEC Driver + * + * Copyright (C) 2003 Alex Woods + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef _TTUSB_DEC_H +#define _TTUSB_DEC_H + +#include "asm/semaphore.h" +#include "dmxdev.h" +#include "dvb_demux.h" +#include "dvb_filter.h" +#include "dvb_i2c.h" +#include "dvb_net.h" + +#define DRIVER_NAME "TechnoTrend/Hauppauge DEC USB" + +#define COMMAND_PIPE 0x03 +#define RESULT_PIPE 0x84 +#define STREAM_PIPE 0x88 + +#define COMMAND_PACKET_SIZE 0x3c +#define ARM_PACKET_SIZE 0x1000 + +#define ISO_BUF_COUNT 0x04 +#define FRAMES_PER_ISO_BUF 0x04 +#define ISO_FRAME_SIZE 0x0380 + +#define MAX_AV_PES_LENGTH 6144 + +struct ttusb_dec { + /* DVB bits */ + struct dvb_adapter *adapter; + struct dmxdev dmxdev; + struct dvb_demux demux; + struct dmx_frontend frontend; + struct dvb_i2c_bus *i2c_bus; + struct dvb_net dvb_net; + + u16 pid[DMX_PES_OTHER]; + + /* USB bits */ + struct usb_device *udev; + u8 trans_count; + unsigned int command_pipe; + unsigned int result_pipe; + unsigned int stream_pipe; + int interface; + struct semaphore usb_sem; + + void *iso_buffer; + dma_addr_t iso_dma_handle; + struct urb *iso_urb[ISO_BUF_COUNT]; + int iso_stream_count; + struct semaphore iso_sem; + + u8 av_pes[MAX_AV_PES_LENGTH + 4]; + int av_pes_state; + int av_pes_length; + int av_pes_payload_length; + + struct dvb_filter_pes2ts a_pes2ts; + struct dvb_filter_pes2ts v_pes2ts; + struct semaphore pes2ts_sem; + + u8 v_pes[16 + MAX_AV_PES_LENGTH]; + int v_pes_length; + int v_pes_postbytes; +}; + +#endif diff -Nru a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig --- a/drivers/media/video/Kconfig Sun Jul 27 10:13:51 2003 +++ b/drivers/media/video/Kconfig Sun Jul 27 10:13:51 2003 @@ -257,5 +257,30 @@ whenever you want). If you want to compile it as a module, say M here and read . +config VIDEO_HEXIUM_ORION + tristate "Hexium HV-PCI6 and Orion frame grabber" + depends on VIDEO_DEV && PCI + ---help--- + This is a video4linux driver for the Hexium HV-PCI6 and + Orion frame grabber cards by Hexium. + + This driver is available as a module called hexium_orion + ( = code which can be inserted in and removed from the + running kernel whenever you want). If you want to compile + it as a module, say M here and read . + +config VIDEO_HEXIUM_GEMINI + tristate "Hexium Gemini frame grabber" + depends on VIDEO_DEV && PCI + ---help--- + This is a video4linux driver for the Hexium Gemini frame + grabber card by Hexium. Please note that the Gemini Dual + card is *not* fully supported. + + This driver is available as a module called hexium_gemini + ( = code which can be inserted in and removed from the + running kernel whenever you want). If you want to compile + it as a module, say M here and read . + endmenu diff -Nru a/drivers/media/video/Makefile b/drivers/media/video/Makefile --- a/drivers/media/video/Makefile Sun Jul 27 10:13:44 2003 +++ b/drivers/media/video/Makefile Sun Jul 27 10:13:44 2003 @@ -31,6 +31,8 @@ obj-$(CONFIG_VIDEO_MEYE) += meye.o obj-$(CONFIG_VIDEO_SAA7134) += saa7134/ obj-$(CONFIG_VIDEO_MXB) += saa7111.o tuner.o tda9840.o tea6415c.o tea6420.o mxb.o +obj-$(CONFIG_VIDEO_HEXIUM_ORION) += hexium_orion.o +obj-$(CONFIG_VIDEO_HEXIUM_GEMINI) += hexium_gemini.o obj-$(CONFIG_VIDEO_DPC) += saa7111.o dpc7146.o obj-$(CONFIG_TUNER_3036) += tuner-3036.o diff -Nru a/drivers/media/video/dpc7146.c b/drivers/media/video/dpc7146.c --- a/drivers/media/video/dpc7146.c Sun Jul 27 10:13:44 2003 +++ b/drivers/media/video/dpc7146.c Sun Jul 27 10:13:44 2003 @@ -173,6 +173,8 @@ return 0; } +static struct saa7146_ext_vv vv_data; + /* this function only gets called when the probing was successful */ static int dpc_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_data *info) { @@ -183,7 +185,7 @@ /* checking for i2c-devices can be omitted here, because we already did this in "dpc_vl42_probe" */ - saa7146_vv_init(dev); + saa7146_vv_init(dev,&vv_data); if( 0 != saa7146_register_device(&dpc->video_dev, dev, "dpc", VFL_TYPE_GRABBER)) { ERR(("cannot register capture v4l2 device. skipping.\n")); return -1; @@ -246,8 +248,9 @@ } #endif -static int dpc_ioctl(struct saa7146_dev *dev, unsigned int cmd, void *arg) +static int dpc_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) { + struct saa7146_dev *dev = fh->dev; struct dpc* dpc = (struct dpc*)dev->ext_priv; /* struct saa7146_vv *vv = dev->vv_data; @@ -307,23 +310,32 @@ } static struct saa7146_standard standard[] = { - { "PAL-BG", V4L2_STD_PAL_BG, SAA7146_PAL_VALUES }, - { "PAL-I", V4L2_STD_PAL_I, SAA7146_PAL_VALUES }, - { "NTSC", V4L2_STD_NTSC, SAA7146_NTSC_VALUES }, - { "SECAM", V4L2_STD_SECAM, SAA7146_SECAM_VALUES }, + { + .name = "PAL", .id = V4L2_STD_PAL, + .v_offset = 0x17, .v_field = 288, .v_calc = 576, + .h_offset = 0x14, .h_pixels = 680, .h_calc = 680+1, + .v_max_out = 576, .h_max_out = 768, + }, { + .name = "NTSC", .id = V4L2_STD_NTSC, + .v_offset = 0x16, .v_field = 240, .v_calc = 480, + .h_offset = 0x06, .h_pixels = 708, .h_calc = 708+1, + .v_max_out = 480, .h_max_out = 640, + }, { + .name = "SECAM", .id = V4L2_STD_SECAM, + .v_offset = 0x14, .v_field = 288, .v_calc = 576, + .h_offset = 0x14, .h_pixels = 720, .h_calc = 720+1, + .v_max_out = 576, .h_max_out = 768, + } }; -static -struct saa7146_extension extension; +static struct saa7146_extension extension; -static -struct saa7146_pci_extension_data dpc = { +static struct saa7146_pci_extension_data dpc = { .ext_priv = "Multimedia eXtension Board", .ext = &extension, }; -static -struct pci_device_id pci_tbl[] = { +static struct pci_device_id pci_tbl[] = { { .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7146, @@ -337,8 +349,7 @@ MODULE_DEVICE_TABLE(pci, pci_tbl); -static -struct saa7146_ext_vv vv_data = { +static struct saa7146_ext_vv vv_data = { .inputs = DPC_INPUTS, .capabilities = V4L2_CAP_VBI_CAPTURE, .stds = &standard[0], @@ -348,14 +359,12 @@ .ioctl = dpc_ioctl, }; -static -struct saa7146_extension extension = { +static struct saa7146_extension extension = { .name = "dpc7146 demonstration board", .flags = SAA7146_USE_I2C_IRQ, .pci_tbl = &pci_tbl[0], .module = THIS_MODULE, - .ext_vv_data = &vv_data, .probe = dpc_probe, .attach = dpc_attach, diff -Nru a/drivers/media/video/hexium.h b/drivers/media/video/hexium.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/media/video/hexium.h Sun Jul 27 10:13:53 2003 @@ -0,0 +1,51 @@ +#ifndef __HEXIUM__ +#define __HEXIUM__ + +#define HEXIUM_HV_PCI6_ORION 1 +#define HEXIUM_ORION_1SVHS_3BNC 2 +#define HEXIUM_ORION_4BNC 3 +#define HEXIUM_GEMUINI 4 +#define HEXIUM_GEMUINI_DUAL 5 + +static struct saa7146_standard hexium_standards[] = { + { + .name = "PAL", .id = V4L2_STD_PAL, + .v_offset = 0x17, .v_field = 288, .v_calc = 576, + .h_offset = 0x14, .h_pixels = 680, .h_calc = 680+1, + .v_max_out = 576, .h_max_out = 768, + }, { + .name = "NTSC", .id = V4L2_STD_NTSC, + .v_offset = 0x17, .v_field = 240, .v_calc = 480, + .h_offset = 0x06, .h_pixels = 640, .h_calc = 641+1, + .v_max_out = 480, .h_max_out = 640, + }, { + .name = "SECAM", .id = V4L2_STD_SECAM, + .v_offset = 0x14, .v_field = 288, .v_calc = 576, + .h_offset = 0x14, .h_pixels = 720, .h_calc = 720+1, + .v_max_out = 576, .h_max_out = 768, + } +}; + + +#define HEXIUM_INPUTS 9 +static struct v4l2_input hexium_inputs[HEXIUM_INPUTS] = { + { 0, "CVBS 1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 }, + { 1, "CVBS 2", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 }, + { 2, "CVBS 3", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 }, + { 3, "CVBS 4", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 }, + { 4, "CVBS 5", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 }, + { 5, "CVBS 6", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 }, + { 6, "Y/C 1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 }, + { 7, "Y/C 2", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 }, + { 8, "Y/C 3", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 }, +}; + +#define HEXIUM_AUDIOS 0 + +struct hexium_data +{ + s8 adr; + u8 byte; +}; + +#endif diff -Nru a/drivers/media/video/hexium_gemini.c b/drivers/media/video/hexium_gemini.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/media/video/hexium_gemini.c Sun Jul 27 10:13:53 2003 @@ -0,0 +1,411 @@ +/* + hexium_gemini.c - v4l2 driver for Hexium Gemini frame grabber cards + + Visit http://www.mihu.de/linux/saa7146/ and follow the link + to "hexium" for further details about this card. + + Copyright (C) 2003 Michael Hunold + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#define DEBUG_VARIABLE debug + +#include + +static int debug = 255; +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "debug verbosity"); + +/* global variables */ +int hexium_num = 0; + +#include "hexium_gemini.h" + +/* bring hardware to a sane state. this has to be done, just in case someone + wants to capture from this device before it has been properly initialized. + the capture engine would badly fail, because no valid signal arrives on the + saa7146, thus leading to timeouts and stuff. */ +static int hexium_init_done(struct saa7146_dev *dev) +{ + struct hexium *hexium = (struct hexium *) dev->ext_priv; + union i2c_smbus_data data; + int i = 0; + + DEB_D(("hexium_init_done called.\n")); + + /* initialize the helper ics to useful values */ + for (i = 0; i < sizeof(hexium_ks0127b); i++) { + data.byte = hexium_ks0127b[i]; + if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, i, I2C_SMBUS_BYTE_DATA, &data)) { + printk("failed for address 0x%02x\n", i); + } + } + + return 0; +} + +static int hexium_set_input(struct hexium *hexium, int input) +{ + union i2c_smbus_data data; + + DEB_D((".\n")); + + data.byte = hexium_input_select[input].byte; + if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, hexium_input_select[input].adr, I2C_SMBUS_BYTE_DATA, &data)) { + return -1; + } + + return 0; +} + +static int hexium_set_standard(struct hexium *hexium, struct hexium_data *vdec) +{ + union i2c_smbus_data data; + int i = 0; + + DEB_D((".\n")); + + while (vdec[i].adr != -1) { + data.byte = vdec[i].byte; + if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, vdec[i].adr, I2C_SMBUS_BYTE_DATA, &data)) { + printk("failed for address 0x%02x\n", i); + return -1; + } + i++; + } + return 0; +} + +static struct saa7146_ext_vv vv_data; + +/* this function only gets called when the probing was successful */ +static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info) +{ + struct hexium *hexium = (struct hexium *) dev->ext_priv; + + DEB_EE((".\n")); + + hexium = (struct hexium *) kmalloc(sizeof(struct hexium), GFP_KERNEL); + if (NULL == hexium) { + printk("hexium_v4l2.o: hexium_probe: not enough kernel memory.\n"); + return -ENOMEM; + } + memset(hexium, 0x0, sizeof(struct hexium)); + (struct hexium *) dev->ext_priv = hexium; + + /* FIXME: enable i2c-port pins, video-port-pins + video port pins should be enabled here ?! */ + saa7146_write(dev, MC1, (MASK_08 | MASK_24 | MASK_10 | MASK_26)); + + saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480); + if (i2c_add_adapter(&hexium->i2c_adapter) < 0) { + DEB_S(("cannot register i2c-device. skipping.\n")); + kfree(hexium); + return -EFAULT; + } + + /* set HWControl GPIO number 2 */ + saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI); + + saa7146_write(dev, DD1_INIT, 0x07000700); + saa7146_write(dev, DD1_STREAM_B, 0x00000000); + saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); + + /* the rest */ + hexium->cur_input = 0; + hexium_init_done(dev); + + hexium_set_standard(hexium, hexium_pal); + hexium->cur_std = V4L2_STD_PAL; + + hexium_set_input(hexium, 0); + hexium->cur_input = 0; + + saa7146_vv_init(dev, &vv_data); + if (0 != saa7146_register_device(&hexium->video_dev, dev, "hexium", VFL_TYPE_GRABBER)) { + ERR(("cannot register capture v4l2 device. skipping.\n")); + return -1; + } + + printk("hexium: found 'hexium frame grabber'-%d.\n", hexium_num); + hexium_num++; + + return 0; +} + +static int hexium_detach(struct saa7146_dev *dev) +{ + struct hexium *hexium = (struct hexium *) dev->ext_priv; + + DEB_EE(("dev:%p\n", dev)); + + saa7146_unregister_device(&hexium->video_dev, dev); + saa7146_vv_release(dev); + + hexium_num--; + + i2c_del_adapter(&hexium->i2c_adapter); + kfree(hexium); + return 0; +} + +static int hexium_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) +{ + struct saa7146_dev *dev = fh->dev; + struct hexium *hexium = (struct hexium *) dev->ext_priv; +/* + struct saa7146_vv *vv = dev->vv_data; +*/ + switch (cmd) { + case VIDIOC_ENUMINPUT: + { + struct v4l2_input *i = arg; + DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index)); + + if (i->index < 0 || i->index >= HEXIUM_INPUTS) { + return -EINVAL; + } + + memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input)); + + DEB_D(("v4l2_ioctl: VIDIOC_ENUMINPUT %d.\n", i->index)); + return 0; + } + case VIDIOC_G_INPUT: + { + int *input = (int *) arg; + *input = hexium->cur_input; + + DEB_D(("VIDIOC_G_INPUT: %d\n", *input)); + return 0; + } + case VIDIOC_S_INPUT: + { + int input = *(int *) arg; + + DEB_EE(("VIDIOC_S_INPUT %d.\n", input)); + + if (input < 0 || input >= HEXIUM_INPUTS) { + return -EINVAL; + } + + hexium->cur_input = input; + hexium_set_input(hexium, input); + + return 0; + } + /* the saa7146 provides some controls (brightness, contrast, saturation) + which gets registered *after* this function. because of this we have + to return with a value != 0 even if the function succeded.. */ + case VIDIOC_QUERYCTRL: + { + struct v4l2_queryctrl *qc = arg; + int i; + + for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) { + if (hexium_controls[i].id == qc->id) { + *qc = hexium_controls[i]; + DEB_D(("VIDIOC_QUERYCTRL %d.\n", qc->id)); + return 0; + } + } + return -EAGAIN; + } + case VIDIOC_G_CTRL: + { + struct v4l2_control *vc = arg; + int i; + + for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) { + if (hexium_controls[i].id == vc->id) { + break; + } + } + + if (i < 0) { + return -EAGAIN; + } + + switch (vc->id) { + case V4L2_CID_PRIVATE_BASE:{ + vc->value = hexium->cur_bw; + DEB_D(("VIDIOC_G_CTRL BW:%d.\n", vc->value)); + return 0; + } + } + return -EINVAL; + } + + case VIDIOC_S_CTRL: + { + struct v4l2_control *vc = arg; + int i = 0; + + for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) { + if (hexium_controls[i].id == vc->id) { + break; + } + } + + if (i < 0) { + return -EAGAIN; + } + + switch (vc->id) { + case V4L2_CID_PRIVATE_BASE:{ + hexium->cur_bw = vc->value; + break; + } + } + + DEB_D(("VIDIOC_S_CTRL BW:%d.\n", hexium->cur_bw)); + + if (0 == hexium->cur_bw && V4L2_STD_PAL == hexium->cur_std) { + hexium_set_standard(hexium, hexium_pal); + return 0; + } + if (0 == hexium->cur_bw && V4L2_STD_NTSC == hexium->cur_std) { + hexium_set_standard(hexium, hexium_ntsc); + return 0; + } + if (0 == hexium->cur_bw && V4L2_STD_SECAM == hexium->cur_std) { + hexium_set_standard(hexium, hexium_secam); + return 0; + } + if (1 == hexium->cur_bw && V4L2_STD_PAL == hexium->cur_std) { + hexium_set_standard(hexium, hexium_pal_bw); + return 0; + } + if (1 == hexium->cur_bw && V4L2_STD_NTSC == hexium->cur_std) { + hexium_set_standard(hexium, hexium_ntsc_bw); + return 0; + } + if (1 == hexium->cur_bw && V4L2_STD_SECAM == hexium->cur_std) { + /* fixme: is there no bw secam mode? */ + return -EINVAL; + } + + return -EINVAL; + } + default: +/* + DEB_D(("v4l2_ioctl does not handle this ioctl.\n")); +*/ + return -ENOIOCTLCMD; + } + return 0; +} + +static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *std) +{ + struct hexium *hexium = (struct hexium *) dev->ext_priv; + + if (V4L2_STD_PAL == std->id) { + hexium_set_standard(hexium, hexium_pal); + hexium->cur_std = V4L2_STD_PAL; + return 0; + } else if (V4L2_STD_NTSC == std->id) { + hexium_set_standard(hexium, hexium_ntsc); + hexium->cur_std = V4L2_STD_NTSC; + return 0; + } else if (V4L2_STD_SECAM == std->id) { + hexium_set_standard(hexium, hexium_secam); + hexium->cur_std = V4L2_STD_SECAM; + return 0; + } + + return -1; +} + +static struct saa7146_extension hexium_extension; + +static struct saa7146_pci_extension_data hexium_gemini_4bnc = { + .ext_priv = "Hexium Gemini (4 BNC)", + .ext = &hexium_extension, +}; + +static struct saa7146_pci_extension_data hexium_gemini_dual_4bnc = { + .ext_priv = "Hexium Gemini Dual (4 BNC)", + .ext = &hexium_extension, +}; + +static struct pci_device_id pci_tbl[] = { + { + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7146, + .subvendor = 0x17c8, + .subdevice = 0x2401, + .driver_data = (unsigned long) &hexium_gemini_4bnc, + }, + { + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7146, + .subvendor = 0x17c8, + .subdevice = 0x2402, + .driver_data = (unsigned long) &hexium_gemini_dual_4bnc, + }, + { + .vendor = 0, + } +}; + +MODULE_DEVICE_TABLE(pci, pci_tbl); + +static struct saa7146_ext_vv vv_data = { + .inputs = HEXIUM_INPUTS, + .capabilities = 0, + .stds = &hexium_standards[0], + .num_stds = sizeof(hexium_standards) / sizeof(struct saa7146_standard), + .std_callback = &std_callback, + .ioctls = &ioctls[0], + .ioctl = hexium_ioctl, +}; + +static struct saa7146_extension hexium_extension = { + .name = "hexium gemini", + .flags = SAA7146_USE_I2C_IRQ, + + .pci_tbl = &pci_tbl[0], + .module = THIS_MODULE, + + .attach = hexium_attach, + .detach = hexium_detach, + + .irq_mask = 0, + .irq_func = NULL, +}; + +int __init hexium_init_module(void) +{ + if (0 != saa7146_register_extension(&hexium_extension)) { + DEB_S(("failed to register extension.\n")); + return -ENODEV; + } + + return 0; +} + +void __exit hexium_cleanup_module(void) +{ + saa7146_unregister_extension(&hexium_extension); +} + +module_init(hexium_init_module); +module_exit(hexium_cleanup_module); + +MODULE_DESCRIPTION("video4linux-2 driver for Hexium Gemini frame grabber cards"); +MODULE_AUTHOR("Michael Hunold "); +MODULE_LICENSE("GPL"); diff -Nru a/drivers/media/video/hexium_gemini.h b/drivers/media/video/hexium_gemini.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/media/video/hexium_gemini.h Sun Jul 27 10:13:53 2003 @@ -0,0 +1,103 @@ +#ifndef __HEXIUM_GEMINI__ +#define __HEXIUM_GEMINI__ + +#include "hexium.h" + +static struct saa7146_extension_ioctls ioctls[] = { + { VIDIOC_G_INPUT, SAA7146_EXCLUSIVE }, + { VIDIOC_S_INPUT, SAA7146_EXCLUSIVE }, + { VIDIOC_QUERYCTRL, SAA7146_BEFORE }, + { VIDIOC_ENUMINPUT, SAA7146_EXCLUSIVE }, + { VIDIOC_S_STD, SAA7146_AFTER }, + { VIDIOC_G_CTRL, SAA7146_BEFORE }, + { VIDIOC_S_CTRL, SAA7146_BEFORE }, + { 0, 0 } +}; + +#define HEXIUM_CONTROLS 1 +static struct v4l2_queryctrl hexium_controls[] = { + { V4L2_CID_PRIVATE_BASE, V4L2_CTRL_TYPE_BOOLEAN, "B/W", 0, 1, 1, 0, 0 }, +}; + +#define HEXIUM_GEMUINI_V_1_0 1 +#define HEXIUM_GEMUINI_DUAL_V_1_0 2 + +struct hexium +{ + int type; + struct video_device video_dev; + struct i2c_adapter i2c_adapter; + + int cur_input; /* current input */ + v4l2_std_id cur_std; /* current standard */ + int cur_bw; /* current black/white status */ +}; + +/* Samsung KS0127B decoder default registers */ +static u8 hexium_ks0127b[0x100]={ +/*00*/ 0x00,0x52,0x30,0x40,0x01,0x0C,0x2A,0x10, +/*08*/ 0x00,0x00,0x00,0x60,0x00,0x00,0x0F,0x06, +/*10*/ 0x00,0x00,0xE4,0xC0,0x00,0x00,0x00,0x00, +/*18*/ 0x14,0x9B,0xFE,0xFF,0xFC,0xFF,0x03,0x22, +/*20*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*28*/ 0x00,0x00,0x00,0x00,0x00,0x2C,0x9B,0x00, +/*30*/ 0x00,0x00,0x10,0x80,0x80,0x10,0x80,0x80, +/*38*/ 0x01,0x04,0x00,0x00,0x00,0x29,0xC0,0x00, +/*40*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*48*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*50*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*58*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*60*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*68*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*70*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*78*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*80*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*88*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*90*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*98*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*A0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*A8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*B0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*B8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*C0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*C8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*D0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*D8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*E0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*E8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*F0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*F8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +}; + +static struct hexium_data hexium_pal[] = { + { 0x01, 0x52 }, { 0x12, 0x64 }, { 0x2D, 0x2C }, { 0x2E, 0x9B }, { -1 , 0xFF } +}; + +static struct hexium_data hexium_pal_bw[] = { + { 0x01, 0x52 }, { 0x12, 0x64 }, { 0x2D, 0x2C }, { 0x2E, 0x9B }, { -1 , 0xFF } +}; + +static struct hexium_data hexium_ntsc[] = { + { 0x01, 0x53 }, { 0x12, 0x04 }, { 0x2D, 0x23 }, { 0x2E, 0x81 }, { -1 , 0xFF } +}; + +static struct hexium_data hexium_ntsc_bw[] = { + { 0x01, 0x53 }, { 0x12, 0x04 }, { 0x2D, 0x23 }, { 0x2E, 0x81 }, { -1 , 0xFF } +}; + +static struct hexium_data hexium_secam[] = { + { 0x01, 0x52 }, { 0x12, 0x64 }, { 0x2D, 0x2C }, { 0x2E, 0x9B }, { -1 , 0xFF } +}; + +static struct hexium_data hexium_input_select[] = { + { 0x02, 0x60 }, + { 0x02, 0x64 }, + { 0x02, 0x61 }, + { 0x02, 0x65 }, + { 0x02, 0x62 }, + { 0x02, 0x66 }, + { 0x02, 0x68 }, + { 0x02, 0x69 }, + { 0x02, 0x6A }, +}; +#endif diff -Nru a/drivers/media/video/hexium_orion.c b/drivers/media/video/hexium_orion.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/media/video/hexium_orion.c Sun Jul 27 10:13:52 2003 @@ -0,0 +1,328 @@ +/* + hexium_orion.c - v4l2 driver for the Hexium Orion frame grabber cards + + Visit http://www.mihu.de/linux/saa7146/ and follow the link + to "hexium" for further details about this card. + + Copyright (C) 2003 Michael Hunold + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#define DEBUG_VARIABLE debug + +#include + +static int debug = 255; +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "debug verbosity"); + +/* global variables */ +int hexium_num = 0; + +#include "hexium_orion.h" + +/* this is only called for old HV-PCI6/Orion cards + without eeprom */ +static int hexium_probe(struct saa7146_dev *dev) +{ + struct hexium *hexium = 0; + union i2c_smbus_data data; + int err = 0; + + DEB_EE((".\n")); + + /* there are no hexium orion cards with revision 0 saa7146s */ + if (0 == dev->revision) { + return -EFAULT; + } + + hexium = (struct hexium *) kmalloc(sizeof(struct hexium), GFP_KERNEL); + if (NULL == hexium) { + printk("hexium_orion.o: hexium_probe: not enough kernel memory.\n"); + return -ENOMEM; + } + memset(hexium, 0x0, sizeof(struct hexium)); + + /* FIXME: enable i2c-port pins, video-port-pins + video port pins should be enabled here ?! */ + saa7146_write(dev, MC1, (MASK_08 | MASK_24 | MASK_10 | MASK_26)); + + saa7146_write(dev, DD1_INIT, 0x02000200); + saa7146_write(dev, DD1_STREAM_B, 0x00000000); + saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); + + saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480); + if (i2c_add_adapter(&hexium->i2c_adapter) < 0) { + DEB_S(("cannot register i2c-device. skipping.\n")); + kfree(hexium); + return -EFAULT; + } + + /* set SAA7110 control GPIO 0 */ + saa7146_setgpio(dev, 0, SAA7146_GPIO_OUTHI); + /* set HWControl GPIO number 2 */ + saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI); + + mdelay(10); + + /* detect newer Hexium Orion cards by subsystem ids */ + if (0x17c8 == dev->pci->subsystem_vendor && 0x0101 == dev->pci->subsystem_device) { + printk("hexium_orion.o: device is a Hexium Orion w/ 1 SVHS + 3 BNC inputs.\n"); + /* we store the pointer in our private data field */ + (struct hexium *) dev->ext_priv = hexium; + hexium->type = HEXIUM_ORION_1SVHS_3BNC; + return 0; + } + + if (0x17c8 == dev->pci->subsystem_vendor && 0x2101 == dev->pci->subsystem_device) { + printk("hexium_orion.o: device is a Hexium Orion w/ 4 BNC inputs.\n"); + /* we store the pointer in our private data field */ + (struct hexium *) dev->ext_priv = hexium; + hexium->type = HEXIUM_ORION_4BNC; + return 0; + } + + /* check if this is an old hexium Orion card by looking at + a saa7110 at address 0x4e */ + if (0 == (err = i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_READ, 0x00, I2C_SMBUS_BYTE_DATA, &data))) { + printk("hexium_orion.o: device is a Hexium HV-PCI6/Orion (old).\n"); + /* we store the pointer in our private data field */ + (struct hexium *) dev->ext_priv = hexium; + hexium->type = HEXIUM_HV_PCI6_ORION; + return 0; + } + + i2c_del_adapter(&hexium->i2c_adapter); + kfree(hexium); + return -EFAULT; +} + +/* bring hardware to a sane state. this has to be done, just in case someone + wants to capture from this device before it has been properly initialized. + the capture engine would badly fail, because no valid signal arrives on the + saa7146, thus leading to timeouts and stuff. */ +static int hexium_init_done(struct saa7146_dev *dev) +{ + struct hexium *hexium = (struct hexium *) dev->ext_priv; + union i2c_smbus_data data; + int i = 0; + + DEB_D(("hexium_init_done called.\n")); + + /* initialize the helper ics to useful values */ + for (i = 0; i < sizeof(hexium_saa7110); i++) { + data.byte = hexium_saa7110[i]; + if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_WRITE, i, I2C_SMBUS_BYTE_DATA, &data)) { + printk("hexium_orion: failed for address 0x%02x\n", i); + } + } + + return 0; +} + +static struct saa7146_ext_vv vv_data; + +/* this function only gets called when the probing was successful */ +static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info) +{ + struct hexium *hexium = (struct hexium *) dev->ext_priv; + + DEB_EE((".\n")); + + saa7146_vv_init(dev, &vv_data); + if (0 != saa7146_register_device(&hexium->video_dev, dev, "hexium", VFL_TYPE_GRABBER)) { + ERR(("cannot register capture v4l2 device. skipping.\n")); + return -1; + } + + printk("hexium_orion.o: found 'hexium orion' frame grabber-%d.\n", hexium_num); + hexium_num++; + + /* the rest */ + hexium->cur_input = 0; + hexium_init_done(dev); + + return 0; +} + +static int hexium_detach(struct saa7146_dev *dev) +{ + struct hexium *hexium = (struct hexium *) dev->ext_priv; + + DEB_EE(("dev:%p\n", dev)); + + saa7146_unregister_device(&hexium->video_dev, dev); + saa7146_vv_release(dev); + + hexium_num--; + + i2c_del_adapter(&hexium->i2c_adapter); + kfree(hexium); + return 0; +} + +static int hexium_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) +{ + struct saa7146_dev *dev = fh->dev; + struct hexium *hexium = (struct hexium *) dev->ext_priv; +/* + struct saa7146_vv *vv = dev->vv_data; +*/ + switch (cmd) { + case VIDIOC_ENUMINPUT: + { + struct v4l2_input *i = arg; + DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index)); + + if (i->index < 0 || i->index >= HEXIUM_INPUTS) { + return -EINVAL; + } + + memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input)); + + DEB_D(("v4l2_ioctl: VIDIOC_ENUMINPUT %d.\n", i->index)); + return 0; + } + case VIDIOC_G_INPUT: + { + int *input = (int *) arg; + *input = hexium->cur_input; + + DEB_D(("VIDIOC_G_INPUT: %d\n", *input)); + return 0; + } + case VIDIOC_S_INPUT: + { + int input = *(int *) arg; + + if (input < 0 || input >= HEXIUM_INPUTS) { + return -EINVAL; + } + + hexium->cur_input = input; + + /* fixme: switch input here, switch audio, too! */ +// saa7146_set_hps_source_and_sync(dev, input_port_selection[input].hps_source, input_port_selection[input].hps_sync); + printk("hexium_orion.o: VIDIOC_S_INPUT: fixme switch input.\n"); + + return 0; + } + default: +/* + DEB_D(("v4l2_ioctl does not handle this ioctl.\n")); +*/ + return -ENOIOCTLCMD; + } + return 0; +} + +static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *std) +{ + return 0; +} + +static struct saa7146_extension extension; + +static struct saa7146_pci_extension_data hexium_hv_pci6 = { + .ext_priv = "Hexium HV-PCI6 / Orion", + .ext = &extension, +}; + +static struct saa7146_pci_extension_data hexium_orion_1svhs_3bnc = { + .ext_priv = "Hexium HV-PCI6 / Orion (1 SVHS/3 BNC)", + .ext = &extension, +}; + +static struct saa7146_pci_extension_data hexium_orion_4bnc = { + .ext_priv = "Hexium HV-PCI6 / Orion (4 BNC)", + .ext = &extension, +}; + +static struct pci_device_id pci_tbl[] = { + { + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7146, + .subvendor = 0x0000, + .subdevice = 0x0000, + .driver_data = (unsigned long) &hexium_hv_pci6, + }, + { + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7146, + .subvendor = 0x17c8, + .subdevice = 0x0101, + .driver_data = (unsigned long) &hexium_orion_1svhs_3bnc, + }, + { + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7146, + .subvendor = 0x17c8, + .subdevice = 0x2101, + .driver_data = (unsigned long) &hexium_orion_4bnc, + }, + { + .vendor = 0, + } +}; + +MODULE_DEVICE_TABLE(pci, pci_tbl); + +static struct saa7146_ext_vv vv_data = { + .inputs = HEXIUM_INPUTS, + .capabilities = 0, + .stds = &hexium_standards[0], + .num_stds = sizeof(hexium_standards) / sizeof(struct saa7146_standard), + .std_callback = &std_callback, + .ioctls = &ioctls[0], + .ioctl = hexium_ioctl, +}; + +static struct saa7146_extension extension = { + .name = "hexium HV-PCI6/Orion", + .flags = 0, // SAA7146_USE_I2C_IRQ, + + .pci_tbl = &pci_tbl[0], + .module = THIS_MODULE, + + .probe = hexium_probe, + .attach = hexium_attach, + .detach = hexium_detach, + + .irq_mask = 0, + .irq_func = NULL, +}; + +int __init hexium_init_module(void) +{ + if (0 != saa7146_register_extension(&extension)) { + DEB_S(("failed to register extension.\n")); + return -ENODEV; + } + + return 0; +} + +void __exit hexium_cleanup_module(void) +{ + saa7146_unregister_extension(&extension); +} + +module_init(hexium_init_module); +module_exit(hexium_cleanup_module); + +MODULE_DESCRIPTION("video4linux-2 driver for Hexium Orion frame grabber cards"); +MODULE_AUTHOR("Michael Hunold "); +MODULE_LICENSE("GPL"); diff -Nru a/drivers/media/video/hexium_orion.h b/drivers/media/video/hexium_orion.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/media/video/hexium_orion.h Sun Jul 27 10:13:53 2003 @@ -0,0 +1,138 @@ +#ifndef __HEXIUM_ORION__ +#define __HEXIUM_ORION__ + +#include "hexium.h" + +static struct saa7146_extension_ioctls ioctls[] = { + { VIDIOC_G_INPUT, SAA7146_EXCLUSIVE }, + { VIDIOC_S_INPUT, SAA7146_EXCLUSIVE }, + { VIDIOC_ENUMINPUT, SAA7146_EXCLUSIVE }, + { VIDIOC_S_STD, SAA7146_AFTER }, + { 0, 0 } +}; + +struct hexium +{ + int type; + struct video_device video_dev; + struct i2c_adapter i2c_adapter; + int cur_input; /* current input */ +}; + +/* Philips SAA7110 decoder default registers */ +static u8 hexium_saa7110[53]={ +/*00*/ 0x4C,0x3C,0x0D,0xEF,0xBD,0xF0,0x00,0x00, +/*08*/ 0xF8,0xF8,0x60,0x60,0x40,0x86,0x18,0x90, +/*10*/ 0x00,0x2C,0x40,0x46,0x42,0x1A,0xFF,0xDA, +/*18*/ 0xF0,0x8B,0x00,0x00,0x00,0x00,0x00,0x00, +/*20*/ 0xD9,0x17,0x40,0x41,0x80,0x41,0x80,0x4F, +/*28*/ 0xFE,0x01,0x0F,0x0F,0x03,0x01,0x81,0x03, +/*30*/ 0x44,0x75,0x01,0x8C,0x03 +}; + +static struct { + struct hexium_data data[8]; +} hexium_input_select[] = { +{ + { /* input 0 */ + { 0x06, 0x00 }, + { 0x20, 0xD9 }, + { 0x21, 0x17 }, // 0x16, + { 0x22, 0x40 }, + { 0x2C, 0x03 }, + { 0x30, 0x44 }, + { 0x31, 0x75 }, // ?? + { 0x21, 0x16 }, // 0x03, + } +}, { + { /* input 1 */ + { 0x06, 0x00 }, + { 0x20, 0xD8 }, + { 0x21, 0x17 }, // 0x16, + { 0x22, 0x40 }, + { 0x2C, 0x03 }, + { 0x30, 0x44 }, + { 0x31, 0x75 }, // ?? + { 0x21, 0x16 }, // 0x03, + } +}, { + { /* input 2 */ + { 0x06, 0x00 }, + { 0x20, 0xBA }, + { 0x21, 0x07 }, // 0x05, + { 0x22, 0x91 }, + { 0x2C, 0x03 }, + { 0x30, 0x60 }, + { 0x31, 0xB5 }, // ?? + { 0x21, 0x05 }, // 0x03, + } +}, { + { /* input 3 */ + { 0x06, 0x00 }, + { 0x20, 0xB8 }, + { 0x21, 0x07 }, // 0x05, + { 0x22, 0x91 }, + { 0x2C, 0x03 }, + { 0x30, 0x60 }, + { 0x31, 0xB5 }, // ?? + { 0x21, 0x05 }, // 0x03, + } +}, { + { /* input 4 */ + { 0x06, 0x00 }, + { 0x20, 0x7C }, + { 0x21, 0x07 }, // 0x03 + { 0x22, 0xD2 }, + { 0x2C, 0x83 }, + { 0x30, 0x60 }, + { 0x31, 0xB5 }, // ?? + { 0x21, 0x03 }, + } +}, { + { /* input 5 */ + { 0x06, 0x00 }, + { 0x20, 0x78 }, + { 0x21, 0x07 }, // 0x03, + { 0x22, 0xD2 }, + { 0x2C, 0x83 }, + { 0x30, 0x60 }, + { 0x31, 0xB5 }, // ? + { 0x21, 0x03 }, + } +}, { + { /* input 6 */ + { 0x06, 0x80 }, + { 0x20, 0x59 }, + { 0x21, 0x17 }, + { 0x22, 0x42 }, + { 0x2C, 0xA3 }, + { 0x30, 0x44 }, + { 0x31, 0x75 }, + { 0x21, 0x12 }, + } +}, { + { /* input 7 */ + { 0x06, 0x80 }, + { 0x20, 0x9A }, + { 0x21, 0x17 }, + { 0x22, 0xB1 }, + { 0x2C, 0x13 }, + { 0x30, 0x60 }, + { 0x31, 0xB5 }, + { 0x21, 0x14 }, + } +}, { + { /* input 8 */ + { 0x06, 0x80 }, + { 0x20, 0x3C }, + { 0x21, 0x27 }, + { 0x22, 0xC1 }, + { 0x2C, 0x23 }, + { 0x30, 0x44 }, + { 0x31, 0x75 }, + { 0x21, 0x21 }, + } +} +}; + +#endif diff -Nru a/drivers/media/video/mxb.c b/drivers/media/video/mxb.c --- a/drivers/media/video/mxb.c Sun Jul 27 10:13:40 2003 +++ b/drivers/media/video/mxb.c Sun Jul 27 10:13:40 2003 @@ -81,7 +81,7 @@ enum { TUNER, AUX1, AUX3, AUX3_YC }; static struct v4l2_input mxb_inputs[MXB_INPUTS] = { - { TUNER, "Tuner", V4L2_INPUT_TYPE_TUNER, 1, 1, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 }, + { TUNER, "Tuner", V4L2_INPUT_TYPE_TUNER, 1, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 }, { AUX1, "AUX1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 }, { AUX3, "AUX3 Composite", V4L2_INPUT_TYPE_CAMERA, 4, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 }, { AUX3_YC, "AUX3 S-Video", V4L2_INPUT_TYPE_CAMERA, 4, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 }, @@ -101,8 +101,8 @@ /* this array holds the information of the audio source (mxb_audios), which has to be switched corresponding to the video source (mxb_channels) */ -static int video_audio_connect[MXB_AUDIOS] = - { 0, 1, 2, 3, 3 }; +static int video_audio_connect[MXB_INPUTS] = + { 0, 1, 3, 3 }; /* these are the necessary input-output-pins for bringing one audio source (see above) to the CD-output */ @@ -173,8 +173,7 @@ int cur_mute; /* current mute status */ }; -static -struct saa7146_extension extension; +static struct saa7146_extension extension; static int mxb_vbi_bypass(struct saa7146_dev* dev) { @@ -431,10 +430,11 @@ polling method ... */ extension.flags &= ~SAA7146_USE_I2C_IRQ; for(i = 1;;i++) { - msg.len = mxb_saa7740_init[i].length; - if (msg.len == -1U) { + if( -1 == mxb_saa7740_init[i].length ) { break; } + + msg.len = mxb_saa7740_init[i].length; msg.buf = &mxb_saa7740_init[i].data[0]; if( 1 != (err = i2c_transfer(&mxb->i2c_adapter, &msg, 1))) { DEB_D(("failed to initialize 'sound arena module'.\n")); @@ -472,6 +472,8 @@ } */ +static struct saa7146_ext_vv vv_data; + /* this function only gets called when the probing was successful */ static int mxb_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_data *info) { @@ -482,7 +484,7 @@ /* checking for i2c-devices can be omitted here, because we already did this in "mxb_vl42_probe" */ - saa7146_vv_init(dev); + saa7146_vv_init(dev,&vv_data); if( 0 != saa7146_register_device(&mxb->video_dev, dev, "mxb", VFL_TYPE_GRABBER)) { ERR(("cannot register capture v4l2 device. skipping.\n")); return -1; @@ -566,8 +568,9 @@ return 0; } -static int mxb_ioctl(struct saa7146_dev *dev, unsigned int cmd, void *arg) +static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) { + struct saa7146_dev *dev = fh->dev; struct mxb* mxb = (struct mxb*)dev->ext_priv; struct saa7146_vv *vv = dev->vv_data; @@ -1002,20 +1005,35 @@ } static struct saa7146_standard standard[] = { - { "PAL-BG", V4L2_STD_PAL_BG, SAA7146_PAL_VALUES }, - { "PAL-I", V4L2_STD_PAL_I, SAA7146_PAL_VALUES }, - { "NTSC", V4L2_STD_NTSC, SAA7146_NTSC_VALUES }, - { "SECAM", V4L2_STD_SECAM, SAA7146_SECAM_VALUES }, + { + .name = "PAL-BG", .id = V4L2_STD_PAL_BG, + .v_offset = 0x17, .v_field = 288, .v_calc = 576, + .h_offset = 0x14, .h_pixels = 680, .h_calc = 680+1, + .v_max_out = 576, .h_max_out = 768, + }, { + .name = "PAL-I", .id = V4L2_STD_PAL_I, + .v_offset = 0x17, .v_field = 288, .v_calc = 576, + .h_offset = 0x14, .h_pixels = 680, .h_calc = 680+1, + .v_max_out = 576, .h_max_out = 768, + }, { + .name = "NTSC", .id = V4L2_STD_NTSC, + .v_offset = 0x16, .v_field = 240, .v_calc = 480, + .h_offset = 0x06, .h_pixels = 708, .h_calc = 708+1, + .v_max_out = 480, .h_max_out = 640, + }, { + .name = "SECAM", .id = V4L2_STD_SECAM, + .v_offset = 0x14, .v_field = 288, .v_calc = 576, + .h_offset = 0x14, .h_pixels = 720, .h_calc = 720+1, + .v_max_out = 576, .h_max_out = 768, + } }; -static -struct saa7146_pci_extension_data mxb = { +static struct saa7146_pci_extension_data mxb = { .ext_priv = "Multimedia eXtension Board", .ext = &extension, }; -static -struct pci_device_id pci_tbl[] = { +static struct pci_device_id pci_tbl[] = { { .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7146, @@ -1029,8 +1047,7 @@ MODULE_DEVICE_TABLE(pci, pci_tbl); -static -struct saa7146_ext_vv vv_data = { +static struct saa7146_ext_vv vv_data = { .inputs = MXB_INPUTS, .capabilities = V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE, .stds = &standard[0], @@ -1040,14 +1057,12 @@ .ioctl = mxb_ioctl, }; -static -struct saa7146_extension extension = { +static struct saa7146_extension extension = { .name = MXB_IDENTIFIER, .flags = SAA7146_USE_I2C_IRQ, .pci_tbl = &pci_tbl[0], .module = THIS_MODULE, - .ext_vv_data = &vv_data, .probe = mxb_probe, .attach = mxb_attach, diff -Nru a/drivers/media/video/pms.c b/drivers/media/video/pms.c --- a/drivers/media/video/pms.c Sun Jul 27 10:13:50 2003 +++ b/drivers/media/video/pms.c Sun Jul 27 10:13:50 2003 @@ -12,6 +12,10 @@ * Most of this code is directly derived from his userspace driver. * His driver works so send any reports to alan@redhat.com unless the * userspace driver also doesn't work for you... + * + * Changes: + * 08/07/2003 Daniele Bellucci + * - pms_capture: report back -EFAULT */ #include @@ -659,7 +663,8 @@ if(dt+len>count) dt=count-len; cnt += dev->height; - copy_to_user(buf, tmp+32, dt); + if (copy_to_user(buf, tmp+32, dt)) + return -EFAULT; buf += dt; len += dt; } diff -Nru a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c --- a/drivers/message/fusion/mptctl.c Sun Jul 27 10:13:40 2003 +++ b/drivers/message/fusion/mptctl.c Sun Jul 27 10:13:40 2003 @@ -88,7 +88,6 @@ #include /* needed for access to Scsi_Host struct */ #include -#include /* for io_request_lock (spinlock) decl */ #include "../../scsi/scsi.h" #include "../../scsi/hosts.h" diff -Nru a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c --- a/drivers/message/fusion/mptscsih.c Sun Jul 27 10:13:44 2003 +++ b/drivers/message/fusion/mptscsih.c Sun Jul 27 10:13:44 2003 @@ -72,7 +72,6 @@ #include #include #include -#include /* for io_request_lock (spinlock) decl */ #include /* for mdelay */ #include /* needed for in_interrupt() proto */ #include /* notifier code */ diff -Nru a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c --- a/drivers/message/i2o/i2o_block.c Sun Jul 27 10:13:49 2003 +++ b/drivers/message/i2o/i2o_block.c Sun Jul 27 10:13:49 2003 @@ -87,8 +87,6 @@ #define MAJOR_NR I2O_MAJOR -#include - #define MAX_I2OB 16 #define MAX_I2OB_DEPTH 8 diff -Nru a/drivers/message/i2o/i2o_scsi.c b/drivers/message/i2o/i2o_scsi.c --- a/drivers/message/i2o/i2o_scsi.c Sun Jul 27 10:13:50 2003 +++ b/drivers/message/i2o/i2o_scsi.c Sun Jul 27 10:13:50 2003 @@ -54,7 +54,7 @@ #include #include #include -#include +#include #include #include "../../scsi/scsi.h" #include "../../scsi/hosts.h" diff -Nru a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c --- a/drivers/mtd/mtd_blkdevs.c Sun Jul 27 10:13:40 2003 +++ b/drivers/mtd/mtd_blkdevs.c Sun Jul 27 10:13:40 2003 @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff -Nru a/drivers/net/8139too.c b/drivers/net/8139too.c --- a/drivers/net/8139too.c Sun Jul 27 10:13:39 2003 +++ b/drivers/net/8139too.c Sun Jul 27 10:13:39 2003 @@ -110,6 +110,7 @@ #include #include #include +#include #include #include @@ -1597,6 +1598,9 @@ timeout = next_tick; do { timeout = interruptible_sleep_on_timeout (&tp->thr_wait, timeout); + /* make swsusp happy with our thread */ + if (current->flags & PF_FREEZE) + refrigerator(PF_IOTHREAD); } while (!signal_pending (current) && (timeout > 0)); if (signal_pending (current)) { diff -Nru a/drivers/net/8390.h b/drivers/net/8390.h --- a/drivers/net/8390.h Sun Jul 27 10:13:49 2003 +++ b/drivers/net/8390.h Sun Jul 27 10:13:49 2003 @@ -110,7 +110,7 @@ */ #if defined(CONFIG_MAC) || \ - defined(CONFIG_ARIADNE2) || defined(CONFIG_ARIADNE2_MODULE) || \ + defined(CONFIG_ZORRO8390) || defined(CONFIG_ZORRO8390_MODULE) || \ defined(CONFIG_HYDRA) || defined(CONFIG_HYDRA_MODULE) #define EI_SHIFT(x) (ei_local->reg_offset[x]) #undef inb diff -Nru a/drivers/net/Kconfig b/drivers/net/Kconfig --- a/drivers/net/Kconfig Sun Jul 27 10:13:50 2003 +++ b/drivers/net/Kconfig Sun Jul 27 10:13:50 2003 @@ -282,23 +282,6 @@ want). The module is called ariadne. If you want to compile it as a module, say M here and read . -config ARIADNE2 - tristate "Ariadne II support" - depends on NETDEVICES && ZORRO - help - This driver is for the Village Tronic Ariadne II and the Individual - Computers X-Surf Ethernet cards. If you have such a card, say Y. - Otherwise, say N. - - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called ariadne2. If you want to compile it as - a module, say M here and read . - -config NE2K_ZORRO - tristate "Ariadne II and X-Surf support" - depends on NET_ETHERNET && ZORRO - config A2065 tristate "A2065 support" depends on NET_ETHERNET && ZORRO @@ -322,6 +305,20 @@ want). The module is called hydra. If you want to compile it as a module, say M here and read . +config ZORRO8390 + tristate "Zorro NS8390-based Ethernet support" + depends on NET_ETHERNET && ZORRO + help + This driver is for Zorro Ethernet cards using an NS8390-compatible + chipset, like the Village Tronic Ariadne II and the Individual + Computers X-Surf Ethernet cards. If you have such a card, say Y. + Otherwise, say N. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module is called zorro8390. If you want to compile it as + a module, say M here and read . + config APNE tristate "PCMCIA NE2000 support" depends on NETDEVICES && AMIGA_PCMCIA @@ -1153,7 +1150,7 @@ config SEEQ8005 tristate "SEEQ8005 support (EXPERIMENTAL)" - depends on NET_ISA && OBSOLETE && EXPERIMENTAL + depends on NET_ISA && EXPERIMENTAL help This is a driver for the SEEQ 8005 network (Ethernet) card. If this is for you, read the Ethernet-HOWTO, available from diff -Nru a/drivers/net/Makefile b/drivers/net/Makefile --- a/drivers/net/Makefile Sun Jul 27 10:13:43 2003 +++ b/drivers/net/Makefile Sun Jul 27 10:13:43 2003 @@ -151,7 +151,7 @@ obj-$(CONFIG_LP486E) += lp486e.o obj-$(CONFIG_ETH16I) += eth16i.o -obj-$(CONFIG_ARIADNE2) += ariadne2.o 8390.o +obj-$(CONFIG_ZORRO8390) += zorro8390.o 8390.o obj-$(CONFIG_HPLANCE) += hplance.o 7990.o obj-$(CONFIG_MVME147_NET) += mvme147.o 7990.o obj-$(CONFIG_EQUALIZER) += eql.o diff -Nru a/drivers/net/Makefile.lib b/drivers/net/Makefile.lib --- a/drivers/net/Makefile.lib Sun Jul 27 10:13:50 2003 +++ b/drivers/net/Makefile.lib Sun Jul 27 10:13:50 2003 @@ -70,5 +70,5 @@ obj-$(CONFIG_LNE390) += crc32.o obj-$(CONFIG_NE3210) += crc32.o obj-$(CONFIG_AC3200) += crc32.o -obj-$(CONFIG_ARIADNE2) += crc32.o +obj-$(CONFIG_ZORRO8390) += crc32.o obj-$(CONFIG_HYDRA) += crc32.o diff -Nru a/drivers/net/arcnet/arc-rimi.c b/drivers/net/arcnet/arc-rimi.c --- a/drivers/net/arcnet/arc-rimi.c Sun Jul 27 10:13:40 2003 +++ b/drivers/net/arcnet/arc-rimi.c Sun Jul 27 10:13:40 2003 @@ -47,7 +47,6 @@ static int arcrimi_status(struct net_device *dev); static void arcrimi_setmask(struct net_device *dev, int mask); static int arcrimi_reset(struct net_device *dev, int really_reset); -static void arcrimi_openclose(struct net_device *dev, bool open); static void arcrimi_copy_to_card(struct net_device *dev, int bufnum, int offset, void *buf, int count); static void arcrimi_copy_from_card(struct net_device *dev, int bufnum, int offset, @@ -179,7 +178,7 @@ lp->hw.status = arcrimi_status; lp->hw.intmask = arcrimi_setmask; lp->hw.reset = arcrimi_reset; - lp->hw.open_close = arcrimi_openclose; + lp->hw.owner = THIS_MODULE; lp->hw.copy_to_card = arcrimi_copy_to_card; lp->hw.copy_from_card = arcrimi_copy_from_card; lp->mem_start = ioremap(dev->mem_start, dev->mem_end - dev->mem_start + 1); @@ -252,15 +251,6 @@ /* done! return success. */ return 0; -} - - -static void arcrimi_openclose(struct net_device *dev, int open) -{ - if (open) - MOD_INC_USE_COUNT; - else - MOD_DEC_USE_COUNT; } static void arcrimi_setmask(struct net_device *dev, int mask) diff -Nru a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c --- a/drivers/net/arcnet/arcnet.c Sun Jul 27 10:13:48 2003 +++ b/drivers/net/arcnet/arcnet.c Sun Jul 27 10:13:48 2003 @@ -343,7 +343,10 @@ static int arcnet_open(struct net_device *dev) { struct arcnet_local *lp = (struct arcnet_local *) dev->priv; - int count, newmtu; + int count, newmtu, error; + + if (!try_module_get(lp->hw.owner)) + return -ENODEV; BUGLVL(D_PROTO) { int count; @@ -360,8 +363,9 @@ /* try to put the card in a defined state - if it fails the first * time, actually reset it. */ + error = -ENODEV; if (ARCRESET(0) && ARCRESET(1)) - return -ENODEV; + goto out_module_put; newmtu = choose_mtu(); if (newmtu < dev->mtu) @@ -391,7 +395,7 @@ lp->rfc1201.sequence = 1; /* bring up the hardware driver */ - ARCOPEN(1); + lp->hw.open(dev); if (dev->dev_addr[0] == 0) BUGMSG(D_NORMAL, "WARNING! Station address 00 is reserved " @@ -415,6 +419,10 @@ netif_start_queue(dev); return 0; + + out_module_put: + module_put(lp->hw.owner); + return error; } @@ -432,8 +440,8 @@ mdelay(1); /* shut down the card */ - ARCOPEN(0); - + lp->hw.close(dev); + module_put(lp->hw.owner); return 0; } diff -Nru a/drivers/net/arcnet/com20020-isa.c b/drivers/net/arcnet/com20020-isa.c --- a/drivers/net/arcnet/com20020-isa.c Sun Jul 27 10:13:41 2003 +++ b/drivers/net/arcnet/com20020-isa.c Sun Jul 27 10:13:41 2003 @@ -131,14 +131,6 @@ MODULE_PARM(clockm, "i"); MODULE_LICENSE("GPL"); -static void com20020isa_open_close(struct net_device *dev, bool open) -{ - if (open) - MOD_INC_USE_COUNT; - else - MOD_DEC_USE_COUNT; -} - int init_module(void) { struct net_device *dev; @@ -160,7 +152,7 @@ lp->clockp = clockp & 7; lp->clockm = clockm & 3; lp->timeout = timeout & 3; - lp->hw.open_close_ll = com20020isa_open_close; + lp->owner = THIS_MODULE; dev->base_addr = io; dev->irq = irq; diff -Nru a/drivers/net/arcnet/com20020-pci.c b/drivers/net/arcnet/com20020-pci.c --- a/drivers/net/arcnet/com20020-pci.c Sun Jul 27 10:13:41 2003 +++ b/drivers/net/arcnet/com20020-pci.c Sun Jul 27 10:13:41 2003 @@ -60,14 +60,6 @@ MODULE_PARM(clockm, "i"); MODULE_LICENSE("GPL"); -static void com20020pci_open_close(struct net_device *dev, bool open) -{ - if (open) - MOD_INC_USE_COUNT; - else - MOD_DEC_USE_COUNT; -} - static int __devinit com20020pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct net_device *dev; @@ -111,7 +103,7 @@ lp->clockp = clockp & 7; lp->clockm = clockm & 3; lp->timeout = timeout; - lp->hw.open_close_ll = com20020pci_open_close; + lp->hw.owner = THIS_MODULE; if (check_region(ioaddr, ARCNET_TOTAL_SIZE)) { BUGMSG(D_INIT, "IO region %xh-%xh already allocated.\n", diff -Nru a/drivers/net/arcnet/com20020.c b/drivers/net/arcnet/com20020.c --- a/drivers/net/arcnet/com20020.c Sun Jul 27 10:13:43 2003 +++ b/drivers/net/arcnet/com20020.c Sun Jul 27 10:13:43 2003 @@ -50,13 +50,12 @@ static int com20020_status(struct net_device *dev); static void com20020_setmask(struct net_device *dev, int mask); static int com20020_reset(struct net_device *dev, int really_reset); -static void com20020_openclose(struct net_device *dev, bool open); static void com20020_copy_to_card(struct net_device *dev, int bufnum, int offset, void *buf, int count); static void com20020_copy_from_card(struct net_device *dev, int bufnum, int offset, void *buf, int count); static void com20020_set_mc_list(struct net_device *dev); - +static void com20020_close(struct net_device *, bool); static void com20020_copy_from_card(struct net_device *dev, int bufnum, int offset, void *buf, int count) @@ -162,13 +161,14 @@ lp = (struct arcnet_local *) dev->priv; + lp->hw.owner = THIS_MODULE; lp->hw.command = com20020_command; lp->hw.status = com20020_status; lp->hw.intmask = com20020_setmask; lp->hw.reset = com20020_reset; - lp->hw.open_close = com20020_openclose; lp->hw.copy_to_card = com20020_copy_to_card; lp->hw.copy_from_card = com20020_copy_from_card; + lp->hw.close = com20020_close; dev->set_multicast_list = com20020_set_mc_list; @@ -298,24 +298,17 @@ return ASTATUS(); } - -static void com20020_openclose(struct net_device *dev, bool open) +static void com20020_close(struct net_device *dev, bool open) { struct arcnet_local *lp = (struct arcnet_local *) dev->priv; int ioaddr = dev->base_addr; - if (open) { - MOD_INC_USE_COUNT; - } - else { + if (!open) { /* disable transmitter */ lp->config &= ~TXENcfg; SETCONF; - MOD_DEC_USE_COUNT; } - lp->hw.open_close_ll(dev, open); } - /* Set or clear the multicast filter for this adaptor. * num_addrs == -1 Promiscuous mode, receive all packets diff -Nru a/drivers/net/arcnet/com90io.c b/drivers/net/arcnet/com90io.c --- a/drivers/net/arcnet/com90io.c Sun Jul 27 10:13:43 2003 +++ b/drivers/net/arcnet/com90io.c Sun Jul 27 10:13:43 2003 @@ -47,7 +47,6 @@ static int com90io_status(struct net_device *dev); static void com90io_setmask(struct net_device *dev, int mask); static int com90io_reset(struct net_device *dev, int really_reset); -static void com90io_openclose(struct net_device *dev, bool open); static void com90io_copy_to_card(struct net_device *dev, int bufnum, int offset, void *buf, int count); static void com90io_copy_from_card(struct net_device *dev, int bufnum, int offset, @@ -257,7 +256,7 @@ lp->hw.status = com90io_status; lp->hw.intmask = com90io_setmask; lp->hw.reset = com90io_reset; - lp->hw.open_close = com90io_openclose; + lp->hw.owner = THIS_MODULE; lp->hw.copy_to_card = com90io_copy_to_card; lp->hw.copy_from_card = com90io_copy_from_card; @@ -342,14 +341,6 @@ short ioaddr = dev->base_addr; AINTMASK(mask); -} - -static void com90io_openclose(struct net_device *dev, int open) -{ - if (open) - MOD_INC_USE_COUNT; - else - MOD_DEC_USE_COUNT; } static void com90io_copy_to_card(struct net_device *dev, int bufnum, int offset, diff -Nru a/drivers/net/arcnet/com90xx.c b/drivers/net/arcnet/com90xx.c --- a/drivers/net/arcnet/com90xx.c Sun Jul 27 10:13:49 2003 +++ b/drivers/net/arcnet/com90xx.c Sun Jul 27 10:13:49 2003 @@ -58,7 +58,6 @@ static int com90xx_status(struct net_device *dev); static void com90xx_setmask(struct net_device *dev, int mask); static int com90xx_reset(struct net_device *dev, int really_reset); -static void com90xx_openclose(struct net_device *dev, bool open); static void com90xx_copy_to_card(struct net_device *dev, int bufnum, int offset, void *buf, int count); static void com90xx_copy_from_card(struct net_device *dev, int bufnum, int offset, @@ -450,7 +449,7 @@ lp->hw.status = com90xx_status; lp->hw.intmask = com90xx_setmask; lp->hw.reset = com90xx_reset; - lp->hw.open_close = com90xx_openclose; + lp->hw.owner = THIS_MODULE; lp->hw.copy_to_card = com90xx_copy_to_card; lp->hw.copy_from_card = com90xx_copy_from_card; lp->mem_start = ioremap(dev->mem_start, dev->mem_end - dev->mem_start + 1); @@ -569,16 +568,6 @@ /* done! return success. */ return 0; } - - -static void com90xx_openclose(struct net_device *dev, bool open) -{ - if (open) - MOD_INC_USE_COUNT; - else - MOD_DEC_USE_COUNT; -} - static void com90xx_copy_to_card(struct net_device *dev, int bufnum, int offset, void *buf, int count) diff -Nru a/drivers/net/ariadne2.c b/drivers/net/ariadne2.c --- a/drivers/net/ariadne2.c Sun Jul 27 10:13:47 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,425 +0,0 @@ -/* - * Amiga Linux/m68k and Linux/PPC Ariadne II and X-Surf Ethernet Driver - * - * (C) Copyright 1998-2000 by some Elitist 680x0 Users(TM) - * - * --------------------------------------------------------------------------- - * - * This program is based on all the other NE2000 drivers for Linux - * - * --------------------------------------------------------------------------- - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of the Linux - * distribution for more details. - * - * --------------------------------------------------------------------------- - * - * The Ariadne II and X-Surf are Zorro-II boards containing Realtek RTL8019AS - * Ethernet Controllers. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "8390.h" - - -#define NE_BASE (dev->base_addr) -#define NE_CMD (0x00*2) -#define NE_DATAPORT (0x10*2) /* NatSemi-defined port window offset. */ -#define NE_RESET (0x1f*2) /* Issue a read to reset, a write to clear. */ -#define NE_IO_EXTENT (0x20*2) - -#define NE_EN0_ISR (0x07*2) -#define NE_EN0_DCFG (0x0e*2) - -#define NE_EN0_RSARLO (0x08*2) -#define NE_EN0_RSARHI (0x09*2) -#define NE_EN0_RCNTLO (0x0a*2) -#define NE_EN0_RXCR (0x0c*2) -#define NE_EN0_TXCR (0x0d*2) -#define NE_EN0_RCNTHI (0x0b*2) -#define NE_EN0_IMR (0x0f*2) - -#define NESM_START_PG 0x40 /* First page of TX buffer */ -#define NESM_STOP_PG 0x80 /* Last page +1 of RX ring */ - - -#define WORDSWAP(a) ((((a)>>8)&0xff) | ((a)<<8)) - -#ifdef MODULE -static struct net_device *root_ariadne2_dev; -#endif - -static const struct card_info { - zorro_id id; - const char *name; - unsigned int offset; -} cards[] __initdata = { - { ZORRO_PROD_VILLAGE_TRONIC_ARIADNE2, "Ariadne II", 0x0600 }, - { ZORRO_PROD_INDIVIDUAL_COMPUTERS_X_SURF, "X-Surf", 0x8600 }, -}; - -static int __init ariadne2_probe(void); -static int __init ariadne2_init(struct net_device *dev, unsigned long board, - const char *name, unsigned long ioaddr); -static int ariadne2_open(struct net_device *dev); -static int ariadne2_close(struct net_device *dev); -static void ariadne2_reset_8390(struct net_device *dev); -static void ariadne2_get_8390_hdr(struct net_device *dev, - struct e8390_pkt_hdr *hdr, int ring_page); -static void ariadne2_block_input(struct net_device *dev, int count, - struct sk_buff *skb, int ring_offset); -static void ariadne2_block_output(struct net_device *dev, const int count, - const unsigned char *buf, - const int start_page); -static void __exit ariadne2_cleanup(void); - -static int __init ariadne2_probe(void) -{ - struct net_device *dev; - struct zorro_dev *z = NULL; - unsigned long board, ioaddr; - int err = -ENODEV; - int i; - - while ((z = zorro_find_device(ZORRO_WILDCARD, z))) { - for (i = ARRAY_SIZE(cards)-1; i >= 0; i--) - if (z->id == cards[i].id) - break; - if (i < 0) - continue; - board = z->resource.start; - ioaddr = board+cards[i].offset; - dev = init_etherdev(0, 0); - SET_MODULE_OWNER(dev); - if (!dev) - return -ENOMEM; - if (!request_mem_region(ioaddr, NE_IO_EXTENT*2, dev->name)) { - kfree(dev); - continue; - } - if ((err = ariadne2_init(dev, board, cards[i].name, - ZTWO_VADDR(ioaddr)))) { - release_mem_region(ioaddr, NE_IO_EXTENT*2); - kfree(dev); - return err; - } - err = 0; - } - - if (err == -ENODEV) - printk("No Ariadne II or X-Surf ethernet card found.\n"); - return err; -} - -static int __init ariadne2_init(struct net_device *dev, unsigned long board, - const char *name, unsigned long ioaddr) -{ - int i; - unsigned char SA_prom[32]; - int start_page, stop_page; - static u32 ariadne2_offsets[16] = { - 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, - 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e, - }; - - /* Reset card. Who knows what dain-bramaged state it was left in. */ - { - unsigned long reset_start_time = jiffies; - - z_writeb(z_readb(ioaddr + NE_RESET), ioaddr + NE_RESET); - - while ((z_readb(ioaddr + NE_EN0_ISR) & ENISR_RESET) == 0) - if (jiffies - reset_start_time > 2*HZ/100) { - printk(" not found (no reset ack).\n"); - return -ENODEV; - } - - z_writeb(0xff, ioaddr + NE_EN0_ISR); /* Ack all intr. */ - } - - /* Read the 16 bytes of station address PROM. - We must first initialize registers, similar to NS8390_init(eifdev, 0). - We can't reliably read the SAPROM address without this. - (I learned the hard way!). */ - { - struct { - u32 value; - u32 offset; - } program_seq[] = { - {E8390_NODMA+E8390_PAGE0+E8390_STOP, NE_CMD}, /* Select page 0*/ - {0x48, NE_EN0_DCFG}, /* Set byte-wide (0x48) access. */ - {0x00, NE_EN0_RCNTLO}, /* Clear the count regs. */ - {0x00, NE_EN0_RCNTHI}, - {0x00, NE_EN0_IMR}, /* Mask completion irq. */ - {0xFF, NE_EN0_ISR}, - {E8390_RXOFF, NE_EN0_RXCR}, /* 0x20 Set to monitor */ - {E8390_TXOFF, NE_EN0_TXCR}, /* 0x02 and loopback mode. */ - {32, NE_EN0_RCNTLO}, - {0x00, NE_EN0_RCNTHI}, - {0x00, NE_EN0_RSARLO}, /* DMA starting at 0x0000. */ - {0x00, NE_EN0_RSARHI}, - {E8390_RREAD+E8390_START, NE_CMD}, - }; - for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++) { - z_writeb(program_seq[i].value, ioaddr + program_seq[i].offset); - } - } - for (i = 0; i < 16; i++) { - SA_prom[i] = z_readb(ioaddr + NE_DATAPORT); - (void)z_readb(ioaddr + NE_DATAPORT); - } - - /* We must set the 8390 for word mode. */ - z_writeb(0x49, ioaddr + NE_EN0_DCFG); - start_page = NESM_START_PG; - stop_page = NESM_STOP_PG; - - dev->base_addr = ioaddr; - dev->irq = IRQ_AMIGA_PORTS; - - /* Install the Interrupt handler */ - i = request_irq(IRQ_AMIGA_PORTS, ei_interrupt, SA_SHIRQ, dev->name, dev); - if (i) return i; - - /* Allocate dev->priv and fill in 8390 specific dev fields. */ - if (ethdev_init(dev)) { - printk("Unable to get memory for dev->priv.\n"); - return -ENOMEM; - } - - for(i = 0; i < ETHER_ADDR_LEN; i++) { -#ifdef DEBUG - printk(" %2.2x", SA_prom[i]); -#endif - dev->dev_addr[i] = SA_prom[i]; - } - - printk("%s: %s at 0x%08lx, Ethernet Address " - "%02x:%02x:%02x:%02x:%02x:%02x\n", dev->name, name, board, - dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], - dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); - - ei_status.name = name; - ei_status.tx_start_page = start_page; - ei_status.stop_page = stop_page; - ei_status.word16 = 1; - - ei_status.rx_start_page = start_page + TX_PAGES; - - ei_status.reset_8390 = &ariadne2_reset_8390; - ei_status.block_input = &ariadne2_block_input; - ei_status.block_output = &ariadne2_block_output; - ei_status.get_8390_hdr = &ariadne2_get_8390_hdr; - ei_status.reg_offset = ariadne2_offsets; - dev->open = &ariadne2_open; - dev->stop = &ariadne2_close; -#ifdef MODULE - ei_status.priv = (unsigned long)root_ariadne2_dev; - root_ariadne2_dev = dev; -#endif - NS8390_init(dev, 0); - return 0; -} - -static int ariadne2_open(struct net_device *dev) -{ - ei_open(dev); - return 0; -} - -static int ariadne2_close(struct net_device *dev) -{ - if (ei_debug > 1) - printk("%s: Shutting down ethercard.\n", dev->name); - ei_close(dev); - return 0; -} - -/* Hard reset the card. This used to pause for the same period that a - 8390 reset command required, but that shouldn't be necessary. */ -static void ariadne2_reset_8390(struct net_device *dev) -{ - unsigned long reset_start_time = jiffies; - - if (ei_debug > 1) - printk("resetting the 8390 t=%ld...", jiffies); - - z_writeb(z_readb(NE_BASE + NE_RESET), NE_BASE + NE_RESET); - - ei_status.txing = 0; - ei_status.dmaing = 0; - - /* This check _should_not_ be necessary, omit eventually. */ - while ((z_readb(NE_BASE+NE_EN0_ISR) & ENISR_RESET) == 0) - if (jiffies - reset_start_time > 2*HZ/100) { - printk("%s: ne_reset_8390() did not complete.\n", dev->name); - break; - } - z_writeb(ENISR_RESET, NE_BASE + NE_EN0_ISR); /* Ack intr. */ -} - -/* Grab the 8390 specific header. Similar to the block_input routine, but - we don't need to be concerned with ring wrap as the header will be at - the start of a page, so we optimize accordingly. */ - -static void ariadne2_get_8390_hdr(struct net_device *dev, - struct e8390_pkt_hdr *hdr, int ring_page) -{ - int nic_base = dev->base_addr; - int cnt; - short *ptrs; - - /* This *shouldn't* happen. If it does, it's the last thing you'll see */ - if (ei_status.dmaing) { - printk("%s: DMAing conflict in ne_get_8390_hdr " - "[DMAstat:%d][irqlock:%d].\n", dev->name, ei_status.dmaing, - ei_status.irqlock); - return; - } - - ei_status.dmaing |= 0x01; - z_writeb(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD); - z_writeb(ENISR_RDC, nic_base + NE_EN0_ISR); - z_writeb(sizeof(struct e8390_pkt_hdr), nic_base + NE_EN0_RCNTLO); - z_writeb(0, nic_base + NE_EN0_RCNTHI); - z_writeb(0, nic_base + NE_EN0_RSARLO); /* On page boundary */ - z_writeb(ring_page, nic_base + NE_EN0_RSARHI); - z_writeb(E8390_RREAD+E8390_START, nic_base + NE_CMD); - - ptrs = (short*)hdr; - for (cnt = 0; cnt < (sizeof(struct e8390_pkt_hdr)>>1); cnt++) - *ptrs++ = z_readw(NE_BASE + NE_DATAPORT); - - z_writeb(ENISR_RDC, nic_base + NE_EN0_ISR); /* Ack intr. */ - - hdr->count = WORDSWAP(hdr->count); - - ei_status.dmaing &= ~0x01; -} - -/* Block input and output, similar to the Crynwr packet driver. If you - are porting to a new ethercard, look at the packet driver source for hints. - The NEx000 doesn't share the on-board packet memory -- you have to put - the packet out through the "remote DMA" dataport using z_writeb. */ - -static void ariadne2_block_input(struct net_device *dev, int count, - struct sk_buff *skb, int ring_offset) -{ - int nic_base = dev->base_addr; - char *buf = skb->data; - short *ptrs; - int cnt; - - /* This *shouldn't* happen. If it does, it's the last thing you'll see */ - if (ei_status.dmaing) { - printk("%s: DMAing conflict in ne_block_input " - "[DMAstat:%d][irqlock:%d].\n", - dev->name, ei_status.dmaing, ei_status.irqlock); - return; - } - ei_status.dmaing |= 0x01; - z_writeb(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD); - z_writeb(ENISR_RDC, nic_base + NE_EN0_ISR); - z_writeb(count & 0xff, nic_base + NE_EN0_RCNTLO); - z_writeb(count >> 8, nic_base + NE_EN0_RCNTHI); - z_writeb(ring_offset & 0xff, nic_base + NE_EN0_RSARLO); - z_writeb(ring_offset >> 8, nic_base + NE_EN0_RSARHI); - z_writeb(E8390_RREAD+E8390_START, nic_base + NE_CMD); - ptrs = (short*)buf; - for (cnt = 0; cnt < (count>>1); cnt++) - *ptrs++ = z_readw(NE_BASE + NE_DATAPORT); - if (count & 0x01) - buf[count-1] = z_readb(NE_BASE + NE_DATAPORT); - - z_writeb(ENISR_RDC, nic_base + NE_EN0_ISR); /* Ack intr. */ - ei_status.dmaing &= ~0x01; -} - -static void ariadne2_block_output(struct net_device *dev, int count, - const unsigned char *buf, - const int start_page) -{ - int nic_base = NE_BASE; - unsigned long dma_start; - short *ptrs; - int cnt; - - /* Round the count up for word writes. Do we need to do this? - What effect will an odd byte count have on the 8390? - I should check someday. */ - if (count & 0x01) - count++; - - /* This *shouldn't* happen. If it does, it's the last thing you'll see */ - if (ei_status.dmaing) { - printk("%s: DMAing conflict in ne_block_output." - "[DMAstat:%d][irqlock:%d]\n", dev->name, ei_status.dmaing, - ei_status.irqlock); - return; - } - ei_status.dmaing |= 0x01; - /* We should already be in page 0, but to be safe... */ - z_writeb(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base + NE_CMD); - - z_writeb(ENISR_RDC, nic_base + NE_EN0_ISR); - - /* Now the normal output. */ - z_writeb(count & 0xff, nic_base + NE_EN0_RCNTLO); - z_writeb(count >> 8, nic_base + NE_EN0_RCNTHI); - z_writeb(0x00, nic_base + NE_EN0_RSARLO); - z_writeb(start_page, nic_base + NE_EN0_RSARHI); - - z_writeb(E8390_RWRITE+E8390_START, nic_base + NE_CMD); - ptrs = (short*)buf; - for (cnt = 0; cnt < count>>1; cnt++) - z_writew(*ptrs++, NE_BASE+NE_DATAPORT); - - dma_start = jiffies; - - while ((z_readb(NE_BASE + NE_EN0_ISR) & ENISR_RDC) == 0) - if (jiffies - dma_start > 2*HZ/100) { /* 20ms */ - printk("%s: timeout waiting for Tx RDC.\n", dev->name); - ariadne2_reset_8390(dev); - NS8390_init(dev,1); - break; - } - - z_writeb(ENISR_RDC, nic_base + NE_EN0_ISR); /* Ack intr. */ - ei_status.dmaing &= ~0x01; - return; -} - -static void __exit ariadne2_cleanup(void) -{ -#ifdef MODULE - struct net_device *dev, *next; - - while ((dev = root_ariadne2_dev)) { - next = (struct net_device *)(ei_status.priv); - unregister_netdev(dev); - free_irq(IRQ_AMIGA_PORTS, dev); - release_mem_region(ZTWO_PADDR(dev->base_addr), NE_IO_EXTENT*2); - kfree(dev); - root_ariadne2_dev = next; - } -#endif -} - -module_init(ariadne2_probe); -module_exit(ariadne2_cleanup); - -MODULE_LICENSE("GPL"); diff -Nru a/drivers/net/atari_pamsnet.c b/drivers/net/atari_pamsnet.c --- a/drivers/net/atari_pamsnet.c Sun Jul 27 10:13:43 2003 +++ b/drivers/net/atari_pamsnet.c Sun Jul 27 10:13:43 2003 @@ -169,7 +169,7 @@ static irqreturn_t pamsnet_intr(int irq, void *data, struct pt_regs *fp); -static struct timer_list pamsnet_timer = TIMER_INITIALIZER(amsnet_tick, 0, 0); +static struct timer_list pamsnet_timer = TIMER_INITIALIZER(pamsnet_tick, 0, 0); #define STRAM_ADDR(a) (((a) & 0xff000000) == 0) diff -Nru a/drivers/net/b44.c b/drivers/net/b44.c --- a/drivers/net/b44.c Sun Jul 27 10:13:44 2003 +++ b/drivers/net/b44.c Sun Jul 27 10:13:44 2003 @@ -1,6 +1,7 @@ /* b44.c: Broadcom 4400 device driver. * * Copyright (C) 2002 David S. Miller (davem@redhat.com) + * Fixed by Pekka Pietikainen (pp@ee.oulu.fi) */ #include @@ -14,6 +15,7 @@ #include #include #include +#include #include #include @@ -23,8 +25,8 @@ #define DRV_MODULE_NAME "b44" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "0.6" -#define DRV_MODULE_RELDATE "Nov 11, 2002" +#define DRV_MODULE_VERSION "0.9" +#define DRV_MODULE_RELDATE "Jul 14, 2003" #define B44_DEF_MSG_ENABLE \ (NETIF_MSG_DRV | \ @@ -78,6 +80,15 @@ static int b44_debug = -1; /* -1 == use B44_DEF_MSG_ENABLE as value */ +#ifndef PCI_DEVICE_ID_BCM4401 +#define PCI_DEVICE_ID_BCM4401 0x4401 +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +#define IRQ_RETVAL(x) +#define irqreturn_t void +#endif + static struct pci_device_id b44_pci_tbl[] __devinitdata = { { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, @@ -259,7 +270,7 @@ == SBTMSLOW_CLOCK); } -static void __b44_cam_write(struct b44 *bp, char *data, int index) +static void __b44_cam_write(struct b44 *bp, unsigned char *data, int index) { u32 val; @@ -521,7 +532,7 @@ /* Link now up */ netif_carrier_on(bp->dev); b44_link_report(bp); - } else if (netif_carrier_ok(bp->dev)) { + } else if (netif_carrier_ok(bp->dev) && !(bmsr & BMSR_LSTATUS)) { /* Link now down */ netif_carrier_off(bp->dev); b44_link_report(bp); @@ -650,8 +661,7 @@ src_map = &bp->rx_buffers[src_idx]; dest_map->skb = src_map->skb; - rh = (struct rx_header *) - (src_map->skb->data - bp->rx_offset); + rh = (struct rx_header *) src_map->skb->data; rh->len = 0; rh->flags = 0; pci_unmap_addr_set(dest_map, mapping, @@ -660,9 +670,12 @@ ctrl = src_desc->ctrl; if (dest_idx == (B44_RX_RING_SIZE - 1)) ctrl |= cpu_to_le32(DESC_CTRL_EOT); + else + ctrl &= cpu_to_le32(~DESC_CTRL_EOT); dest_desc->ctrl = ctrl; dest_desc->addr = src_desc->addr; + src_map->skb = NULL; } static int b44_rx(struct b44 *bp, int budget) @@ -685,7 +698,7 @@ pci_dma_sync_single(bp->pdev, map, RX_PKT_BUF_SZ, PCI_DMA_FROMDEVICE); - rh = (struct rx_header *) (skb->data - bp->rx_offset); + rh = (struct rx_header *) skb->data; len = cpu_to_le16(rh->len); if ((len > (RX_PKT_BUF_SZ - bp->rx_offset)) || (rh->flags & cpu_to_le16(RX_FLAG_ERRORS))) { @@ -718,7 +731,9 @@ goto drop_it; pci_unmap_single(bp->pdev, map, skb_size, PCI_DMA_FROMDEVICE); - skb_put(skb, len); + /* Leave out rx_header */ + skb_put(skb, len+bp->rx_offset); + skb_pull(skb,bp->rx_offset); } else { struct sk_buff *copy_skb; @@ -730,8 +745,8 @@ copy_skb->dev = bp->dev; skb_reserve(copy_skb, 2); skb_put(copy_skb, len); - /* DMA sync done above */ - memcpy(copy_skb->data, skb->data, len); + /* DMA sync done above, copy just the actual packet */ + memcpy(copy_skb->data, skb->data+bp->rx_offset, len); skb = copy_skb; } @@ -748,6 +763,7 @@ } bp->rx_cons = cons; + bw32(B44_DMARX_PTR, cons * sizeof(struct dma_desc)); return received; } @@ -764,6 +780,7 @@ b44_tx(bp); /* spin_unlock(&bp->tx_lock); */ } + spin_unlock_irq(&bp->lock); done = 1; if (bp->istat & ISTAT_RX) { @@ -783,10 +800,12 @@ } if (bp->istat & ISTAT_ERRORS) { + spin_lock_irq(&bp->lock); b44_halt(bp); b44_init_rings(bp); b44_init_hw(bp); netif_wake_queue(bp->dev); + spin_unlock_irq(&bp->lock); done = 1; } @@ -794,7 +813,6 @@ netif_rx_complete(netdev); b44_enable_ints(bp); } - spin_unlock_irq(&bp->lock); return (done ? 0 : 1); } @@ -885,7 +903,7 @@ ctrl |= DESC_CTRL_EOT; bp->tx_ring[entry].ctrl = cpu_to_le32(ctrl); - bp->tx_ring[entry].addr = cpu_to_le32((u32) mapping); + bp->tx_ring[entry].addr = cpu_to_le32((u32) mapping+bp->dma_offset); entry = NEXT_TX(entry); @@ -1173,8 +1191,8 @@ __b44_set_rx_mode(bp->dev); /* MTU + eth header + possible VLAN tag + struct rx_header */ - bw32(B44_RXMAXLEN, bp->dev->mtu + ETH_HLEN + 8 + 24); - bw32(B44_TXMAXLEN, bp->dev->mtu + ETH_HLEN + 8 + 24); + bw32(B44_RXMAXLEN, bp->dev->mtu + ETH_HLEN + 8 + RX_HEADER_LEN); + bw32(B44_TXMAXLEN, bp->dev->mtu + ETH_HLEN + 8 + RX_HEADER_LEN); bw32(B44_TX_WMARK, 56); /* XXX magic */ bw32(B44_DMATX_CTRL, DMATX_CTRL_ENABLE); @@ -1184,6 +1202,7 @@ bw32(B44_DMARX_ADDR, bp->rx_ring_dma + bp->dma_offset); bw32(B44_DMARX_PTR, bp->rx_pending); + bp->rx_prod = bp->rx_pending; bw32(B44_MIB_CTRL, MIB_CTRL_CLR_ON_READ); @@ -1345,6 +1364,8 @@ __b44_load_mcast(bp, dev); bw32(B44_RXCONFIG, val); + val = br32(B44_CAM_CTRL); + bw32(B44_CAM_CTRL, val | CAM_CTRL_ENABLE); } } @@ -1678,8 +1699,9 @@ bp->core_unit = ssb_core_unit(bp); bp->dma_offset = ssb_get_addr(bp, SBID_PCI_DMA, 0); - bp->flags |= B44_FLAG_BUGGY_TXPTR; - + /* XXX - really required? + bp->flags |= B44_FLAG_BUGGY_TXPTR; + */ out: return err; } diff -Nru a/drivers/net/b44.h b/drivers/net/b44.h --- a/drivers/net/b44.h Sun Jul 27 10:13:48 2003 +++ b/drivers/net/b44.h Sun Jul 27 10:13:48 2003 @@ -142,7 +142,7 @@ #define MDIO_OP_READ 2 #define MDIO_DATA_SB_MASK 0xc0000000 /* Start Bits */ #define MDIO_DATA_SB_SHIFT 30 -#define MDIO_DATA_SB_START 0x10000000 /* Start Of Frame */ +#define MDIO_DATA_SB_START 0x40000000 /* Start Of Frame */ #define B44_EMAC_IMASK 0x0418UL /* EMAC Interrupt Mask */ #define B44_EMAC_ISTAT 0x041CUL /* EMAC Interrupt Status */ #define EMAC_INT_MII 0x00000001 /* MII MDIO Interrupt */ diff -Nru a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c --- a/drivers/net/e1000/e1000_ethtool.c Sun Jul 27 10:13:45 2003 +++ b/drivers/net/e1000/e1000_ethtool.c Sun Jul 27 10:13:45 2003 @@ -1475,6 +1475,107 @@ return -EFAULT; return 0; } + case ETHTOOL_GRXCSUM: { + struct ethtool_value edata = { ETHTOOL_GRXCSUM }; + + edata.data = adapter->rx_csum; + if (copy_to_user(addr, &edata, sizeof(edata))) + return -EFAULT; + return 0; + } + case ETHTOOL_SRXCSUM: { + struct ethtool_value edata; + + if (copy_from_user(&edata, addr, sizeof(edata))) + return -EFAULT; + adapter->rx_csum = edata.data; + if(netif_running(netdev)) { + e1000_down(adapter); + e1000_up(adapter); + } else + e1000_reset(adapter); + return 0; + } + case ETHTOOL_GTXCSUM: { + struct ethtool_value edata = { ETHTOOL_GTXCSUM }; + + edata.data = + (netdev->features & NETIF_F_HW_CSUM) != 0; + if (copy_to_user(addr, &edata, sizeof(edata))) + return -EFAULT; + return 0; + } + case ETHTOOL_STXCSUM: { + struct ethtool_value edata; + + if (copy_from_user(&edata, addr, sizeof(edata))) + return -EFAULT; + + if(adapter->hw.mac_type < e1000_82543) { + if (edata.data != 0) + return -EINVAL; + return 0; + } + + if (edata.data) + netdev->features |= NETIF_F_HW_CSUM; + else + netdev->features &= ~NETIF_F_HW_CSUM; + + return 0; + } + case ETHTOOL_GSG: { + struct ethtool_value edata = { ETHTOOL_GSG }; + + edata.data = + (netdev->features & NETIF_F_SG) != 0; + if (copy_to_user(addr, &edata, sizeof(edata))) + return -EFAULT; + return 0; + } + case ETHTOOL_SSG: { + struct ethtool_value edata; + + if (copy_from_user(&edata, addr, sizeof(edata))) + return -EFAULT; + + if (edata.data) + netdev->features |= NETIF_F_SG; + else + netdev->features &= ~NETIF_F_SG; + + return 0; + } +#ifdef NETIF_F_TSO + case ETHTOOL_GTSO: { + struct ethtool_value edata = { ETHTOOL_GTSO }; + + edata.data = (netdev->features & NETIF_F_TSO) != 0; + if (copy_to_user(addr, &edata, sizeof(edata))) + return -EFAULT; + return 0; + } + case ETHTOOL_STSO: { + struct ethtool_value edata; + + if (copy_from_user(&edata, addr, sizeof(edata))) + return -EFAULT; + + if ((adapter->hw.mac_type < e1000_82544) || + (adapter->hw.mac_type == e1000_82547)) { + if (edata.data != 0) + return -EINVAL; + return 0; + } + + if (edata.data) + netdev->features |= NETIF_F_TSO; + else + netdev->features &= ~NETIF_F_TSO; + + return 0; + } +#endif default: return -EOPNOTSUPP; } diff -Nru a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c --- a/drivers/net/e1000/e1000_main.c Sun Jul 27 10:13:44 2003 +++ b/drivers/net/e1000/e1000_main.c Sun Jul 27 10:13:44 2003 @@ -50,7 +50,7 @@ char e1000_driver_name[] = "e1000"; char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver"; -char e1000_driver_version[] = "5.1.13-k1"; +char e1000_driver_version[] = "5.1.13-k2"; char e1000_copyright[] = "Copyright (c) 1999-2003 Intel Corporation."; /* e1000_pci_tbl - PCI Device ID Table diff -Nru a/drivers/net/eql.c b/drivers/net/eql.c --- a/drivers/net/eql.c Sun Jul 27 10:13:51 2003 +++ b/drivers/net/eql.c Sun Jul 27 10:13:51 2003 @@ -162,22 +162,12 @@ static char version[] __initdata = "Equalizer2002: Simon Janes (simon@ncm.com) and David S. Miller (davem@redhat.com)\n"; -static int __init eql_init(struct net_device *dev) +static void __init eql_setup(struct net_device *dev) { - static unsigned int version_printed; - equalizer_t *eql; + equalizer_t *eql = dev->priv; SET_MODULE_OWNER(dev); - if (version_printed++ == 0) - printk(version); - - dev->priv = kmalloc(sizeof (equalizer_t), GFP_KERNEL); - if (dev->priv == NULL) - return -ENOMEM; - memset(dev->priv, 0, sizeof (equalizer_t)); - eql = dev->priv; - init_timer(&eql->timer); eql->timer.data = (unsigned long) dev->priv; eql->timer.expires = jiffies + EQL_DEFAULT_RESCHED_IVAL; @@ -203,8 +193,6 @@ dev->type = ARPHRD_SLIP; dev->tx_queue_len = 5; /* Hands them off fast */ - - return 0; } static int eql_open(struct net_device *dev) @@ -598,23 +586,28 @@ return -EINVAL; } -static struct net_device dev_eql; +static struct net_device *dev_eql; static int __init eql_init_module(void) { - strcpy(dev_eql.name, "eql"); - dev_eql.init = eql_init; - if (register_netdev(&dev_eql) != 0) { - printk("eql: register_netdev() returned non-zero.\n"); - return -EIO; - } - return 0; + int err; + + printk(version); + + dev_eql = alloc_netdev(sizeof(equalizer_t), "eql", eql_setup); + if (!dev_eql) + return -ENOMEM; + + err = register_netdev(dev_eql); + if (err) + kfree(dev_eql); + return err; } static void __exit eql_cleanup_module(void) { - kfree(dev_eql.priv); - unregister_netdev(&dev_eql); + unregister_netdev(dev_eql); + kfree(dev_eql); } module_init(eql_init_module); diff -Nru a/drivers/net/fc/iph5526.c b/drivers/net/fc/iph5526.c --- a/drivers/net/fc/iph5526.c Sun Jul 27 10:13:42 2003 +++ b/drivers/net/fc/iph5526.c Sun Jul 27 10:13:42 2003 @@ -48,7 +48,6 @@ #include #include #include -#include #include /* had the declarations for init_fcdev among others + includes if_fcdevice.h */ diff -Nru a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c --- a/drivers/net/irda/vlsi_ir.c Sun Jul 27 10:13:40 2003 +++ b/drivers/net/irda/vlsi_ir.c Sun Jul 27 10:13:40 2003 @@ -474,10 +474,8 @@ if (pos + nbytes > size) nbytes = size - pos; - if (!access_ok(VERIFY_WRITE, buf, nbytes)) - return -EINVAL; - - copy_to_user(buf, procdata->data + pos, nbytes); + if (copy_to_user(buf, procdata->data + pos, nbytes)) + return -EFAULT; *ppos += nbytes; diff -Nru a/drivers/net/mac8390.c b/drivers/net/mac8390.c --- a/drivers/net/mac8390.c Sun Jul 27 10:13:46 2003 +++ b/drivers/net/mac8390.c Sun Jul 27 10:13:46 2003 @@ -378,7 +378,7 @@ #ifdef MODULE MODULE_AUTHOR("David Huggins-Daines and others"); MODULE_DESCRIPTION("Macintosh NS8390-based Nubus Ethernet driver"); -MODUEL_LICENSE("GPL"); +MODULE_LICENSE("GPL"); int init_module(void) { diff -Nru a/drivers/net/macsonic.c b/drivers/net/macsonic.c --- a/drivers/net/macsonic.c Sun Jul 27 10:13:41 2003 +++ b/drivers/net/macsonic.c Sun Jul 27 10:13:41 2003 @@ -138,7 +138,7 @@ int __init macsonic_init(struct net_device* dev) { - struct sonic_local* lp; + struct sonic_local* lp = NULL; int i; /* Allocate the entire chunk of memory for the descriptors. diff -Nru a/drivers/net/ne2k-pci.c b/drivers/net/ne2k-pci.c --- a/drivers/net/ne2k-pci.c Sun Jul 27 10:13:42 2003 +++ b/drivers/net/ne2k-pci.c Sun Jul 27 10:13:42 2003 @@ -635,6 +635,7 @@ unregister_netdev(dev); release_region(dev->base_addr, NE_IO_EXTENT); + kfree(dev->priv); kfree(dev); pci_set_drvdata(pdev, NULL); } diff -Nru a/drivers/net/ni65.c b/drivers/net/ni65.c --- a/drivers/net/ni65.c Sun Jul 27 10:13:43 2003 +++ b/drivers/net/ni65.c Sun Jul 27 10:13:43 2003 @@ -245,6 +245,7 @@ int cmdr_addr; int cardno; int features; + spinlock_t ring_lock; }; static int ni65_probe1(struct net_device *dev,int); @@ -299,7 +300,7 @@ int irqval = request_irq(dev->irq, &ni65_interrupt,0, cards[p->cardno].cardname,dev); if (irqval) { - printk ("%s: unable to get IRQ %d (irqval=%d).\n", + printk(KERN_ERR "%s: unable to get IRQ %d (irqval=%d).\n", dev->name,dev->irq, irqval); return -EAGAIN; } @@ -409,12 +410,14 @@ p = (struct priv *) dev->priv; p->cmdr_addr = ioaddr + cards[i].cmd_offset; p->cardno = i; + spin_lock_init(&p->ring_lock); - printk("%s: %s found at %#3x, ", dev->name, cards[p->cardno].cardname , ioaddr); + printk(KERN_INFO "%s: %s found at %#3x, ", dev->name, cards[p->cardno].cardname , ioaddr); outw(inw(PORT+L_RESET),PORT+L_RESET); /* first: reset the card */ if( (j=readreg(CSR0)) != 0x4) { - printk(KERN_ERR "can't RESET card: %04x\n",j); + printk("failed.\n"); + printk(KERN_ERR "%s: Can't RESET card: %04x\n", dev->name, j); ni65_free_buffer(p); release_region(ioaddr, cards[p->cardno].total_size); return -EAGAIN; @@ -467,7 +470,8 @@ break; } if(i == 5) { - printk("Can't detect DMA channel!\n"); + printk("failed.\n"); + printk(KERN_ERR "%s: Can't detect DMA channel!\n", dev->name); ni65_free_buffer(p); release_region(ioaddr, cards[p->cardno].total_size); return -EAGAIN; @@ -480,13 +484,13 @@ if(dev->irq < 2) { - unsigned long irq_mask, delay; + unsigned long irq_mask; ni65_init_lance(p,dev->dev_addr,0,0); irq_mask = probe_irq_on(); writereg(CSR0_INIT|CSR0_INEA,CSR0); /* trigger interrupt */ - delay = jiffies + HZ/50; - while (time_before(jiffies, delay)) ; + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ/50); dev->irq = probe_irq_off(irq_mask); if(!dev->irq) { @@ -503,7 +507,7 @@ if(request_dma(dev->dma, cards[p->cardno].cardname ) != 0) { - printk("%s: Can't request dma-channel %d\n",dev->name,(int) dev->dma); + printk(KERN_ERR "%s: Can't request dma-channel %d\n",dev->name,(int) dev->dma); ni65_free_buffer(p); release_region(ioaddr, cards[p->cardno].total_size); return -EAGAIN; @@ -570,7 +574,7 @@ if(type) { ret = skb = alloc_skb(2+16+size,GFP_KERNEL|GFP_DMA); if(!skb) { - printk("%s: unable to allocate %s memory.\n",dev->name,what); + printk(KERN_WARNING "%s: unable to allocate %s memory.\n",dev->name,what); return NULL; } skb->dev = dev; @@ -581,12 +585,12 @@ else { ret = ptr = kmalloc(T_BUF_SIZE,GFP_KERNEL | GFP_DMA); if(!ret) { - printk("%s: unable to allocate %s memory.\n",dev->name,what); + printk(KERN_WARNING "%s: unable to allocate %s memory.\n",dev->name,what); return NULL; } } if( (u32) virt_to_phys(ptr+size) > 0x1000000) { - printk("%s: unable to allocate %s memory in lower 16MB!\n",dev->name,what); + printk(KERN_WARNING "%s: unable to allocate %s memory in lower 16MB!\n",dev->name,what); if(type) kfree_skb(skb); else @@ -692,7 +696,7 @@ writedatareg(CSR0_STOP); if(debuglevel > 1) - printk("ni65_stop_start\n"); + printk(KERN_DEBUG "ni65_stop_start\n"); if(p->features & INIT_RING_BEFORE_START) { int i; @@ -846,6 +850,8 @@ p = (struct priv *) dev->priv; + spin_lock(&p->ring_lock); + while(--bcnt) { csr0 = inw(PORT+L_DATAREG); @@ -867,7 +873,7 @@ { struct priv *p = (struct priv *) dev->priv; if(debuglevel > 1) - printk("%s: general error: %04x.\n",dev->name,csr0); + printk(KERN_ERR "%s: general error: %04x.\n",dev->name,csr0); if(csr0 & CSR0_BABL) p->stats.tx_errors++; if(csr0 & CSR0_MISS) { @@ -879,7 +885,7 @@ } if(csr0 & CSR0_MERR) { if(debuglevel > 1) - printk("%s: Ooops .. memory error: %04x.\n",dev->name,csr0); + printk(KERN_ERR "%s: Ooops .. memory error: %04x.\n",dev->name,csr0); ni65_stop_start(dev,p); } } @@ -932,12 +938,13 @@ #endif if( (csr0 & (CSR0_RXON | CSR0_TXON)) != (CSR0_RXON | CSR0_TXON) ) { - printk("%s: RX or TX was offline -> restart\n",dev->name); + printk(KERN_DEBUG "%s: RX or TX was offline -> restart\n",dev->name); ni65_stop_start(dev,p); } else writedatareg(CSR0_INEA); + spin_unlock(&p->ring_lock); return IRQ_HANDLED; } @@ -1147,9 +1154,7 @@ memset((char *)p->tmdbounce[p->tmdbouncenum]+skb->len, 0, len-skb->len); dev_kfree_skb (skb); - save_flags(flags); - cli(); - + spin_lock_irqsave(&p->ring_lock, flags); tmdp = p->tmdhead + p->tmdnum; tmdp->u.buffer = (u32) isa_virt_to_bus(p->tmdbounce[p->tmdbouncenum]); p->tmdbouncenum = (p->tmdbouncenum + 1) & (TMDNUM - 1); @@ -1157,8 +1162,7 @@ #ifdef XMT_VIA_SKB } else { - save_flags(flags); - cli(); + spin_lock_irqsave(&p->ring_lock, flags); tmdp = p->tmdhead + p->tmdnum; tmdp->u.buffer = (u32) isa_virt_to_bus(skb->data); @@ -1178,8 +1182,8 @@ p->lock = 0; dev->trans_start = jiffies; - - restore_flags(flags); + + spin_unlock_irqrestore(&p->ring_lock, flags); } return 0; @@ -1238,10 +1242,8 @@ { struct priv *p; p = (struct priv *) dev_ni65.priv; - if(!p) { - printk("Ooops .. no private struct\n"); - return; - } + if(!p) + BUG(); disable_dma(dev_ni65.dma); free_dma(dev_ni65.dma); unregister_netdev(&dev_ni65); @@ -1250,6 +1252,7 @@ dev_ni65.priv = NULL; } #endif /* MODULE */ + MODULE_LICENSE("GPL"); /* diff -Nru a/drivers/net/ni65.h b/drivers/net/ni65.h --- a/drivers/net/ni65.h Sun Jul 27 10:13:52 2003 +++ b/drivers/net/ni65.h Sun Jul 27 10:13:52 2003 @@ -20,32 +20,32 @@ #define CSR0_BABL 0x4000 /* Babble transmitter timeout error (RC) */ #define CSR0_CERR 0x2000 /* Collision Error (RC) */ #define CSR0_MISS 0x1000 /* Missed packet (RC) */ -#define CSR0_MERR 0x0800 /* Memory Error (RC) */ +#define CSR0_MERR 0x0800 /* Memory Error (RC) */ #define CSR0_RINT 0x0400 /* Receiver Interrupt (RC) */ -#define CSR0_TINT 0x0200 /* Transmit Interrupt (RC) */ +#define CSR0_TINT 0x0200 /* Transmit Interrupt (RC) */ #define CSR0_IDON 0x0100 /* Initialization Done (RC) */ #define CSR0_INTR 0x0080 /* Interrupt Flag (R) */ #define CSR0_INEA 0x0040 /* Interrupt Enable (RW) */ #define CSR0_RXON 0x0020 /* Receiver on (R) */ -#define CSR0_TXON 0x0010 /* Transmitter on (R) */ +#define CSR0_TXON 0x0010 /* Transmitter on (R) */ #define CSR0_TDMD 0x0008 /* Transmit Demand (RS) */ -#define CSR0_STOP 0x0004 /* Stop (RS) */ +#define CSR0_STOP 0x0004 /* Stop (RS) */ #define CSR0_STRT 0x0002 /* Start (RS) */ #define CSR0_INIT 0x0001 /* Initialize (RS) */ -#define CSR0_CLRALL 0x7f00 /* mask for all clearable bits */ +#define CSR0_CLRALL 0x7f00 /* mask for all clearable bits */ /* * Initialization Block Mode operation Bit Definitions. */ #define M_PROM 0x8000 /* Promiscuous Mode */ -#define M_INTL 0x0040 /* Internal Loopback */ -#define M_DRTY 0x0020 /* Disable Retry */ +#define M_INTL 0x0040 /* Internal Loopback */ +#define M_DRTY 0x0020 /* Disable Retry */ #define M_COLL 0x0010 /* Force Collision */ #define M_DTCR 0x0008 /* Disable Transmit CRC) */ #define M_LOOP 0x0004 /* Loopback */ -#define M_DTX 0x0002 /* Disable the Transmitter */ -#define M_DRX 0x0001 /* Disable the Receiver */ +#define M_DTX 0x0002 /* Disable the Transmitter */ +#define M_DRX 0x0001 /* Disable the Receiver */ /* @@ -56,7 +56,7 @@ #define RCV_ERR 0x40 /* Error Summary */ #define RCV_FRAM 0x20 /* Framing Error */ #define RCV_OFLO 0x10 /* Overflow Error */ -#define RCV_CRC 0x08 /* CRC Error */ +#define RCV_CRC 0x08 /* CRC Error */ #define RCV_BUF_ERR 0x04 /* Buffer Error */ #define RCV_START 0x02 /* Start of Packet */ #define RCV_END 0x01 /* End of Packet */ @@ -67,7 +67,7 @@ */ #define XMIT_OWN 0x80 /* owner bit 0 = host, 1 = lance */ -#define XMIT_ERR 0x40 /* Error Summary */ +#define XMIT_ERR 0x40 /* Error Summary */ #define XMIT_RETRY 0x10 /* more the 1 retry needed to Xmit */ #define XMIT_1_RETRY 0x08 /* one retry needed to Xmit */ #define XMIT_DEF 0x04 /* Deferred */ @@ -78,53 +78,44 @@ * transmit status (2) (valid if XMIT_ERR == 1) */ -#define XMIT_TDRMASK 0x03ff /* time-domain-reflectometer-value */ -#define XMIT_RTRY 0x0400 /* Failed after 16 retransmissions */ -#define XMIT_LCAR 0x0800 /* Loss of Carrier */ -#define XMIT_LCOL 0x1000 /* Late collision */ -#define XMIT_RESERV 0x2000 /* Reserved */ -#define XMIT_UFLO 0x4000 /* Underflow (late memory) */ -#define XMIT_BUFF 0x8000 /* Buffering error (no ENP) */ - -struct init_block -{ - unsigned short mode; - unsigned char eaddr[6]; - unsigned char filter[8]; - /* bit 29-31: number of rmd's (power of 2) */ - u32 rrp; /* receive ring pointer (align 8) */ - /* bit 29-31: number of tmd's (power of 2) */ - u32 trp; /* transmit ring pointer (align 8) */ +#define XMIT_TDRMASK 0x03ff /* time-domain-reflectometer-value */ +#define XMIT_RTRY 0x0400 /* Failed after 16 retransmissions */ +#define XMIT_LCAR 0x0800 /* Loss of Carrier */ +#define XMIT_LCOL 0x1000 /* Late collision */ +#define XMIT_RESERV 0x2000 /* Reserved */ +#define XMIT_UFLO 0x4000 /* Underflow (late memory) */ +#define XMIT_BUFF 0x8000 /* Buffering error (no ENP) */ + +struct init_block { + unsigned short mode; + unsigned char eaddr[6]; + unsigned char filter[8]; + /* bit 29-31: number of rmd's (power of 2) */ + u32 rrp; /* receive ring pointer (align 8) */ + /* bit 29-31: number of tmd's (power of 2) */ + u32 trp; /* transmit ring pointer (align 8) */ }; -struct rmd /* Receive Message Descriptor */ -{ - union - { - volatile u32 buffer; - struct - { - volatile unsigned char dummy[3]; - volatile unsigned char status; - } s; - } u; - volatile short blen; - volatile unsigned short mlen; +struct rmd { /* Receive Message Descriptor */ + union { + volatile u32 buffer; + struct { + volatile unsigned char dummy[3]; + volatile unsigned char status; + } s; + } u; + volatile short blen; + volatile unsigned short mlen; }; -struct tmd -{ - union - { - volatile u32 buffer; - struct - { - volatile unsigned char dummy[3]; - volatile unsigned char status; - } s; - } u; - volatile unsigned short blen; - volatile unsigned short status2; +struct tmd { + union { + volatile u32 buffer; + struct { + volatile unsigned char dummy[3]; + volatile unsigned char status; + } s; + } u; + volatile unsigned short blen; + volatile unsigned short status2; }; - - diff -Nru a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c --- a/drivers/net/pcmcia/3c574_cs.c Sun Jul 27 10:13:42 2003 +++ b/drivers/net/pcmcia/3c574_cs.c Sun Jul 27 10:13:42 2003 @@ -296,7 +296,8 @@ lp = dev->priv; link = &lp->link; link->priv = dev; - + + spin_lock_init(&lp->window_lock); init_timer(&link->release); link->release.function = &tc574_release; link->release.data = (unsigned long)link; diff -Nru a/drivers/net/pcmcia/Kconfig b/drivers/net/pcmcia/Kconfig --- a/drivers/net/pcmcia/Kconfig Sun Jul 27 10:13:49 2003 +++ b/drivers/net/pcmcia/Kconfig Sun Jul 27 10:13:49 2003 @@ -113,7 +113,7 @@ If unsure, say N. config PCMCIA_AXNET - tristate "broken NS8390-cards support" + tristate "Asix AX88190 PCMCIA support" depends on NET_PCMCIA && PCMCIA ---help--- Say Y here if you intend to attach an Asix AX88190-based PCMCIA diff -Nru a/drivers/net/seeq8005.c b/drivers/net/seeq8005.c --- a/drivers/net/seeq8005.c Sun Jul 27 10:13:49 2003 +++ b/drivers/net/seeq8005.c Sun Jul 27 10:13:49 2003 @@ -700,7 +700,8 @@ * wait_for_buffer * * This routine waits for the SEEQ chip to assert that the FIFO is ready - * by checking for a window interrupt, and then clearing it + * by checking for a window interrupt, and then clearing it. This has to + * occur in the interrupt handler! */ inline void wait_for_buffer(struct net_device * dev) { @@ -710,7 +711,7 @@ tmp = jiffies + HZ; while ( ( ((status=inw(SEEQ_STATUS)) & SEEQSTAT_WINDOW_INT) != SEEQSTAT_WINDOW_INT) && time_before(jiffies, tmp)) - mb(); + cpu_relax(); if ( (status & SEEQSTAT_WINDOW_INT) == SEEQSTAT_WINDOW_INT) outw( SEEQCMD_WINDOW_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD); diff -Nru a/drivers/net/sk_mca.c b/drivers/net/sk_mca.c --- a/drivers/net/sk_mca.c Sun Jul 27 10:13:48 2003 +++ b/drivers/net/sk_mca.c Sun Jul 27 10:13:48 2003 @@ -254,8 +254,7 @@ /* disable interrupts */ - save_flags(flags); - cli(); + spin_lock_irqsave(&priv->lock, flags); /* wait until no transfer is pending */ @@ -281,7 +280,7 @@ /* reenable interrupts */ - restore_flags(flags); + spin_lock_irqrestore(&priv->lock, flags); } /* get LANCE register */ @@ -294,8 +293,7 @@ /* disable interrupts */ - save_flags(flags); - cli(); + spin_lock_irqsave(&priv->lock, flags); /* wait until no transfer is pending */ @@ -321,7 +319,7 @@ /* reenable interrupts */ - restore_flags(flags); + spin_lock_irqrestore(&priv->lock, flags); return res; } @@ -968,8 +966,9 @@ #endif /* one more descriptor busy */ - save_flags(flags); - cli(); + + spin_lock_irqsave(&priv->lock, flags); + priv->nexttxput++; if (priv->nexttxput >= TXCOUNT) priv->nexttxput = 0; @@ -994,7 +993,7 @@ if (priv->txbusy == 0) SetLANCE(dev, LANCE_CSR0, CSR0_INEA | CSR0_TDMD); - restore_flags(flags); + spin_lock_irqrestore(&priv->lock, flags); tx_done: @@ -1156,6 +1155,7 @@ priv->cmdaddr = base + 0x3ff3; priv->medium = medium; memset(&(priv->stat), 0, sizeof(struct net_device_stats)); + spin_lock_init(&priv->lock); /* set base + irq for this device (irq not allocated so far) */ dev->irq = 0; diff -Nru a/drivers/net/sk_mca.h b/drivers/net/sk_mca.h --- a/drivers/net/sk_mca.h Sun Jul 27 10:13:46 2003 +++ b/drivers/net/sk_mca.h Sun Jul 27 10:13:46 2003 @@ -53,6 +53,7 @@ int realirq; /* memorizes actual IRQ, even when currently not allocated */ skmca_medium medium; /* physical cannector */ + spinlock_t lock; } skmca_priv; /* card registers: control/status register bits */ diff -Nru a/drivers/net/sonic.c b/drivers/net/sonic.c --- a/drivers/net/sonic.c Sun Jul 27 10:13:52 2003 +++ b/drivers/net/sonic.c Sun Jul 27 10:13:52 2003 @@ -113,15 +113,6 @@ if (sonic_debug > 2) printk("sonic_send_packet: skb=%p, dev=%p\n", skb, dev); - /* - * Block a timer-based transmit from overlapping. This could better be - * done with atomic_swap(1, dev->tbusy), but set_bit() works as well. - */ - if (test_and_set_bit(0, (void *) &dev->tbusy) != 0) { - printk("%s: Transmitter access conflict.\n", dev->name); - return 1; - } - /* * Map the packet data into the logical DMA address space */ diff -Nru a/drivers/net/tg3.c b/drivers/net/tg3.c --- a/drivers/net/tg3.c Sun Jul 27 10:13:46 2003 +++ b/drivers/net/tg3.c Sun Jul 27 10:13:46 2003 @@ -32,6 +32,12 @@ #include #include +#ifdef CONFIG_SPARC64 +#include +#include +#include +#endif + #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) #define TG3_VLAN_TAG_USED 1 #else @@ -51,8 +57,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "1.6" -#define DRV_MODULE_RELDATE "June 11, 2003" +#define DRV_MODULE_VERSION "1.7" +#define DRV_MODULE_RELDATE "July 23, 2003" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 @@ -148,6 +154,8 @@ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, + { PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1001, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC9100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { 0, } @@ -6272,11 +6280,44 @@ return err; } +#ifdef CONFIG_SPARC64 +static int __devinit tg3_get_macaddr_sparc(struct tg3 *tp) +{ + struct net_device *dev = tp->dev; + struct pci_dev *pdev = tp->pdev; + struct pcidev_cookie *pcp = pdev->sysdata; + + if (pcp != NULL) { + int node = pcp->prom_node; + + if (prom_getproplen(node, "local-mac-address") == 6) { + prom_getproperty(node, "local-mac-address", + dev->dev_addr, 6); + return 0; + } + } + return -ENODEV; +} + +static int __devinit tg3_get_default_macaddr_sparc(struct tg3 *tp) +{ + struct net_device *dev = tp->dev; + + memcpy(dev->dev_addr, idprom->id_ethaddr, 6); + return 0; +} +#endif + static int __devinit tg3_get_device_address(struct tg3 *tp) { struct net_device *dev = tp->dev; u32 hi, lo, mac_offset; +#ifdef CONFIG_SPARC64 + if (!tg3_get_macaddr_sparc(tp)) + return 0; +#endif + if (PCI_FUNC(tp->pdev->devfn) == 0) mac_offset = 0x7c; else @@ -6317,9 +6358,13 @@ dev->dev_addr[0] = (hi >> 8) & 0xff; } - if (!is_valid_ether_addr(&dev->dev_addr[0])) + if (!is_valid_ether_addr(&dev->dev_addr[0])) { +#ifdef CONFIG_SPARC64 + if (!tg3_get_default_macaddr_sparc(tp)) + return 0; +#endif return -EINVAL; - + } return 0; } diff -Nru a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c --- a/drivers/net/via-rhine.c Sun Jul 27 10:13:52 2003 +++ b/drivers/net/via-rhine.c Sun Jul 27 10:13:52 2003 @@ -122,11 +122,14 @@ - No filtering multicast in promisc mode (Edward Peng) - Fix for Rhine-I Tx timeouts + LK1.1.19 (Roger Luethi) + - Increase Tx threshold for unspecified errors + */ #define DRV_NAME "via-rhine" -#define DRV_VERSION "1.1.18-2.5" -#define DRV_RELDATE "July-4-2003" +#define DRV_VERSION "1.1.19-2.5" +#define DRV_RELDATE "July-12-2003" /* A few user-configurable values. @@ -1664,9 +1667,13 @@ } if ((intr_status & IntrTxError) && ~( IntrTxAborted | IntrTxUnderrun | IntrTxDescRace )) { - if (debug > 2) - printk(KERN_INFO "%s: Unspecified error.\n", - dev->name); + if (np->tx_thresh < 0xE0) { + writeb(np->tx_thresh += 0x20, ioaddr + TxConfig); + } + if (debug > 1) + printk(KERN_INFO "%s: Unspecified error. Tx " + "threshold now %2.2x.\n", + dev->name, np->tx_thresh); } if (intr_status & ( IntrTxAborted | IntrTxUnderrun | IntrTxDescRace | IntrTxError )) diff -Nru a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig --- a/drivers/net/wan/Kconfig Sun Jul 27 10:13:42 2003 +++ b/drivers/net/wan/Kconfig Sun Jul 27 10:13:42 2003 @@ -60,9 +60,10 @@ # # COMX drivers # +# Not updated to 2.6. config COMX tristate "MultiGate (COMX) synchronous serial boards support" - depends on WAN && (ISA || PCI) + depends on WAN && (ISA || PCI) && OBSOLETE ---help--- Say Y if you want to use any board from the MultiGate (COMX) family. These boards are synchronous serial adapters for the PC, @@ -399,37 +400,6 @@ automatically loaded when the interface is referenced then you should add "alias hdlcX farsync" to /etc/modules.conf for each interface, where X is 0, 1, 2, ... - -config HDLC_DEBUG_PKT - bool "Debug received/transmitted packets" - depends on HDLC - help - This option is for developers only - do NOT use on production - systems. - -config HDLC_DEBUG_HARD_HEADER - bool "Debug hard_header routines" - depends on HDLC - help - This option is for developers only - do NOT use on production - systems. - -config HDLC_DEBUG_ECN - bool "Debug FECN/BECN conditions" - depends on HDLC - help - This option is for developers only - do NOT use on production - systems. - -config HDLC_DEBUG_RINGS - bool "Debug RX/TX packet rings" - depends on HDLC - help - If you answer Y here you will be able to get a diagnostic dump of - port's TX and RX packet rings, using "sethdlc hdlcX private" - command. It does not affect normal operations. - - If unsure, say Y here. config DLCI tristate "Frame relay DLCI support" diff -Nru a/drivers/net/wan/c101.c b/drivers/net/wan/c101.c --- a/drivers/net/wan/c101.c Sun Jul 27 10:13:49 2003 +++ b/drivers/net/wan/c101.c Sun Jul 27 10:13:49 2003 @@ -14,7 +14,6 @@ * Moxa C101 User's Manual */ -#include #include #include #include @@ -31,9 +30,12 @@ #include "hd64570.h" -static const char* version = "Moxa C101 driver version: 1.14"; +static const char* version = "Moxa C101 driver version: 1.15"; static const char* devname = "C101"; +#undef DEBUG_PKT +#define DEBUG_RINGS + #define C101_PAGE 0x1D00 #define C101_DTR 0x1E00 #define C101_SCA 0x1F00 @@ -95,7 +97,8 @@ #define winsize(card) (C101_WINDOW_SIZE) #define win0base(card) ((card)->win0base) #define winbase(card) ((card)->win0base + 0x2000) -#define get_port(card, port) ((port) == 0 ? (card) : NULL) +#define get_port(card, port) (card) +static void sca_msci_intr(port_t *port); static inline u8 sca_get_page(card_t *card) @@ -116,9 +119,30 @@ #include "hd6457x.c" +static void sca_msci_intr(port_t *port) +{ + card_t* card = port_to_card(port); + u8 stat = sca_in(MSCI1_OFFSET + ST1, card); /* read MSCI ST1 status */ + + /* Reset MSCI TX underrun status bit */ + sca_out(stat & ST1_UDRN, MSCI0_OFFSET + ST1, card); + + if (stat & ST1_UDRN) { + port->hdlc.stats.tx_errors++; /* TX Underrun error detected */ + port->hdlc.stats.tx_fifo_errors++; + } + + /* Reset MSCI CDCD status bit - uses ch#2 DCD input */ + sca_out(stat & ST1_CDCD, MSCI1_OFFSET + ST1, card); + + if (stat & ST1_CDCD) + hdlc_set_carrier(!(sca_in(MSCI1_OFFSET + ST3, card) & ST3_DCD), + &port->hdlc); +} + + static void c101_set_iface(port_t *port) { - u8 msci = get_msci(port); u8 rxs = port->rxs & CLK_BRG_MASK; u8 txs = port->txs & CLK_BRG_MASK; @@ -145,8 +169,8 @@ port->rxs = rxs; port->txs = txs; - sca_out(rxs, msci + RXS, port); - sca_out(txs, msci + TXS, port); + sca_out(rxs, MSCI1_OFFSET + RXS, port); + sca_out(txs, MSCI1_OFFSET + TXS, port); sca_set_port(port); } @@ -164,6 +188,17 @@ writeb(1, port->win0base + C101_DTR); sca_out(0, MSCI1_OFFSET + CTL, port); /* RTS uses ch#2 output */ sca_open(hdlc); + /* DCD is connected to port 2 !@#$%^& - disable MSCI0 CDCD interrupt */ + sca_out(IE1_UDRN, MSCI0_OFFSET + IE1, port); + sca_out(IE0_TXINT, MSCI0_OFFSET + IE0, port); + + hdlc_set_carrier(!(sca_in(MSCI1_OFFSET + ST3, port) & ST3_DCD), hdlc); + printk(KERN_DEBUG "0x%X\n", sca_in(MSCI1_OFFSET + ST3, port)); + + /* enable MSCI1 CDCD interrupt */ + sca_out(IE1_CDCD, MSCI1_OFFSET + IE1, port); + sca_out(IE0_RXINTA, MSCI1_OFFSET + IE0, port); + sca_out(0x48, IER0, port); /* TXINT #0 and RXINT #1 */ c101_set_iface(port); return 0; } @@ -189,9 +224,14 @@ hdlc_device *hdlc = dev_to_hdlc(dev); port_t *port = hdlc_to_port(hdlc); -#ifdef CONFIG_HDLC_DEBUG_RINGS +#ifdef DEBUG_RINGS if (cmd == SIOCDEVPRIVATE) { sca_dump_rings(hdlc); + printk(KERN_DEBUG "MSCI1: ST: %02x %02x %02x %02x\n", + sca_in(MSCI1_OFFSET + ST0, port), + sca_in(MSCI1_OFFSET + ST1, port), + sca_in(MSCI1_OFFSET + ST2, port), + sca_in(MSCI1_OFFSET + ST3, port)); return 0; } #endif @@ -298,9 +338,6 @@ card->tx_ring_buffers = TX_RING_BUFFERS; card->rx_ring_buffers = RX_RING_BUFFERS; - printk(KERN_DEBUG "c101: using %u TX + %u RX packets rings\n", - card->tx_ring_buffers, card->rx_ring_buffers); - card->buff_offset = C101_WINDOW_SIZE; /* Bytes 1D00-1FFF reserved */ readb(card->win0base + C101_PAGE); /* Resets SCA? */ @@ -333,6 +370,13 @@ } sca_init_sync_port(card); /* Set up C101 memory */ + hdlc_set_carrier(!(sca_in(MSCI1_OFFSET + ST3, card) & ST3_DCD), + &card->hdlc); + + printk(KERN_INFO "%s: Moxa C101 on IRQ%u," + " using %u TX + %u RX packets rings\n", + hdlc_to_name(&card->hdlc), card->irq, + card->tx_ring_buffers, card->rx_ring_buffers); *new_card = card; new_card = &card->next_card; diff -Nru a/drivers/net/wan/comx-hw-comx.c b/drivers/net/wan/comx-hw-comx.c --- a/drivers/net/wan/comx-hw-comx.c Sun Jul 27 10:13:41 2003 +++ b/drivers/net/wan/comx-hw-comx.c Sun Jul 27 10:13:41 2003 @@ -11,6 +11,7 @@ * * Contributors: * Arnaldo Carvalho de Melo - 0.86 + * Daniele Bellucci - 0.87 * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -42,9 +43,12 @@ * - printk cleanups * Version 0.86 (00/08/15): * - resource release on failure at COMX_init + * + * Version 0.87 (03/07/09) + * - audit copy_from_user in comxhw_write_proc */ -#define VERSION "0.86" +#define VERSION "0.87" #include #include @@ -1084,7 +1088,8 @@ if (hw->firmware->data) { kfree(hw->firmware->data); } - copy_from_user(tmp + file->f_pos, buffer, count); + if (copy_from_user(tmp + file->f_pos, buffer, count)) + return -EFAULT; hw->firmware->len = entry->size = file->f_pos + count; hw->firmware->data = tmp; file->f_pos += count; diff -Nru a/drivers/net/wan/hd64570.h b/drivers/net/wan/hd64570.h --- a/drivers/net/wan/hd64570.h Sun Jul 27 10:13:43 2003 +++ b/drivers/net/wan/hd64570.h Sun Jul 27 10:13:43 2003 @@ -217,12 +217,15 @@ #define ST0_RXRDY 0x01 /* RX ready */ #define ST1_UDRN 0x80 /* MSCI TX underrun */ +#define ST1_CDCD 0x04 /* DCD level changed */ #define ST3_CTS 0x08 /* modem input - /CTS */ #define ST3_DCD 0x04 /* modem input - /DCD */ #define IE0_TXINT 0x80 /* TX INT MSCI interrupt enable */ +#define IE0_RXINTA 0x40 /* RX INT A MSCI interrupt enable */ #define IE1_UDRN 0x80 /* TX underrun MSCI interrupt enable */ +#define IE1_CDCD 0x04 /* DCD level changed */ #define DCR_ABORT 0x01 /* Software abort command */ #define DCR_CLEAR_EOF 0x02 /* Clear EOF interrupt */ diff -Nru a/drivers/net/wan/hd6457x.c b/drivers/net/wan/hd6457x.c --- a/drivers/net/wan/hd6457x.c Sun Jul 27 10:13:42 2003 +++ b/drivers/net/wan/hd6457x.c Sun Jul 27 10:13:42 2003 @@ -35,7 +35,6 @@ #include #include #include -#include #include #include #include @@ -244,10 +243,14 @@ sca_out(DIR_BOFE, DIR_TX(phy_node(port)), card); } } + + hdlc_set_carrier(!(sca_in(get_msci(port) + ST3, card) & ST3_DCD), + &port->hdlc); } +#ifdef NEED_SCA_MSCI_INTR /* MSCI interrupt service */ static inline void sca_msci_intr(port_t *port) { @@ -255,17 +258,19 @@ card_t* card = port_to_card(port); u8 stat = sca_in(msci + ST1, card); /* read MSCI ST1 status */ - /* printk(KERN_DEBUG "MSCI INT: ST1=%02X ILAR=%02X\n", - stat, sca_in(ILAR, card)); */ - - /* Reset MSCI TX underrun status bit */ - sca_out(stat & ST1_UDRN, msci + ST1, card); + /* Reset MSCI TX underrun and CDCD status bit */ + sca_out(stat & (ST1_UDRN | ST1_CDCD), msci + ST1, card); if (stat & ST1_UDRN) { port->hdlc.stats.tx_errors++; /* TX Underrun error detected */ port->hdlc.stats.tx_fifo_errors++; } + + if (stat & ST1_CDCD) + hdlc_set_carrier(!(sca_in(msci + ST3, card) & ST3_DCD), + &port->hdlc); } +#endif @@ -307,7 +312,7 @@ openwin(card, 0); #endif skb_put(skb, len); -#ifdef CONFIG_HDLC_DEBUG_PKT +#ifdef DEBUG_PKT printk(KERN_DEBUG "%s RX(%i):", hdlc_to_name(&port->hdlc), skb->len); debug_frame(skb); #endif @@ -560,25 +565,28 @@ #endif /* We're using the following interrupts: - - TXINT (DMAC completed all transmisions, underflow or CTS change) + - TXINT (DMAC completed all transmisions, underrun or DCD change) - all DMA interrupts */ + hdlc_set_carrier(!(sca_in(msci + ST3, card) & ST3_DCD), hdlc); + #ifdef __HD64570_H - /* MSCI TX INT IRQ enable */ - sca_out(IE0_TXINT, msci + IE0, card); - sca_out(IE1_UDRN, msci + IE1, card); /* TX underrun -> TXINT */ - sca_out(sca_in(IER0, card) | (phy_node(port) ? 0x80 : 0x08), - IER0, card); - /* DMA IRQ enable */ + /* MSCI TX INT and RX INT A IRQ enable */ + sca_out(IE0_TXINT | IE0_RXINTA, msci + IE0, card); + sca_out(IE1_UDRN | IE1_CDCD, msci + IE1, card); + sca_out(sca_in(IER0, card) | (phy_node(port) ? 0xC0 : 0x0C), + IER0, card); /* TXINT and RXINT */ + /* enable DMA IRQ */ sca_out(sca_in(IER1, card) | (phy_node(port) ? 0xF0 : 0x0F), IER1, card); #else - /* MSCI TX INT IRQ enable */ - sca_outl(IE0_TXINT | IE0_UDRN, msci + IE0, card); + /* MSCI TXINT and RXINTA interrupt enable */ + sca_outl(IE0_TXINT | IE0_RXINTA | IE0_UDRN | IE0_CDCD, msci + IE0, + card); /* DMA & MSCI IRQ enable */ - sca_outl(sca_in(IER0, card) | - (phy_node(port) ? 0x02006600 : 0x00020066), IER0, card); + sca_outl(sca_inl(IER0, card) | + (phy_node(port) ? 0x0A006600 : 0x000A0066), IER0, card); #endif #ifdef __HD64570_H @@ -600,10 +608,23 @@ static void sca_close(hdlc_device *hdlc) { port_t *port = hdlc_to_port(hdlc); + card_t* card = port_to_card(port); /* reset channel */ netif_stop_queue(hdlc_to_dev(hdlc)); sca_out(CMD_RESET, get_msci(port) + CMD, port_to_card(port)); +#ifdef __HD64570_H + /* disable MSCI interrupts */ + sca_out(sca_in(IER0, card) & (phy_node(port) ? 0x0F : 0xF0), + IER0, card); + /* disable DMA interrupts */ + sca_out(sca_in(IER1, card) & (phy_node(port) ? 0x0F : 0xF0), + IER1, card); +#else + /* disable DMA & MSCI IRQ */ + sca_outl(sca_inl(IER0, card) & + (phy_node(port) ? 0x00FF00FF : 0xFF00FF00), IER0, card); +#endif } @@ -636,7 +657,7 @@ -#ifdef CONFIG_HDLC_DEBUG_RINGS +#ifdef DEBUG_RINGS static void sca_dump_rings(hdlc_device *hdlc) { port_t *port = hdlc_to_port(hdlc); @@ -651,30 +672,26 @@ openwin(card, 0); #endif - printk(KERN_ERR "RX ring: CDA=%u EDA=%u DSR=%02X in=%u %sactive", + printk(KERN_DEBUG "RX ring: CDA=%u EDA=%u DSR=%02X in=%u %sactive", sca_ina(get_dmac_rx(port) + CDAL, card), sca_ina(get_dmac_rx(port) + EDAL, card), - sca_in(DSR_RX(phy_node(port)), card), - port->rxin, + sca_in(DSR_RX(phy_node(port)), card), port->rxin, sca_in(DSR_RX(phy_node(port)), card) & DSR_DE?"":"in"); for (cnt = 0; cnt < port_to_card(port)->rx_ring_buffers; cnt++) - printk(" %02X", - readb(&(desc_address(port, cnt, 0)->stat))); + printk(" %02X", readb(&(desc_address(port, cnt, 0)->stat))); - printk("\n" KERN_ERR "TX ring: CDA=%u EDA=%u DSR=%02X in=%u " + printk("\n" KERN_DEBUG "TX ring: CDA=%u EDA=%u DSR=%02X in=%u " "last=%u %sactive", sca_ina(get_dmac_tx(port) + CDAL, card), sca_ina(get_dmac_tx(port) + EDAL, card), - sca_in(DSR_TX(phy_node(port)), card), port->txin, - port->txlast, + sca_in(DSR_TX(phy_node(port)), card), port->txin, port->txlast, sca_in(DSR_TX(phy_node(port)), card) & DSR_DE ? "" : "in"); for (cnt = 0; cnt < port_to_card(port)->tx_ring_buffers; cnt++) - printk(" %02X", - readb(&(desc_address(port, cnt, 1)->stat))); + printk(" %02X", readb(&(desc_address(port, cnt, 1)->stat))); printk("\n"); - printk(KERN_ERR "MSCI: MD: %02x %02x %02x, " + printk(KERN_DEBUG "MSCI: MD: %02x %02x %02x, " "ST: %02x %02x %02x %02x" #ifdef __HD64572_H " %02x" @@ -695,14 +712,18 @@ sca_in(get_msci(port) + CST1, card)); #ifdef __HD64572_H - printk(KERN_ERR "ILAR: %02x\n", sca_in(ILAR, card)); + printk(KERN_DEBUG "ILAR: %02x ISR: %08x %08x\n", sca_in(ILAR, card), + sca_inl(ISR0, card), sca_inl(ISR1, card)); +#else + printk(KERN_DEBUG "ISR: %02x %02x %02x\n", sca_in(ISR0, card), + sca_in(ISR1, card), sca_in(ISR2, card)); #endif #if !defined(PAGE0_ALWAYS_MAPPED) && !defined(ALL_PAGES_ALWAYS_MAPPED) openwin(card, page); /* Restore original page */ #endif } -#endif /* CONFIG_HDLC_DEBUG_RINGS */ +#endif /* DEBUG_RINGS */ @@ -723,7 +744,7 @@ desc = desc_address(port, port->txin + 1, 1); if (readb(&desc->stat)) { /* allow 1 packet gap */ /* should never happen - previous xmit should stop queue */ -#ifdef CONFIG_HDLC_DEBUG_PKT +#ifdef DEBUG_PKT printk(KERN_DEBUG "%s: transmitter buffer full\n", dev->name); #endif netif_stop_queue(dev); @@ -731,7 +752,7 @@ return 1; /* request packet to be queued */ } -#ifdef CONFIG_HDLC_DEBUG_PKT +#ifdef DEBUG_PKT printk(KERN_DEBUG "%s TX(%i):", hdlc_to_name(hdlc), skb->len); debug_frame(skb); #endif @@ -828,7 +849,6 @@ sca_out(0, DMER, card); /* DMA Master disable */ sca_out(0x03, PCR, card); /* DMA priority */ - sca_out(0, IER1, card); /* DMA interrupt disable */ sca_out(0, DSR_RX(0), card); /* DMA disable - to halt state */ sca_out(0, DSR_TX(0), card); sca_out(0, DSR_RX(1), card); diff -Nru a/drivers/net/wan/hdlc_cisco.c b/drivers/net/wan/hdlc_cisco.c --- a/drivers/net/wan/hdlc_cisco.c Sun Jul 27 10:13:43 2003 +++ b/drivers/net/wan/hdlc_cisco.c Sun Jul 27 10:13:43 2003 @@ -9,7 +9,6 @@ * as published by the Free Software Foundation. */ -#include #include #include #include @@ -24,6 +23,7 @@ #include #include +#undef DEBUG_HARD_HEADER #define CISCO_MULTICAST 0x8F /* Cisco multicast address */ #define CISCO_UNICAST 0x0F /* Cisco unicast address */ @@ -39,7 +39,7 @@ unsigned int len) { hdlc_header *data; -#ifdef CONFIG_HDLC_DEBUG_HARD_HEADER +#ifdef DEBUG_HARD_HEADER printk(KERN_DEBUG "%s: cisco_hard_header called\n", dev->name); #endif @@ -182,7 +182,7 @@ case CISCO_KEEPALIVE_REQ: hdlc->state.cisco.rxseq = ntohl(cisco_data->par1); - if (ntohl(cisco_data->par2) == hdlc->state.cisco.txseq) { + if (ntohl(cisco_data->par2)==hdlc->state.cisco.txseq) { hdlc->state.cisco.last_poll = jiffies; if (!hdlc->state.cisco.up) { u32 sec, min, hrs, days; @@ -219,11 +219,12 @@ { hdlc_device *hdlc = (hdlc_device*)arg; - if (hdlc->state.cisco.up && - jiffies - hdlc->state.cisco.last_poll >= + if (hdlc->state.cisco.up && jiffies - hdlc->state.cisco.last_poll >= hdlc->state.cisco.settings.timeout * HZ) { hdlc->state.cisco.up = 0; printk(KERN_INFO "%s: Link down\n", hdlc_to_name(hdlc)); + if (netif_carrier_ok(&hdlc->netdev)) + netif_carrier_off(&hdlc->netdev); } cisco_keepalive_send(hdlc, CISCO_KEEPALIVE_REQ, @@ -238,7 +239,7 @@ -static int cisco_open(hdlc_device *hdlc) +static void cisco_start(hdlc_device *hdlc) { hdlc->state.cisco.last_poll = 0; hdlc->state.cisco.up = 0; @@ -249,14 +250,15 @@ hdlc->state.cisco.timer.function = cisco_timer; hdlc->state.cisco.timer.data = (unsigned long)hdlc; add_timer(&hdlc->state.cisco.timer); - return 0; } -static void cisco_close(hdlc_device *hdlc) +static void cisco_stop(hdlc_device *hdlc) { del_timer_sync(&hdlc->state.cisco.timer); + if (netif_carrier_ok(&hdlc->netdev)) + netif_carrier_off(&hdlc->netdev); } @@ -301,12 +303,13 @@ hdlc_proto_detach(hdlc); memcpy(&hdlc->state.cisco.settings, &new_settings, size); + memset(&hdlc->proto, 0, sizeof(hdlc->proto)); - hdlc->open = cisco_open; - hdlc->stop = cisco_close; - hdlc->netif_rx = cisco_rx; - hdlc->type_trans = cisco_type_trans; - hdlc->proto = IF_PROTO_CISCO; + hdlc->proto.start = cisco_start; + hdlc->proto.stop = cisco_stop; + hdlc->proto.netif_rx = cisco_rx; + hdlc->proto.type_trans = cisco_type_trans; + hdlc->proto.id = IF_PROTO_CISCO; dev->hard_start_xmit = hdlc->xmit; dev->hard_header = cisco_hard_header; dev->type = ARPHRD_CISCO; diff -Nru a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c --- a/drivers/net/wan/hdlc_fr.c Sun Jul 27 10:13:50 2003 +++ b/drivers/net/wan/hdlc_fr.c Sun Jul 27 10:13:50 2003 @@ -9,7 +9,9 @@ * as published by the Free Software Foundation. * - Theory of PVC state in DCE mode: + Theory of PVC state + + DCE mode: (exist,new) -> 0,0 when "PVC create" or if "link unreliable" 0,x -> 1,1 if "link reliable" when sending FULL STATUS @@ -17,9 +19,16 @@ (active) -> 0 when "ifconfig PVC down" or "link unreliable" or "PVC create" -> 1 when "PVC up" and (exist,new) = 1,0 + + DTE mode: + (exist,new,active) = FULL STATUS if "link reliable" + = 0, 0, 0 if "link unreliable" + No LMI: + active = open and "link reliable" + exist = new = not used + */ -#include #include #include #include @@ -36,12 +45,96 @@ #include #include +#undef DEBUG_PKT +#undef DEBUG_ECN +#undef DEBUG_LINK + +#define MAXLEN_LMISTAT 20 /* max size of status enquiry frame */ + +#define PVC_STATE_NEW 0x01 +#define PVC_STATE_ACTIVE 0x02 +#define PVC_STATE_FECN 0x08 /* FECN condition */ +#define PVC_STATE_BECN 0x10 /* BECN condition */ + + +#define FR_UI 0x03 +#define FR_PAD 0x00 + +#define NLPID_IP 0xCC +#define NLPID_IPV6 0x8E +#define NLPID_SNAP 0x80 +#define NLPID_PAD 0x00 +#define NLPID_Q933 0x08 + + +#define LMI_DLCI 0 /* LMI DLCI */ +#define LMI_PROTO 0x08 +#define LMI_CALLREF 0x00 /* Call Reference */ +#define LMI_ANSI_LOCKSHIFT 0x95 /* ANSI lockshift */ +#define LMI_REPTYPE 1 /* report type */ +#define LMI_CCITT_REPTYPE 0x51 +#define LMI_ALIVE 3 /* keep alive */ +#define LMI_CCITT_ALIVE 0x53 +#define LMI_PVCSTAT 7 /* pvc status */ +#define LMI_CCITT_PVCSTAT 0x57 +#define LMI_FULLREP 0 /* full report */ +#define LMI_INTEGRITY 1 /* link integrity report */ +#define LMI_SINGLE 2 /* single pvc report */ +#define LMI_STATUS_ENQUIRY 0x75 +#define LMI_STATUS 0x7D /* reply */ + +#define LMI_REPT_LEN 1 /* report type element length */ +#define LMI_INTEG_LEN 2 /* link integrity element length */ + +#define LMI_LENGTH 13 /* standard LMI frame length */ +#define LMI_ANSI_LENGTH 14 + + +typedef struct { +#if defined(__LITTLE_ENDIAN_BITFIELD) + unsigned ea1: 1; + unsigned cr: 1; + unsigned dlcih: 6; + + unsigned ea2: 1; + unsigned de: 1; + unsigned becn: 1; + unsigned fecn: 1; + unsigned dlcil: 4; +#else + unsigned dlcih: 6; + unsigned cr: 1; + unsigned ea1: 1; + + unsigned dlcil: 4; + unsigned fecn: 1; + unsigned becn: 1; + unsigned de: 1; + unsigned ea2: 1; +#endif +}__attribute__ ((packed)) fr_hdr; + + +static inline u16 q922_to_dlci(u8 *hdr) +{ + return ((hdr[0] & 0xFC) << 2) | ((hdr[1] & 0xF0) >> 4); +} + + -__inline__ pvc_device* find_pvc(hdlc_device *hdlc, u16 dlci) +static inline void dlci_to_q922(u8 *hdr, u16 dlci) +{ + hdr[0] = (dlci >> 2) & 0xFC; + hdr[1] = ((dlci << 4) & 0xF0) | 0x01; +} + + + +static inline pvc_device* find_pvc(hdlc_device *hdlc, u16 dlci) { pvc_device *pvc = hdlc->state.fr.first_pvc; - while(pvc) { + while (pvc) { if (pvc->dlci == dlci) return pvc; if (pvc->dlci > dlci) @@ -53,15 +146,15 @@ } -__inline__ pvc_device* add_pvc(hdlc_device *hdlc, u16 dlci) +static inline pvc_device* add_pvc(hdlc_device *hdlc, u16 dlci) { pvc_device *pvc, **pvc_p = &hdlc->state.fr.first_pvc; - while(*pvc_p) { + while (*pvc_p) { if ((*pvc_p)->dlci == dlci) return *pvc_p; if ((*pvc_p)->dlci > dlci) - break; /* the listed is sorted */ + break; /* the list is sorted */ pvc_p = &(*pvc_p)->next; } @@ -78,17 +171,37 @@ } -__inline__ int pvc_is_used(pvc_device *pvc) +static inline int pvc_is_used(pvc_device *pvc) { return pvc->main != NULL || pvc->ether != NULL; } -__inline__ void delete_unused_pvcs(hdlc_device *hdlc) +static inline void pvc_carrier(int on, pvc_device *pvc) +{ + if (on) { + if (pvc->main) + if (!netif_carrier_ok(pvc->main)) + netif_carrier_on(pvc->main); + if (pvc->ether) + if (!netif_carrier_ok(pvc->ether)) + netif_carrier_on(pvc->ether); + } else { + if (pvc->main) + if (netif_carrier_ok(pvc->main)) + netif_carrier_off(pvc->main); + if (pvc->ether) + if (netif_carrier_ok(pvc->ether)) + netif_carrier_off(pvc->ether); + } +} + + +static inline void delete_unused_pvcs(hdlc_device *hdlc) { pvc_device **pvc_p = &hdlc->state.fr.first_pvc; - while(*pvc_p) { + while (*pvc_p) { if (!pvc_is_used(*pvc_p)) { pvc_device *pvc = *pvc_p; *pvc_p = pvc->next; @@ -100,7 +213,7 @@ } -__inline__ struct net_device** get_dev_p(pvc_device *pvc, int type) +static inline struct net_device** get_dev_p(pvc_device *pvc, int type) { if (type == ARPHRD_ETHER) return &pvc->ether; @@ -109,20 +222,19 @@ } -__inline__ u16 status_to_dlci(u8 *status, int *active, int *new) +static inline u16 status_to_dlci(u8 *status, int *active, int *new) { *new = (status[2] & 0x08) ? 1 : 0; *active = (status[2] & 0x02) ? 1 : 0; - return ((status[0] & 0x3F)<<4) | ((status[1] & 0x78)>>3); + return ((status[0] & 0x3F) << 4) | ((status[1] & 0x78) >> 3); } -__inline__ void dlci_to_status(u16 dlci, u8 *status, - int active, int new) +static inline void dlci_to_status(u16 dlci, u8 *status, int active, int new) { - status[0] = (dlci>>4) & 0x3F; - status[1] = ((dlci<<3) & 0x78) | 0x80; + status[0] = (dlci >> 4) & 0x3F; + status[1] = ((dlci << 3) & 0x78) | 0x80; status[2] = 0x80; if (new) @@ -138,7 +250,7 @@ u16 head_len; struct sk_buff *skb = *skb_p; - switch(skb->protocol) { + switch (skb->protocol) { case __constant_ntohs(ETH_P_IP): head_len = 4; skb_push(skb, head_len); @@ -204,8 +316,9 @@ if (pvc->open_count++ == 0) { if (pvc->master->state.fr.settings.lmi == LMI_NONE) - pvc->state.active = 1; + pvc->state.active = pvc->master->carrier; + pvc_carrier(pvc->state.active, pvc); pvc->master->state.fr.dce_changed = 1; } return 0; @@ -260,7 +373,7 @@ } -__inline__ struct net_device_stats *pvc_get_stats(struct net_device *dev) +static inline struct net_device_stats *pvc_get_stats(struct net_device *dev) { return (struct net_device_stats *) ((char *)dev + sizeof(struct net_device)); @@ -402,6 +515,7 @@ /* ifconfig PVC up */ if (pvc->open_count && !pvc->state.active && pvc->state.exist && !pvc->state.new) { + pvc_carrier(1, pvc); pvc->state.active = 1; fr_log_dlci_active(pvc); } @@ -423,6 +537,41 @@ +static void fr_set_link_state(int reliable, hdlc_device *hdlc) +{ + pvc_device *pvc = hdlc->state.fr.first_pvc; + + hdlc->state.fr.reliable = reliable; + if (reliable) { + if (!netif_carrier_ok(&hdlc->netdev)) + netif_carrier_on(&hdlc->netdev); + + hdlc->state.fr.n391cnt = 0; /* Request full status */ + hdlc->state.fr.dce_changed = 1; + + if (hdlc->state.fr.settings.lmi == LMI_NONE) { + while (pvc) { /* Activate all PVCs */ + pvc_carrier(1, pvc); + pvc->state.exist = pvc->state.active = 1; + pvc->state.new = 0; + pvc = pvc->next; + } + } + } else { + if (netif_carrier_ok(&hdlc->netdev)) + netif_carrier_off(&hdlc->netdev); + + while (pvc) { /* Deactivate all PVCs */ + pvc_carrier(0, pvc); + pvc->state.exist = pvc->state.active = 0; + pvc->state.new = 0; + pvc = pvc->next; + } + } +} + + + static void fr_timer(unsigned long arg) { hdlc_device *hdlc = (hdlc_device*)arg; @@ -449,22 +598,9 @@ } if (hdlc->state.fr.reliable != reliable) { - pvc_device *pvc = hdlc->state.fr.first_pvc; - - hdlc->state.fr.reliable = reliable; printk(KERN_INFO "%s: Link %sreliable\n", hdlc_to_name(hdlc), reliable ? "" : "un"); - - if (reliable) { - hdlc->state.fr.n391cnt = 0; /* Request full status */ - hdlc->state.fr.dce_changed = 1; - } else { - while (pvc) { /* Deactivate all PVCs */ - pvc->state.exist = 0; - pvc->state.active = pvc->state.new = 0; - pvc = pvc->next; - } - } + fr_set_link_state(reliable, hdlc); } if (hdlc->state.fr.settings.dce) @@ -636,6 +772,7 @@ !pvc->state.exist) { pvc->state.new = new; pvc->state.active = active; + pvc_carrier(active, pvc); fr_log_dlci_active(pvc); } } @@ -647,6 +784,7 @@ while (pvc) { if (pvc->state.deleted && pvc->state.exist) { + pvc_carrier(0, pvc); pvc->state.active = pvc->state.new = 0; pvc->state.exist = 0; fr_log_dlci_active(pvc); @@ -699,7 +837,7 @@ pvc = find_pvc(hdlc, dlci); if (!pvc) { -#ifdef CONFIG_HDLC_DEBUG_PKT +#ifdef DEBUG_PKT printk(KERN_INFO "%s: No PVC for received frame's DLCI %d\n", hdlc_to_name(hdlc), dlci); #endif @@ -708,7 +846,7 @@ } if (pvc->state.fecn != fh->fecn) { -#ifdef CONFIG_HDLC_DEBUG_ECN +#ifdef DEBUG_ECN printk(KERN_DEBUG "%s: DLCI %d FECN O%s\n", hdlc_to_name(pvc), dlci, fh->fecn ? "N" : "FF"); #endif @@ -716,7 +854,7 @@ } if (pvc->state.becn != fh->becn) { -#ifdef CONFIG_HDLC_DEBUG_ECN +#ifdef DEBUG_ECN printk(KERN_DEBUG "%s: DLCI %d BECN O%s\n", hdlc_to_name(pvc), dlci, fh->becn ? "N" : "FF"); #endif @@ -787,9 +925,14 @@ -static int fr_open(hdlc_device *hdlc) +static void fr_start(hdlc_device *hdlc) { +#ifdef DEBUG_LINK + printk(KERN_DEBUG "fr_start\n"); +#endif if (hdlc->state.fr.settings.lmi != LMI_NONE) { + if (netif_carrier_ok(&hdlc->netdev)) + netif_carrier_off(&hdlc->netdev); hdlc->state.fr.last_poll = 0; hdlc->state.fr.reliable = 0; hdlc->state.fr.dce_changed = 1; @@ -806,9 +949,19 @@ hdlc->state.fr.timer.data = (unsigned long)hdlc; add_timer(&hdlc->state.fr.timer); } else - hdlc->state.fr.reliable = 1; + fr_set_link_state(1, hdlc); +} - return 0; + + +static void fr_stop(hdlc_device *hdlc) +{ +#ifdef DEBUG_LINK + printk(KERN_DEBUG "fr_stop\n"); +#endif + if (hdlc->state.fr.settings.lmi != LMI_NONE) + del_timer_sync(&hdlc->state.fr.timer); + fr_set_link_state(0, hdlc); } @@ -817,22 +970,17 @@ { pvc_device *pvc = hdlc->state.fr.first_pvc; - if (hdlc->state.fr.settings.lmi != LMI_NONE) - del_timer_sync(&hdlc->state.fr.timer); - - while(pvc) { /* Shutdown all PVCs for this FRAD */ + while (pvc) { /* Shutdown all PVCs for this FRAD */ if (pvc->main) dev_close(pvc->main); if (pvc->ether) dev_close(pvc->ether); - pvc->state.active = pvc->state.new = pvc->state.fecn = - pvc->state.becn = 0; - pvc->state.exist = 0; pvc = pvc->next; } } + static int fr_add_pvc(hdlc_device *hdlc, unsigned int dlci, int type) { pvc_device *pvc = NULL; @@ -900,6 +1048,7 @@ return -EIO; } + dev->destructor = (void (*)(struct net_device *)) kfree; *get_dev_p(pvc, type) = dev; if (!used) { hdlc->state.fr.dce_changed = 1; @@ -924,8 +1073,7 @@ if (dev->flags & IFF_UP) return -EBUSY; /* PVC in use */ - unregister_netdevice(dev); - kfree(dev); + unregister_netdevice(dev); /* the destructor will kfree(dev) */ *get_dev_p(pvc, type) = NULL; if (!pvc_is_used(pvc)) { @@ -940,24 +1088,24 @@ static void fr_destroy(hdlc_device *hdlc) { - pvc_device *pvc = hdlc->state.fr.first_pvc; - while(pvc) { + pvc_device *pvc; + + pvc = hdlc->state.fr.first_pvc; + hdlc->state.fr.first_pvc = NULL; /* All PVCs destroyed */ + hdlc->state.fr.dce_pvc_count = 0; + hdlc->state.fr.dce_changed = 1; + + while (pvc) { pvc_device *next = pvc->next; - if (pvc->main) { + if (pvc->main) /* the destructor will kfree(main + ether) */ unregister_netdevice(pvc->main); - kfree(pvc->main); - } - if (pvc->ether) { + + if (pvc->ether) unregister_netdevice(pvc->ether); - kfree(pvc->ether); - } + kfree(pvc); pvc = next; } - - hdlc->state.fr.first_pvc = NULL; /* All PVCs destroyed */ - hdlc->state.fr.dce_pvc_count = 0; - hdlc->state.fr.dce_changed = 1; } @@ -1012,19 +1160,20 @@ if (result) return result; - if (hdlc->proto != IF_PROTO_FR) { + if (hdlc->proto.id != IF_PROTO_FR) { hdlc_proto_detach(hdlc); hdlc->state.fr.first_pvc = NULL; hdlc->state.fr.dce_pvc_count = 0; } memcpy(&hdlc->state.fr.settings, &new_settings, size); + memset(&hdlc->proto, 0, sizeof(hdlc->proto)); - hdlc->open = fr_open; - hdlc->stop = fr_close; - hdlc->netif_rx = fr_rx; - hdlc->type_trans = NULL; - hdlc->proto_detach = fr_destroy; - hdlc->proto = IF_PROTO_FR; + hdlc->proto.close = fr_close; + hdlc->proto.start = fr_start; + hdlc->proto.stop = fr_stop; + hdlc->proto.detach = fr_destroy; + hdlc->proto.netif_rx = fr_rx; + hdlc->proto.id = IF_PROTO_FR; dev->hard_start_xmit = hdlc->xmit; dev->hard_header = NULL; dev->type = ARPHRD_FRAD; diff -Nru a/drivers/net/wan/hdlc_generic.c b/drivers/net/wan/hdlc_generic.c --- a/drivers/net/wan/hdlc_generic.c Sun Jul 27 10:13:41 2003 +++ b/drivers/net/wan/hdlc_generic.c Sun Jul 27 10:13:41 2003 @@ -33,7 +33,9 @@ #include -static const char* version = "HDLC support module revision 1.14"; +static const char* version = "HDLC support module revision 1.15"; + +#undef DEBUG_LINK static int hdlc_change_mtu(struct net_device *dev, int new_mtu) @@ -57,8 +59,8 @@ struct packet_type *p) { hdlc_device *hdlc = dev_to_hdlc(dev); - if (hdlc->netif_rx) - hdlc->netif_rx(skb); + if (hdlc->proto.netif_rx) + hdlc->proto.netif_rx(skb); else { hdlc->stats.rx_dropped++; /* Shouldn't happen */ dev_kfree_skb(skb); @@ -67,6 +69,103 @@ } + +void hdlc_set_carrier(int on, hdlc_device *hdlc) +{ + on = on ? 1 : 0; + +#ifdef DEBUG_LINK + printk(KERN_DEBUG "hdlc_set_carrier %i\n", on); +#endif + + spin_lock_irq(&hdlc->state_lock); + + if (hdlc->carrier == on) + goto carrier_exit; /* no change in DCD line level */ + + printk(KERN_INFO "%s: carrier %s\n", hdlc_to_name(hdlc), + on ? "ON" : "off"); + hdlc->carrier = on; + + if (!hdlc->open) + goto carrier_exit; + + if (hdlc->carrier) { + if (hdlc->proto.start) + hdlc->proto.start(hdlc); + else if (!netif_carrier_ok(&hdlc->netdev)) + netif_carrier_on(&hdlc->netdev); + + } else { /* no carrier */ + if (hdlc->proto.stop) + hdlc->proto.stop(hdlc); + else if (netif_carrier_ok(&hdlc->netdev)) + netif_carrier_off(&hdlc->netdev); + } + + carrier_exit: + spin_unlock_irq(&hdlc->state_lock); +} + + +/* Must be called by hardware driver when HDLC device is being opened */ +int hdlc_open(hdlc_device *hdlc) +{ +#ifdef DEBUG_LINK + printk(KERN_DEBUG "hdlc_open carrier %i open %i\n", + hdlc->carrier, hdlc->open); +#endif + + if (hdlc->proto.id == -1) + return -ENOSYS; /* no protocol attached */ + + if (hdlc->proto.open) { + int result = hdlc->proto.open(hdlc); + if (result) + return result; + } + + spin_lock_irq(&hdlc->state_lock); + + if (hdlc->carrier) { + if (hdlc->proto.start) + hdlc->proto.start(hdlc); + else if (!netif_carrier_ok(&hdlc->netdev)) + netif_carrier_on(&hdlc->netdev); + + } else if (netif_carrier_ok(&hdlc->netdev)) + netif_carrier_off(&hdlc->netdev); + + hdlc->open = 1; + + spin_unlock_irq(&hdlc->state_lock); + return 0; +} + + + +/* Must be called by hardware driver when HDLC device is being closed */ +void hdlc_close(hdlc_device *hdlc) +{ +#ifdef DEBUG_LINK + printk(KERN_DEBUG "hdlc_close carrier %i open %i\n", + hdlc->carrier, hdlc->open); +#endif + + spin_lock_irq(&hdlc->state_lock); + + hdlc->open = 0; + if (hdlc->carrier && hdlc->proto.stop) + hdlc->proto.stop(hdlc); + + spin_unlock_irq(&hdlc->state_lock); + + if (hdlc->proto.close) + hdlc->proto.close(hdlc); +} + + + #ifndef CONFIG_HDLC_RAW #define hdlc_raw_ioctl(hdlc, ifr) -ENOSYS #endif @@ -111,7 +210,7 @@ break; default: - proto = hdlc->proto; + proto = hdlc->proto.id; } switch(proto) { @@ -141,11 +240,14 @@ dev->flags = IFF_POINTOPOINT | IFF_NOARP; - hdlc->proto = -1; - hdlc->proto_detach = NULL; + hdlc->proto.id = -1; + hdlc->proto.detach = NULL; + hdlc->carrier = 1; + hdlc->open = 0; + spin_lock_init(&hdlc->state_lock); result = dev_alloc_name(dev, "hdlc%d"); - if (result<0) + if (result < 0) return result; result = register_netdev(dev); @@ -171,6 +273,9 @@ MODULE_DESCRIPTION("HDLC support module"); MODULE_LICENSE("GPL v2"); +EXPORT_SYMBOL(hdlc_open); +EXPORT_SYMBOL(hdlc_close); +EXPORT_SYMBOL(hdlc_set_carrier); EXPORT_SYMBOL(hdlc_ioctl); EXPORT_SYMBOL(register_hdlc_device); EXPORT_SYMBOL(unregister_hdlc_device); diff -Nru a/drivers/net/wan/hdlc_ppp.c b/drivers/net/wan/hdlc_ppp.c --- a/drivers/net/wan/hdlc_ppp.c Sun Jul 27 10:13:41 2003 +++ b/drivers/net/wan/hdlc_ppp.c Sun Jul 27 10:13:41 2003 @@ -9,7 +9,6 @@ * as published by the Free Software Foundation. */ -#include #include #include #include @@ -99,12 +98,12 @@ return result; hdlc_proto_detach(hdlc); + memset(&hdlc->proto, 0, sizeof(hdlc->proto)); - hdlc->open = ppp_open; - hdlc->stop = ppp_close; - hdlc->netif_rx = NULL; - hdlc->type_trans = ppp_type_trans; - hdlc->proto = IF_PROTO_PPP; + hdlc->proto.open = ppp_open; + hdlc->proto.close = ppp_close; + hdlc->proto.type_trans = ppp_type_trans; + hdlc->proto.id = IF_PROTO_PPP; dev->hard_start_xmit = hdlc->xmit; dev->hard_header = NULL; dev->type = ARPHRD_PPP; diff -Nru a/drivers/net/wan/hdlc_raw.c b/drivers/net/wan/hdlc_raw.c --- a/drivers/net/wan/hdlc_raw.c Sun Jul 27 10:13:47 2003 +++ b/drivers/net/wan/hdlc_raw.c Sun Jul 27 10:13:47 2003 @@ -9,7 +9,6 @@ * as published by the Free Software Foundation. */ -#include #include #include #include @@ -75,12 +74,10 @@ hdlc_proto_detach(hdlc); memcpy(&hdlc->state.raw_hdlc.settings, &new_settings, size); + memset(&hdlc->proto, 0, sizeof(hdlc->proto)); - hdlc->open = NULL; - hdlc->stop = NULL; - hdlc->netif_rx = NULL; - hdlc->type_trans = raw_type_trans; - hdlc->proto = IF_PROTO_HDLC; + hdlc->proto.type_trans = raw_type_trans; + hdlc->proto.id = IF_PROTO_HDLC; dev->hard_start_xmit = hdlc->xmit; dev->hard_header = NULL; dev->type = ARPHRD_RAWHDLC; diff -Nru a/drivers/net/wan/hdlc_raw_eth.c b/drivers/net/wan/hdlc_raw_eth.c --- a/drivers/net/wan/hdlc_raw_eth.c Sun Jul 27 10:13:45 2003 +++ b/drivers/net/wan/hdlc_raw_eth.c Sun Jul 27 10:13:45 2003 @@ -9,7 +9,6 @@ * as published by the Free Software Foundation. */ -#include #include #include #include @@ -89,12 +88,10 @@ hdlc_proto_detach(hdlc); memcpy(&hdlc->state.raw_hdlc.settings, &new_settings, size); + memset(&hdlc->proto, 0, sizeof(hdlc->proto)); - hdlc->open = NULL; - hdlc->stop = NULL; - hdlc->netif_rx = NULL; - hdlc->type_trans = eth_type_trans; - hdlc->proto = IF_PROTO_HDLC_ETH; + hdlc->proto.type_trans = eth_type_trans; + hdlc->proto.id = IF_PROTO_HDLC_ETH; dev->hard_start_xmit = eth_tx; old_ch_mtu = dev->change_mtu; old_qlen = dev->tx_queue_len; diff -Nru a/drivers/net/wan/hdlc_x25.c b/drivers/net/wan/hdlc_x25.c --- a/drivers/net/wan/hdlc_x25.c Sun Jul 27 10:13:52 2003 +++ b/drivers/net/wan/hdlc_x25.c Sun Jul 27 10:13:52 2003 @@ -9,7 +9,6 @@ * as published by the Free Software Foundation. */ -#include #include #include #include @@ -199,12 +198,13 @@ return result; hdlc_proto_detach(hdlc); + memset(&hdlc->proto, 0, sizeof(hdlc->proto)); - hdlc->open = x25_open; - hdlc->stop = x25_close; - hdlc->netif_rx = x25_rx; - hdlc->type_trans = NULL; - hdlc->proto = IF_PROTO_X25; + hdlc->proto.open = x25_open; + hdlc->proto.close = x25_close; + hdlc->proto.netif_rx = x25_rx; + hdlc->proto.type_trans = NULL; + hdlc->proto.id = IF_PROTO_X25; dev->hard_start_xmit = x25_xmit; dev->hard_header = NULL; dev->type = ARPHRD_X25; diff -Nru a/drivers/net/wan/lmc/lmc_proto.c b/drivers/net/wan/lmc/lmc_proto.c --- a/drivers/net/wan/lmc/lmc_proto.c Sun Jul 27 10:13:46 2003 +++ b/drivers/net/wan/lmc/lmc_proto.c Sun Jul 27 10:13:46 2003 @@ -43,7 +43,7 @@ #include #include #include -#include +#include #include "lmc.h" #include "lmc_var.h" diff -Nru a/drivers/net/wan/n2.c b/drivers/net/wan/n2.c --- a/drivers/net/wan/n2.c Sun Jul 27 10:13:42 2003 +++ b/drivers/net/wan/n2.c Sun Jul 27 10:13:42 2003 @@ -16,7 +16,6 @@ * SDL Inc. PPP/HDLC/CISCO driver */ -#include #include #include #include @@ -34,9 +33,12 @@ #include "hd64570.h" -static const char* version = "SDL RISCom/N2 driver version: 1.14"; +static const char* version = "SDL RISCom/N2 driver version: 1.15"; static const char* devname = "RISCom/N2"; +#undef DEBUG_PKT +#define DEBUG_RINGS + #define USE_WINDOWSIZE 16384 #define USE_BUS16BITS 1 #define CLOCK_BASE 9830400 /* 9.8304 MHz */ @@ -48,6 +50,7 @@ #endif #define N2_IOPORTS 0x10 #define NEED_DETECT_RAM +#define NEED_SCA_MSCI_INTR #define MAX_TX_BUFFERS 10 static char *hw = NULL; /* pointer to hw=xxx command line string */ @@ -257,7 +260,7 @@ hdlc_device *hdlc = dev_to_hdlc(dev); port_t *port = hdlc_to_port(hdlc); -#ifdef CONFIG_HDLC_DEBUG_RINGS +#ifdef DEBUG_RINGS if (cmd == SIOCDEVPRIVATE) { sca_dump_rings(hdlc); return 0; @@ -415,7 +418,7 @@ card->buff_offset = (valid0 + valid1) * sizeof(pkt_desc) * (card->tx_ring_buffers + card->rx_ring_buffers); - printk(KERN_DEBUG "n2: RISCom/N2 %u KB RAM, IRQ%u, " + printk(KERN_INFO "n2: RISCom/N2 %u KB RAM, IRQ%u, " "using %u TX + %u RX packets rings\n", card->ram_size / 1024, card->irq, card->tx_ring_buffers, card->rx_ring_buffers); @@ -447,7 +450,7 @@ SET_MODULE_OWNER(dev); dev->irq = irq; dev->mem_start = winbase; - dev->mem_end = winbase + USE_WINDOWSIZE-1; + dev->mem_end = winbase + USE_WINDOWSIZE - 1; dev->tx_queue_len = 50; dev->do_ioctl = n2_ioctl; dev->open = n2_open; diff -Nru a/drivers/net/wan/sdladrv.c b/drivers/net/wan/sdladrv.c --- a/drivers/net/wan/sdladrv.c Sun Jul 27 10:13:42 2003 +++ b/drivers/net/wan/sdladrv.c Sun Jul 27 10:13:42 2003 @@ -160,10 +160,6 @@ /****** Function Prototypes *************************************************/ -/* Module entry points. These are called by the OS and must be public. */ -int init_module (void); -void cleanup_module (void); - /* Hardware-specific functions */ static int sdla_detect (sdlahw_t* hw); static int sdla_autodpm (sdlahw_t* hw); @@ -325,11 +321,7 @@ * Context: process */ -#ifdef MODULE -int init_module (void) -#else int sdladrv_init(void) -#endif { int i=0; @@ -354,9 +346,12 @@ * Module 'remove' entry point. * o release all remaining system resources */ -void cleanup_module (void) +static void sdladrv_cleanup(void) { } + +module_init(sdladrv_init); +module_cleanup(sdladrv_cleanup); #endif /******* Kernel APIs ********************************************************/ diff -Nru a/drivers/net/wan/sdlamain.c b/drivers/net/wan/sdlamain.c --- a/drivers/net/wan/sdlamain.c Sun Jul 27 10:13:49 2003 +++ b/drivers/net/wan/sdlamain.c Sun Jul 27 10:13:49 2003 @@ -177,10 +177,6 @@ extern void disable_irq(unsigned int); extern void enable_irq(unsigned int); -/* Module entry points */ -int init_module (void); -void cleanup_module (void); - /* WAN link driver entry points */ static int setup(struct wan_device* wandev, wandev_conf_t* conf); static int shutdown(struct wan_device* wandev); @@ -246,11 +242,7 @@ * Context: process */ -#ifdef MODULE -int init_module (void) -#else int wanpipe_init(void) -#endif { int cnt, err = 0; @@ -313,7 +305,7 @@ * o unregister all adapters from the WAN router * o release all remaining system resources */ -void cleanup_module (void) +static void wanpipe_cleanup(void) { int i; @@ -329,6 +321,8 @@ printk(KERN_INFO "\nwanpipe: WANPIPE Modules Unloaded.\n"); } +module_init(wanpipe_init); +module_exit(wanpipe_cleanup); #endif /******* WAN Device Driver Entry Points *************************************/ diff -Nru a/drivers/net/wan/syncppp.c b/drivers/net/wan/syncppp.c --- a/drivers/net/wan/syncppp.c Sun Jul 27 10:13:43 2003 +++ b/drivers/net/wan/syncppp.c Sun Jul 27 10:13:43 2003 @@ -161,7 +161,7 @@ * then put the packet into tx_queue, and call sppp_flush_xmit() * after spinlock is released. */ -static void sppp_flush_xmit() +static void sppp_flush_xmit(void) { struct sk_buff *skb; while ((skb = skb_dequeue(&tx_queue)) != NULL) diff -Nru a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig --- a/drivers/net/wireless/Kconfig Sun Jul 27 10:13:42 2003 +++ b/drivers/net/wireless/Kconfig Sun Jul 27 10:13:42 2003 @@ -296,6 +296,14 @@ firmware package can be downloaded from http://www.thekelleys.org.uk/atmel/atmel_firmware.tar.gz +config PCMCIA_WL3501 + tristate "Planet WL3501 PCMCIA cards" + depends on NET_RADIO && EXPERIMENTAL && PCMCIA + ---help--- + A driver for WL3501 PCMCIA 802.11 wireless cards made by Planet. + It has basic support for Linux wireless extensions and initial + micro support for ethtool. + # yes, this works even when no drivers are selected config NET_WIRELESS bool diff -Nru a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile --- a/drivers/net/wireless/Makefile Sun Jul 27 10:13:52 2003 +++ b/drivers/net/wireless/Makefile Sun Jul 27 10:13:52 2003 @@ -23,4 +23,4 @@ # 16-bit wireless PCMCIA client drivers obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o obj-$(CONFIG_PCMCIA_ATMEL) += atmel_cs.o atmel.o - +obj-$(CONFIG_PCMCIA_WL3501) += wl3501_cs.o diff -Nru a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c --- a/drivers/net/wireless/airo.c Sun Jul 27 10:13:41 2003 +++ b/drivers/net/wireless/airo.c Sun Jul 27 10:13:41 2003 @@ -648,9 +648,38 @@ u16 currentXmitRate; u16 apDevExtensions; u16 normalizedSignalStrength; - u16 _reserved1; + u16 shortPreamble; u8 apIP[4]; - u16 _reserved[7]; + u8 noisePercent; /* Noise percent in last second */ + u8 noisedBm; /* Noise dBm in last second */ + u8 noiseAvePercent; /* Noise percent in last minute */ + u8 noiseAvedBm; /* Noise dBm in last minute */ + u8 noiseMaxPercent; /* Highest noise percent in last minute */ + u8 noiseMaxdBm; /* Highest noise dbm in last minute */ + u16 load; + u8 carrier[4]; + u16 assocStatus; +#define STAT_NOPACKETS 0 +#define STAT_NOCARRIERSET 10 +#define STAT_GOTCARRIERSET 11 +#define STAT_WRONGSSID 20 +#define STAT_BADCHANNEL 25 +#define STAT_BADBITRATES 30 +#define STAT_BADPRIVACY 35 +#define STAT_APFOUND 40 +#define STAT_APREJECTED 50 +#define STAT_AUTHENTICATING 60 +#define STAT_DEAUTHENTICATED 61 +#define STAT_AUTHTIMEOUT 62 +#define STAT_ASSOCIATING 70 +#define STAT_DEASSOCIATED 71 +#define STAT_ASSOCTIMEOUT 72 +#define STAT_NOTAIROAP 73 +#define STAT_ASSOCIATED 80 +#define STAT_LEAPING 90 +#define STAT_LEAPFAILED 91 +#define STAT_LEAPTIMEDOUT 92 +#define STAT_LEAPCOMPLETE 93 } StatusRid; typedef struct { @@ -923,8 +952,8 @@ static void OUT4500( struct airo_info *, u16 register, u16 value ); static unsigned short IN4500( struct airo_info *, u16 register ); static u16 setup_card(struct airo_info*, u8 *mac); -static int enable_MAC( struct airo_info *ai, Resp *rsp ); -static void disable_MAC(struct airo_info *ai); +static int enable_MAC( struct airo_info *ai, Resp *rsp, int lock ); +static void disable_MAC(struct airo_info *ai, int lock); static void enable_interrupts(struct airo_info*); static void disable_interrupts(struct airo_info*); static u16 issuecommand(struct airo_info*, Cmd *pCmd, Resp *pRsp); @@ -938,11 +967,11 @@ static int bap_write(struct airo_info*, const u16 *pu16Src, int bytelen, int whichbap); static int PC4500_accessrid(struct airo_info*, u16 rid, u16 accmd); -static int PC4500_readrid(struct airo_info*, u16 rid, void *pBuf, int len); +static int PC4500_readrid(struct airo_info*, u16 rid, void *pBuf, int len, int lock); static int PC4500_writerid(struct airo_info*, u16 rid, const void - *pBuf, int len); + *pBuf, int len, int lock); static int do_writerid( struct airo_info*, u16 rid, const void *rid_data, - int len ); + int len, int dummy ); static u16 transmit_allocate(struct airo_info*, int lenPayload, int raw); static int transmit_802_3_packet(struct airo_info*, int len, char *pPacket); static int transmit_802_11_packet(struct airo_info*, int len, char *pPacket); @@ -986,7 +1015,6 @@ #define FLAG_PROMISC IFF_PROMISC /* 0x100 - include/linux/if.h */ #define FLAG_RADIO_OFF 0x02 /* User disabling of MAC */ #define FLAG_RADIO_DOWN 0x08 /* ifup/ifdown disabling of MAC */ -#define FLAG_LOCKED 2 /* 0x04 - use as a bit offset */ #define FLAG_FLASHING 0x10 #define FLAG_ADHOC 0x01 /* Needed by MIC */ #define FLAG_MIC_CAPABLE 0x20 @@ -999,6 +1027,7 @@ tdsRssiEntry *rssi; struct semaphore sem; struct task_struct *task; + struct work_struct stats_task; struct work_struct promisc_task; struct { struct sk_buff *skb; @@ -1056,7 +1085,7 @@ ai->task = NULL; } rc = PC4500_readrid(ai, first ? RID_BSSLISTFIRST : RID_BSSLISTNEXT, - list, sizeof(*list)); + list, sizeof(*list), 1); list->len = le16_to_cpu(list->len); list->index = le16_to_cpu(list->index); @@ -1071,7 +1100,7 @@ static int readWepKeyRid(struct airo_info*ai, WepKeyRid *wkr, int temp) { int rc = PC4500_readrid(ai, temp ? RID_WEP_TEMP : RID_WEP_PERM, - wkr, sizeof(*wkr)); + wkr, sizeof(*wkr), 1); wkr->len = le16_to_cpu(wkr->len); wkr->kindex = le16_to_cpu(wkr->kindex); @@ -1080,17 +1109,17 @@ } /* In the writeXXXRid routines we copy the rids so that we don't screwup * the originals when we endian them... */ -static int writeWepKeyRid(struct airo_info*ai, WepKeyRid *pwkr, int perm) { +static int writeWepKeyRid(struct airo_info*ai, WepKeyRid *pwkr, int perm, int lock) { int rc; WepKeyRid wkr = *pwkr; wkr.len = cpu_to_le16(wkr.len); wkr.kindex = cpu_to_le16(wkr.kindex); wkr.klen = cpu_to_le16(wkr.klen); - rc = PC4500_writerid(ai, RID_WEP_TEMP, &wkr, sizeof(wkr)); + rc = PC4500_writerid(ai, RID_WEP_TEMP, &wkr, sizeof(wkr), lock); if (rc!=SUCCESS) printk(KERN_ERR "airo: WEP_TEMP set %x\n", rc); if (perm) { - rc = PC4500_writerid(ai, RID_WEP_PERM, &wkr, sizeof(wkr)); + rc = PC4500_writerid(ai, RID_WEP_PERM, &wkr, sizeof(wkr), lock); if (rc!=SUCCESS) { printk(KERN_ERR "airo: WEP_PERM set %x\n", rc); } @@ -1100,7 +1129,7 @@ static int readSsidRid(struct airo_info*ai, SsidRid *ssidr) { int i; - int rc = PC4500_readrid(ai, RID_SSID, ssidr, sizeof(*ssidr)); + int rc = PC4500_readrid(ai, RID_SSID, ssidr, sizeof(*ssidr), 1); ssidr->len = le16_to_cpu(ssidr->len); for(i = 0; i < 3; i++) { @@ -1117,10 +1146,10 @@ for(i = 0; i < 3; i++) { ssidr.ssids[i].len = cpu_to_le16(ssidr.ssids[i].len); } - rc = PC4500_writerid(ai, RID_SSID, &ssidr, sizeof(ssidr)); + rc = PC4500_writerid(ai, RID_SSID, &ssidr, sizeof(ssidr), 1); return rc; } -static int readConfigRid(struct airo_info*ai) { +static int readConfigRid(struct airo_info*ai, int lock) { int rc; u16 *s; ConfigRid cfg; @@ -1128,7 +1157,7 @@ if (ai->config.len) return SUCCESS; - rc = PC4500_readrid(ai, RID_ACTUALCONFIG, &cfg, sizeof(cfg)); + rc = PC4500_readrid(ai, RID_ACTUALCONFIG, &cfg, sizeof(cfg), lock); if (rc != SUCCESS) return rc; @@ -1157,7 +1186,7 @@ } } } -static int writeConfigRid(struct airo_info*ai) { +static int writeConfigRid(struct airo_info*ai, int lock) { u16 *s; ConfigRid cfgr; @@ -1184,33 +1213,34 @@ for(s = &cfgr.arlThreshold; s <= &cfgr.autoWake; s++) *s = cpu_to_le16(*s); - return PC4500_writerid( ai, RID_CONFIG, &cfgr, sizeof(cfgr)); + return PC4500_writerid( ai, RID_CONFIG, &cfgr, sizeof(cfgr), lock); } static int readStatusRid(struct airo_info*ai, StatusRid *statr) { - int rc = PC4500_readrid(ai, RID_STATUS, statr, sizeof(*statr)); + int rc = PC4500_readrid(ai, RID_STATUS, statr, sizeof(*statr), 1); u16 *s; statr->len = le16_to_cpu(statr->len); for(s = &statr->mode; s <= &statr->SSIDlen; s++) *s = le16_to_cpu(*s); - for(s = &statr->beaconPeriod; s <= &statr->_reserved[9]; s++) + for(s = &statr->beaconPeriod; s <= &statr->shortPreamble; s++) *s = le16_to_cpu(*s); - + statr->load = le16_to_cpu(statr->load); + statr->assocStatus = le16_to_cpu(statr->assocStatus); return rc; } static int readAPListRid(struct airo_info*ai, APListRid *aplr) { - int rc = PC4500_readrid(ai, RID_APLIST, aplr, sizeof(*aplr)); + int rc = PC4500_readrid(ai, RID_APLIST, aplr, sizeof(*aplr), 1); aplr->len = le16_to_cpu(aplr->len); return rc; } static int writeAPListRid(struct airo_info*ai, APListRid *aplr) { int rc; aplr->len = cpu_to_le16(aplr->len); - rc = PC4500_writerid(ai, RID_APLIST, aplr, sizeof(*aplr)); + rc = PC4500_writerid(ai, RID_APLIST, aplr, sizeof(*aplr), 1); return rc; } static int readCapabilityRid(struct airo_info*ai, CapabilityRid *capr) { - int rc = PC4500_readrid(ai, RID_CAPABILITIES, capr, sizeof(*capr)); + int rc = PC4500_readrid(ai, RID_CAPABILITIES, capr, sizeof(*capr), 1); u16 *s; capr->len = le16_to_cpu(capr->len); @@ -1221,8 +1251,8 @@ *s = le16_to_cpu(*s); return rc; } -static int readStatsRid(struct airo_info*ai, StatsRid *sr, int rid) { - int rc = PC4500_readrid(ai, rid, sr, sizeof(*sr)); +static int readStatsRid(struct airo_info*ai, StatsRid *sr, int rid, int lock) { + int rc = PC4500_readrid(ai, rid, sr, sizeof(*sr), lock); u32 *i; sr->len = le16_to_cpu(sr->len); @@ -1242,8 +1272,8 @@ * is open (to pipeline changes and speed-up card setup). If * those changes are not yet commited, do it now - Jean II */ if(info->need_commit) { - disable_MAC(info); - writeConfigRid(info); + disable_MAC(info, 1); + writeConfigRid(info, 1); } if (info->wifidev != dev) { @@ -1251,7 +1281,7 @@ info->flags &= ~FLAG_RADIO_DOWN; enable_interrupts(info); } - enable_MAC(info, &rsp); + enable_MAC(info, &rsp, 1); netif_start_queue(dev); return 0; @@ -1430,29 +1460,41 @@ return 0; } -struct net_device_stats *airo_get_stats(struct net_device *dev) -{ - struct airo_info *local = dev->priv; +static void airo_read_stats(struct airo_info *ai) { StatsRid stats_rid; u32 *vals = stats_rid.vals; - /* Get stats out of the card */ - readStatsRid(local, &stats_rid, RID_STATS); + if (down_trylock(&ai->sem) == 0) { + readStatsRid(ai, &stats_rid, RID_STATS, 0); + up(&ai->sem); + + ai->stats.rx_packets = vals[43] + vals[44] + vals[45]; + ai->stats.tx_packets = vals[39] + vals[40] + vals[41]; + ai->stats.rx_bytes = vals[92]; + ai->stats.tx_bytes = vals[91]; + ai->stats.rx_errors = vals[0] + vals[2] + vals[3] + vals[4]; + ai->stats.tx_errors = vals[42] + ai->stats.tx_fifo_errors; + ai->stats.multicast = vals[43]; + ai->stats.collisions = vals[89]; + + /* detailed rx_errors: */ + ai->stats.rx_length_errors = vals[3]; + ai->stats.rx_crc_errors = vals[4]; + ai->stats.rx_frame_errors = vals[2]; + ai->stats.rx_fifo_errors = vals[0]; + } else { + ai->stats_task.func = (void (*)(void *))airo_read_stats; + ai->stats_task.data = (void *)ai; + schedule_work(&ai->stats_task); + } +} - local->stats.rx_packets = vals[43] + vals[44] + vals[45]; - local->stats.tx_packets = vals[39] + vals[40] + vals[41]; - local->stats.rx_bytes = vals[92]; - local->stats.tx_bytes = vals[91]; - local->stats.rx_errors = vals[0] + vals[2] + vals[3] + vals[4]; - local->stats.tx_errors = vals[42] + local->stats.tx_fifo_errors; - local->stats.multicast = vals[43]; - local->stats.collisions = vals[89]; - - /* detailed rx_errors: */ - local->stats.rx_length_errors = vals[3]; - local->stats.rx_crc_errors = vals[4]; - local->stats.rx_frame_errors = vals[2]; - local->stats.rx_fifo_errors = vals[0]; +struct net_device_stats *airo_get_stats(struct net_device *dev) +{ + struct airo_info *local = dev->priv; + + /* Get stats out of the card if available */ + airo_read_stats(local); return &local->stats; } @@ -1507,9 +1549,9 @@ memcpy (ai->config.macAddr, addr->sa_data, dev->addr_len); ai->need_commit = 1; - disable_MAC(ai); - writeConfigRid (ai); - enable_MAC(ai, &rsp); + disable_MAC(ai, 1); + writeConfigRid (ai, 1); + enable_MAC(ai, &rsp, 1); memcpy (ai->dev->dev_addr, addr->sa_data, dev->addr_len); if (ai->wifidev) memcpy (ai->wifidev->dev_addr, addr->sa_data, dev->addr_len); @@ -1538,7 +1580,7 @@ * stack (i.e. the network stack won't try to broadcast * anything on the interface and routes are gone. Jean II */ ai->flags |= FLAG_RADIO_DOWN; - disable_MAC(ai); + disable_MAC(ai, 1); #endif disable_interrupts( ai ); } @@ -1762,6 +1804,9 @@ int i; struct airo_info *ai = dev->priv; + + if (down_interruptible(&ai->sem)) + return -1; waitbusy (ai); OUT4500(ai,COMMAND,CMD_SOFTRESET); set_current_state (TASK_UNINTERRUPTIBLE); @@ -1771,6 +1816,7 @@ schedule_timeout (HZ/5); if ( setup_card(ai, dev->dev_addr ) != SUCCESS ) { printk( KERN_ERR "airo: MAC could not be enabled\n" ); + up(&ai->sem); return -1; } else { printk( KERN_INFO "airo: MAC enabled %s %x:%x:%x:%x:%x:%x\n", @@ -1788,6 +1834,7 @@ } enable_interrupts( ai ); netif_wake_queue(dev); + up(&ai->sem); return 0; } @@ -1800,9 +1847,7 @@ StatusRid status_rid; if (down_trylock(&ai->sem) == 0) { - __set_bit(FLAG_LOCKED, &ai->flags); - PC4500_readrid(ai, RID_STATUS, &status_rid, sizeof(status_rid)); - clear_bit(FLAG_LOCKED, &ai->flags); + PC4500_readrid(ai, RID_STATUS, &status_rid, sizeof(status_rid), 0); up(&ai->sem); wrqu.data.length = 0; wrqu.data.flags = 0; @@ -1823,9 +1868,7 @@ MICRid mic_rid; if (down_trylock(&ai->sem) == 0) { - __set_bit(FLAG_LOCKED, &ai->flags); - PC4500_readrid(ai, RID_MIC, &mic_rid, sizeof(mic_rid)); - clear_bit(FLAG_LOCKED, &ai->flags); + PC4500_readrid(ai, RID_MIC, &mic_rid, sizeof(mic_rid), 0); up(&ai->sem); #ifdef MICSUPPORT micinit (ai, &mic_rid); @@ -1866,7 +1909,8 @@ if ( status & EV_MIC ) { OUT4500( apriv, EVACK, EV_MIC ); - airo_read_mic( apriv ); + if (apriv->flags & FLAG_MIC_CAPABLE) + airo_read_mic( apriv ); } if ( status & EV_LINK ) { #if WIRELESS_EXT > 13 @@ -2057,6 +2101,28 @@ } } if (len) { +#if 0 && WIRELESS_EXT > 15 +#ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */ + if (apriv->spy_data.spy_number > 0) { + char *sa; + struct iw_quality wstats; + /* Prepare spy data : addr + qual */ + sa = (char*)buffer + ((apriv->flags & FLAG_802_11) ? 10 : 6); + if (!(apriv->flags & FLAG_802_11)) { + bap_setup (apriv, fid, 8, BAP0); + bap_read (apriv, (u16*)hdr.rssi, 2, BAP0); + } + wstats.qual = hdr.rssi[0]; + if (apriv->rssi) + wstats.level = 0x100 - apriv->rssi[hdr.rssi[1]].rssidBm; + else + wstats.level = (hdr.rssi[1] + 321) / 2; + wstats.updated = 3; + /* Update spy records */ + wireless_spy_update(dev, sa, &wstats); + } +#endif /* IW_WIRELESS_SPY */ +#else /* WIRELESS_EXT > 15 */ #ifdef WIRELESS_SPY if (apriv->spy_number > 0) { int i; @@ -2082,6 +2148,7 @@ } } #endif /* WIRELESS_SPY */ +#endif /* WIRELESS_EXT > 15 */ OUT4500( apriv, EVACK, EV_RX); if (apriv->flags & FLAG_802_11) { @@ -2113,17 +2180,17 @@ if ( ( apriv->fids[i] & 0xffff ) == fid ) { len = apriv->fids[i] >> 16; index = i; - /* Set up to be used again */ - apriv->fids[i] &= 0xffff; } } if (index != -1) { - netif_wake_queue(dev); if (status & EV_TXEXC) get_tx_error(apriv, index); - } - OUT4500( apriv, EVACK, status & (EV_TX | EV_TXEXC)); - if (index==-1) { + OUT4500( apriv, EVACK, status & (EV_TX | EV_TXEXC)); + /* Set up to be used again */ + apriv->fids[index] &= 0xffff; + netif_wake_queue(dev); + } else { + OUT4500( apriv, EVACK, status & (EV_TX | EV_TXEXC)); printk( KERN_ERR "airo: Unallocated FID was used to xmit\n" ); } } @@ -2169,7 +2236,7 @@ return rc; } -static int enable_MAC( struct airo_info *ai, Resp *rsp ) { +static int enable_MAC( struct airo_info *ai, Resp *rsp, int lock ) { int rc; Cmd cmd; @@ -2182,7 +2249,7 @@ if (ai->flags & (FLAG_RADIO_OFF|FLAG_RADIO_DOWN)) return SUCCESS; memset(&cmd, 0, sizeof(cmd)); cmd.cmd = MAC_ENABLE; - if (test_bit(FLAG_LOCKED, &ai->flags) != 0) + if (!lock) return issuecommand(ai, &cmd, rsp); if (down_interruptible(&ai->sem)) @@ -2192,13 +2259,13 @@ return rc; } -static void disable_MAC( struct airo_info *ai ) { +static void disable_MAC( struct airo_info *ai, int lock ) { Cmd cmd; Resp rsp; memset(&cmd, 0, sizeof(cmd)); cmd.cmd = MAC_DISABLE; // disable in case already enabled - if (test_bit(FLAG_LOCKED, &ai->flags) != 0) { + if (!lock) { issuecommand(ai, &cmd, &rsp); return; } @@ -2276,13 +2343,13 @@ CapabilityRid cap_rid; // general configuration (read/modify/write) - status = readConfigRid(ai); + status = readConfigRid(ai, 1); if ( status != SUCCESS ) return ERROR; status = readCapabilityRid(ai, &cap_rid); if ( status != SUCCESS ) return ERROR; - status = PC4500_readrid(ai,RID_RSSI,&rssi_rid,sizeof(rssi_rid)); + status = PC4500_readrid(ai,RID_RSSI,&rssi_rid,sizeof(rssi_rid),1); if ( status == SUCCESS ) { if (ai->rssi || (ai->rssi = kmalloc(512, GFP_KERNEL)) != NULL) memcpy(ai->rssi, (u8*)&rssi_rid + 2, 512); @@ -2346,14 +2413,14 @@ } } - status = writeConfigRid(ai); + status = writeConfigRid(ai, 1); if ( status != SUCCESS ) return ERROR; /* Set up the SSID list */ status = writeSsidRid(ai, &mySsid); if ( status != SUCCESS ) return ERROR; - status = enable_MAC(ai, &rsp); + status = enable_MAC(ai, &rsp, 1); if ( status != SUCCESS || (rsp.status & 0xFF00) != 0) { printk( KERN_ERR "airo: Bad MAC enable reason = %x, rid = %x, offset = %d\n", rsp.rsp0, rsp.rsp1, rsp.rsp2 ); return ERROR; @@ -2568,13 +2635,12 @@ /* Note, that we are using BAP1 which is also used by transmit, so * we must get a lock. */ -static int PC4500_readrid(struct airo_info *ai, u16 rid, void *pBuf, int len) +static int PC4500_readrid(struct airo_info *ai, u16 rid, void *pBuf, int len, int lock) { - u16 status, dolock = 0; + u16 status; int rc = SUCCESS; - if (test_bit(FLAG_LOCKED, &ai->flags) == 0) { - dolock = 1; + if (lock) { if (down_interruptible(&ai->sem)) return ERROR; } @@ -2602,7 +2668,7 @@ // read remainder of the rid rc = bap_read(ai, ((u16*)pBuf)+1, len, BAP1); done: - if (dolock) + if (lock) up(&ai->sem); return rc; } @@ -2610,13 +2676,14 @@ /* Note, that we are using BAP1 which is also used by transmit, so * make sure this isnt called when a transmit is happening */ static int PC4500_writerid(struct airo_info *ai, u16 rid, - const void *pBuf, int len) + const void *pBuf, int len, int lock) { - u16 status, dolock = 0; + u16 status; int rc = SUCCESS; - if (test_bit(FLAG_LOCKED, &ai->flags) == 0) { - dolock = 1; + *(u16*)pBuf = cpu_to_le16((u16)len); + + if (lock) { if (down_interruptible(&ai->sem)) return ERROR; } @@ -2634,7 +2701,7 @@ // ---now commit the rid data rc = PC4500_accessrid(ai, rid, 0x100|CMD_ACCESS); done: - if (dolock) + if (lock) up(&ai->sem); return rc; } @@ -2653,11 +2720,11 @@ if (down_interruptible(&ai->sem)) return ERROR; if (issuecommand(ai, &cmd, &rsp) != SUCCESS) { - txFid = 0; + txFid = ERROR; goto done; } if ( (rsp.status & 0xFF00) != 0) { - txFid = 0; + txFid = ERROR; goto done; } /* wait for the allocate event/indication @@ -2704,7 +2771,7 @@ len >>= 16; - if (len < ETH_ALEN * 2) { + if (len <= ETH_ALEN * 2) { printk( KERN_WARNING "Short packet %d\n", len ); return ERROR; } @@ -3160,7 +3227,7 @@ return -ENOMEM; } - readStatsRid(apriv, &stats, rid); + readStatsRid(apriv, &stats, rid, 1); j = 0; for(i=0; statsLabels[i]!=(char *)-1 && @@ -3195,18 +3262,21 @@ return value; } +static int airo_config_commit(struct net_device *dev, + struct iw_request_info *info, void *zwrq, + char *extra); + static void proc_config_on_close( struct inode *inode, struct file *file ) { struct proc_data *data = file->private_data; struct proc_dir_entry *dp = PDE(inode); struct net_device *dev = dp->data; struct airo_info *ai = dev->priv; - Resp rsp; char *line; - int need_reset = 0; if ( !data->writelen ) return; - readConfigRid(ai); + readConfigRid(ai, 1); + ai->need_commit = 1; line = data->wbuffer; while( line[0] ) { @@ -3214,7 +3284,7 @@ if ( !strncmp( line, "Mode: ", 6 ) ) { line += 6; if ((ai->config.rmode & 0xff) >= RXMODE_RFMON) - need_reset = 1; + ai->need_commit = 2; ai->config.rmode &= 0xfe00; ai->flags &= ~FLAG_802_11; ai->config.opmode &= 0xFF00; @@ -3392,22 +3462,7 @@ while( line[0] && line[0] != '\n' ) line++; if ( line[0] ) line++; } - disable_MAC(ai); - if (need_reset) { - APListRid APList_rid; - SsidRid SSID_rid; - - readAPListRid(ai, &APList_rid); - readSsidRid(ai, &SSID_rid); - reset_airo_card(dev); - disable_MAC(ai); - writeSsidRid(ai, &SSID_rid); - writeAPListRid(ai, &APList_rid); - } - writeConfigRid(ai); - enable_MAC(ai, &rsp); - if (need_reset) - airo_set_promisc(ai); + airo_config_commit(dev, NULL, NULL, NULL); } static char *get_rmode(u16 mode) { @@ -3443,7 +3498,7 @@ data->maxwritelen = 2048; data->on_close = proc_config_on_close; - readConfigRid(ai); + readConfigRid(ai, 1); i = sprintf( data->rbuffer, "Mode: %s\n" @@ -3535,9 +3590,9 @@ offset < data->writelen ) offset++; offset++; } - disable_MAC(ai); + disable_MAC(ai, 1); writeSsidRid(ai, &SSID_rid); - enable_MAC(ai, &rsp); + enable_MAC(ai, &rsp, 1); } inline static u8 hexVal(char c) { @@ -3576,20 +3631,20 @@ } } } - disable_MAC(ai); + disable_MAC(ai, 1); writeAPListRid(ai, &APList_rid); - enable_MAC(ai, &rsp); + enable_MAC(ai, &rsp, 1); } /* This function wraps PC4500_writerid with a MAC disable */ static int do_writerid( struct airo_info *ai, u16 rid, const void *rid_data, - int len ) { + int len, int dummy ) { int rc; Resp rsp; - disable_MAC(ai); - rc = PC4500_writerid(ai, rid, rid_data, len); - enable_MAC(ai, &rsp); + disable_MAC(ai, 1); + rc = PC4500_writerid(ai, rid, rid_data, len, 1); + enable_MAC(ai, &rsp, 1); return rc; } @@ -3617,7 +3672,7 @@ } static int set_wep_key(struct airo_info *ai, u16 index, - const char *key, u16 keylen, int perm ) { + const char *key, u16 keylen, int perm, int lock ) { static const unsigned char macaddr[ETH_ALEN] = { 0x01, 0, 0, 0, 0, 0 }; WepKeyRid wkr; @@ -3639,7 +3694,7 @@ printk(KERN_INFO "Setting key %d\n", index); } - writeWepKeyRid(ai, &wkr, perm); + writeWepKeyRid(ai, &wkr, perm, lock); return 0; } @@ -3662,7 +3717,7 @@ (data->wbuffer[1] == ' ' || data->wbuffer[1] == '\n')) { index = data->wbuffer[0] - '0'; if (data->wbuffer[1] == '\n') { - set_wep_key(ai, index, 0, 0, 1); + set_wep_key(ai, index, 0, 0, 1, 1); return; } j = 2; @@ -3681,7 +3736,7 @@ break; } } - set_wep_key(ai, index, key, i/3, 1); + set_wep_key(ai, index, key, i/3, 1, 1); } static int proc_wepkey_open( struct inode *inode, struct file *file ) { @@ -3928,10 +3983,9 @@ add_timer(&apriv->timer); return; } - __set_bit(FLAG_LOCKED, &apriv->flags); - readConfigRid(apriv); - disable_MAC(apriv); + readConfigRid(apriv, 0); + disable_MAC(apriv, 0); switch(apriv->config.authType) { case AUTH_ENCRYPT: /* So drop to OPEN */ @@ -3939,13 +3993,13 @@ break; case AUTH_SHAREDKEY: if (apriv->keyindex < auto_wep) { - set_wep_key(apriv, apriv->keyindex, 0, 0, 0); + set_wep_key(apriv, apriv->keyindex, 0, 0, 0, 0); apriv->config.authType = AUTH_SHAREDKEY; apriv->keyindex++; } else { /* Drop to ENCRYPT */ apriv->keyindex = 0; - set_wep_key(apriv, apriv->defindex, 0, 0, 0); + set_wep_key(apriv, apriv->defindex, 0, 0, 0, 0); apriv->config.authType = AUTH_ENCRYPT; } break; @@ -3953,9 +4007,8 @@ apriv->config.authType = AUTH_SHAREDKEY; } apriv->need_commit = 1; - writeConfigRid(apriv); - enable_MAC(apriv, &rsp); - clear_bit(FLAG_LOCKED, &apriv->flags); + writeConfigRid(apriv, 0); + enable_MAC(apriv, &rsp, 0); up(&apriv->sem); /* Schedule check to see if the change worked */ @@ -4135,9 +4188,11 @@ struct airo_info *local = dev->priv; StatusRid status_rid; /* Card status info */ - readStatusRid(local, &status_rid); + if ((local->config.opmode & 0xFF) == MODE_STA_ESS) + status_rid.channel = local->config.channelSet; + else + readStatusRid(local, &status_rid); - /* Will return zero in infrastructure mode */ #ifdef WEXT_USECHANNELS fwrq->m = ((int)status_rid.channel) + 1; fwrq->e = 0; @@ -4191,9 +4246,9 @@ SSID_rid.ssids[index].len = dwrq->length - 1; } /* Write it to the card */ - disable_MAC(local); + disable_MAC(local, 1); writeSsidRid(local, &SSID_rid); - enable_MAC(local, &rsp); + enable_MAC(local, &rsp, 1); return 0; } @@ -4255,9 +4310,9 @@ memset(&APList_rid, 0, sizeof(APList_rid)); APList_rid.len = sizeof(APList_rid); memcpy(APList_rid.ap[0], awrq->sa_data, ETH_ALEN); - disable_MAC(local); + disable_MAC(local, 1); writeAPListRid(local, &APList_rid); - enable_MAC(local, &rsp); + enable_MAC(local, &rsp, 1); } return 0; } @@ -4506,28 +4561,47 @@ char *extra) { struct airo_info *local = dev->priv; + int commit = 1; + + if ((local->config.rmode & 0xff) >= RXMODE_RFMON) + commit = 2; switch(*uwrq) { case IW_MODE_ADHOC: local->config.opmode &= 0xFF00; local->config.opmode |= MODE_STA_IBSS; + local->config.rmode &= 0xfe00; + local->flags &= ~FLAG_802_11; break; case IW_MODE_INFRA: local->config.opmode &= 0xFF00; local->config.opmode |= MODE_STA_ESS; + local->config.rmode &= 0xfe00; + local->flags &= ~FLAG_802_11; break; case IW_MODE_MASTER: local->config.opmode &= 0xFF00; local->config.opmode |= MODE_AP; + local->config.rmode &= 0xfe00; + local->flags &= ~FLAG_802_11; break; case IW_MODE_REPEAT: local->config.opmode &= 0xFF00; local->config.opmode |= MODE_AP_RPTR; + local->config.rmode &= 0xfe00; + local->flags &= ~FLAG_802_11; + break; + case IW_MODE_MONITOR: + local->config.opmode &= 0xFF00; + local->config.opmode |= MODE_STA_ESS; + local->config.rmode &= 0xfe00; + local->config.rmode |= RXMODE_RFMON | RXMODE_DISABLE_802_3_HEADER; + local->flags |= FLAG_802_11; break; default: return -EINVAL; } - local->need_commit = 1; + local->need_commit = commit; return -EINPROGRESS; /* Call commit handler */ } @@ -4613,7 +4687,7 @@ /* Copy the key in the driver */ memcpy(key.key, extra, dwrq->length); /* Send the key to the card */ - set_wep_key(local, index, key.key, key.len, 1); + set_wep_key(local, index, key.key, key.len, 1, 1); } /* WE specify that if a valid key is set, encryption * should be enabled (user may turn it off later) @@ -4627,7 +4701,7 @@ /* Do we want to just set the transmit key index ? */ int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; if ((index>=0) && (index<(cap_rid.softCap&0x80)?4:1)) { - set_wep_key(local, index, 0, 0, 1); + set_wep_key(local, index, 0, 0, 1, 1); } else /* Don't complain if only change the mode */ if(!dwrq->flags & IW_ENCODE_MODE) { @@ -5272,7 +5346,7 @@ * consequences are begnign. So I don't bother fixing it - Javier */ /* Try to read the first entry of the scan result */ - rc = PC4500_readrid(ai, RID_BSSLISTFIRST, &BSSList, sizeof(BSSList)); + rc = PC4500_readrid(ai, RID_BSSLISTFIRST, &BSSList, sizeof(BSSList), 1); if((rc) || (BSSList.index == 0xffff)) { /* Client error, no scan results... * The caller need to restart the scan. */ @@ -5288,7 +5362,7 @@ /* Read next entry */ rc = PC4500_readrid(ai, RID_BSSLISTNEXT, - &BSSList, sizeof(BSSList)); + &BSSList, sizeof(BSSList), 1); } /* Length of data */ dwrq->length = (current_ev - extra); @@ -5298,6 +5372,7 @@ } #endif /* WIRELESS_EXT > 13 */ +#if WIRELESS_EXT <= 15 #ifdef WIRELESS_SPY /*------------------------------------------------------------------*/ /* @@ -5360,6 +5435,7 @@ return 0; } #endif /* WIRELESS_SPY */ +#endif /* WIRELESS_EXT <= 15 */ /*------------------------------------------------------------------*/ /* @@ -5378,9 +5454,22 @@ /* Some of the "SET" function may have modified some of the * parameters. It's now time to commit them in the card */ - disable_MAC(local); - writeConfigRid(local); - enable_MAC(local, &rsp); + disable_MAC(local, 1); + if (local->need_commit > 1) { + APListRid APList_rid; + SsidRid SSID_rid; + + readAPListRid(local, &APList_rid); + readSsidRid(local, &SSID_rid); + reset_airo_card(dev); + disable_MAC(local, 1); + writeSsidRid(local, &SSID_rid); + writeAPListRid(local, &APList_rid); + } + writeConfigRid(local, 1); + enable_MAC(local, &rsp, 1); + if (local->need_commit > 1) + airo_set_promisc(local); return 0; } @@ -5417,6 +5506,12 @@ (iw_handler) NULL, /* SIOCGIWPRIV */ (iw_handler) NULL, /* SIOCSIWSTATS */ (iw_handler) NULL, /* SIOCGIWSTATS */ +#if WIRELESS_EXT > 15 + iw_handler_set_spy, /* SIOCSIWSPY */ + iw_handler_get_spy, /* SIOCGIWSPY */ + iw_handler_set_thrspy, /* SIOCSIWTHRSPY */ + iw_handler_get_thrspy, /* SIOCGIWTHRSPY */ +#else /* WIRELESS_EXT > 15 */ #ifdef WIRELESS_SPY (iw_handler) airo_set_spy, /* SIOCSIWSPY */ (iw_handler) airo_get_spy, /* SIOCGIWSPY */ @@ -5426,6 +5521,7 @@ #endif /* WIRELESS_SPY */ (iw_handler) NULL, /* -- hole -- */ (iw_handler) NULL, /* -- hole -- */ +#endif /* WIRELESS_EXT > 15 */ (iw_handler) airo_set_wap, /* SIOCSIWAP */ (iw_handler) airo_get_wap, /* SIOCGIWAP */ (iw_handler) NULL, /* -- hole -- */ @@ -5479,6 +5575,11 @@ .standard = (iw_handler *) airo_handler, .private = (iw_handler *) airo_private_handler, .private_args = (struct iw_priv_args *) airo_private_args, +#if 0 && WIRELESS_EXT > 15 + .spy_offset = ((void *) (&((struct airo_info *) NULL)->spy_data) - + (void *) NULL), +#endif /* WIRELESS_EXT > 15 */ + }; #endif /* WIRELESS_EXT > 12 */ @@ -5864,7 +5965,7 @@ /* Get stats out of the card */ readStatusRid(local, &status_rid); - readStatsRid(local, &stats_rid, RID_STATS); + readStatsRid(local, &stats_rid, RID_STATS, 1); /* The status */ local->wstats.status = status_rid.mode; @@ -5902,18 +6003,14 @@ unsigned short ridcode; unsigned char *iobuf; struct airo_info *ai = dev->priv; - int ret = 0; if (ai->flags & FLAG_FLASHING) return -EIO; - iobuf = kmalloc(RIDS_SIZE, GFP_KERNEL); - if (!iobuf) - return -ENOMEM; switch(comp->command) { case AIROGCAP: ridcode = RID_CAPABILITIES; break; - case AIROGCFG: writeConfigRid (ai); + case AIROGCFG: writeConfigRid (ai, 1); ridcode = RID_CONFIG; break; case AIROGSLIST: ridcode = RID_SSID; break; case AIROGVLIST: ridcode = RID_APLIST; break; @@ -5921,17 +6018,13 @@ case AIROGEHTENC: ridcode = RID_ETHERENCAP; break; case AIROGWEPKTMP: ridcode = RID_WEP_TEMP; /* Only super-user can read WEP keys */ - if (!capable(CAP_NET_ADMIN)) { - ret = -EPERM; - goto rr_free; - } + if (!capable(CAP_NET_ADMIN)) + return -EPERM; break; case AIROGWEPKNV: ridcode = RID_WEP_PERM; /* Only super-user can read WEP keys */ - if (!capable(CAP_NET_ADMIN)) { - ret = -EPERM; - goto rr_free; - } + if (!capable(CAP_NET_ADMIN)) + return -EPERM; break; case AIROGSTAT: ridcode = RID_STATUS; break; case AIROGSTATSD32: ridcode = RID_STATSDELTA; break; @@ -5939,25 +6032,29 @@ case AIROGMICSTATS: if (copy_to_user(comp->data, &ai->micstats, min((int)comp->len,(int)sizeof(ai->micstats)))) - ret = -EFAULT; - goto rr_free; + return -EFAULT; + return 0; default: - ret = -EINVAL; - goto rr_free; + return -EINVAL; + break; } - PC4500_readrid(ai,ridcode,iobuf,RIDS_SIZE); + if ((iobuf = kmalloc(RIDS_SIZE, GFP_KERNEL)) == NULL) + return -ENOMEM; + + PC4500_readrid(ai,ridcode,iobuf,RIDS_SIZE, 1); /* get the count of bytes in the rid docs say 1st 2 bytes is it. * then return it to the user * 9/22/2000 Honor user given length */ if (copy_to_user(comp->data, iobuf, - min((int)comp->len, (int)RIDS_SIZE))) - ret = -EFAULT; -rr_free: - kfree(iobuf); - return ret; + min((int)comp->len, (int)RIDS_SIZE))) { + kfree (iobuf); + return -EFAULT; + } + kfree (iobuf); + return 0; } /* @@ -5968,9 +6065,8 @@ struct airo_info *ai = dev->priv; int ridcode, enabled; Resp rsp; - static int (* writer)(struct airo_info *, u16 rid, const void *, int); + static int (* writer)(struct airo_info *, u16 rid, const void *, int, int); unsigned char *iobuf; - int ret = 0; /* Only super-user can write RIDs */ if (!capable(CAP_NET_ADMIN)) @@ -5979,10 +6075,6 @@ if (ai->flags & FLAG_FLASHING) return -EIO; - iobuf = kmalloc(RIDS_SIZE, GFP_KERNEL); - if (!iobuf) - return -ENOMEM; - ridcode = 0; writer = do_writerid; @@ -6003,47 +6095,52 @@ * same with MAC off */ case AIROPMACON: - if (enable_MAC(ai, &rsp) != 0) - ret = -EIO; - goto wr_free; + if (enable_MAC(ai, &rsp, 1) != 0) + return -EIO; + return 0; /* * Evidently this code in the airo driver does not get a symbol * as disable_MAC. it's probably so short the compiler does not gen one. */ case AIROPMACOFF: - disable_MAC(ai); - goto wr_free; + disable_MAC(ai, 1); + return 0; /* This command merely clears the counts does not actually store any data * only reads rid. But as it changes the cards state, I put it in the * writerid routines. */ case AIROPSTCLR: - PC4500_readrid(ai,RID_STATSDELTACLEAR,iobuf,RIDS_SIZE); + if ((iobuf = kmalloc(RIDS_SIZE, GFP_KERNEL)) == NULL) + return -ENOMEM; + + PC4500_readrid(ai,RID_STATSDELTACLEAR,iobuf,RIDS_SIZE, 1); enabled = ai->micstats.enabled; memset(&ai->micstats,0,sizeof(ai->micstats)); ai->micstats.enabled = enabled; if (copy_to_user(comp->data, iobuf, - min((int)comp->len, (int)RIDS_SIZE))) - ret = -EFAULT; - goto wr_free; + min((int)comp->len, (int)RIDS_SIZE))) { + kfree (iobuf); + return -EFAULT; + } + kfree (iobuf); + return 0; default: - ret = -EOPNOTSUPP; /* Blarg! */ - goto wr_free; + return -EOPNOTSUPP; /* Blarg! */ } + if(comp->len > RIDS_SIZE) + return -EINVAL; - if (comp->len > RIDS_SIZE) { - ret = -EINVAL; - goto wr_free; - } + if ((iobuf = kmalloc(RIDS_SIZE, GFP_KERNEL)) == NULL) + return -ENOMEM; if (copy_from_user(iobuf,comp->data,comp->len)) { - ret = -EFAULT; - goto wr_free; + kfree (iobuf); + return -EFAULT; } if (comp->command == AIROPCFG) { @@ -6058,11 +6155,12 @@ ai->flags &= ~FLAG_ADHOC; } - if((*writer)(ai, ridcode, iobuf,comp->len)) - ret = -EIO; -wr_free: - kfree(iobuf); - return ret; + if((*writer)(ai, ridcode, iobuf,comp->len,1)) { + kfree (iobuf); + return -EIO; + } + kfree (iobuf); + return 0; } /***************************************************************************** @@ -6140,7 +6238,7 @@ */ int cmdreset(struct airo_info *ai) { - disable_MAC(ai); + disable_MAC(ai, 1); if(!waitbusy (ai)){ printk(KERN_INFO "Waitbusy hang before RESET\n"); diff -Nru a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c --- a/drivers/net/wireless/ray_cs.c Sun Jul 27 10:13:44 2003 +++ b/drivers/net/wireless/ray_cs.c Sun Jul 27 10:13:44 2003 @@ -25,6 +25,8 @@ * - reorganize kmallocs in ray_attach, checking all for failure * and releasing the previous allocations if one fails * + * Daniele Bellucci - 07/10/2003 + * - Audit copy_to_user in ioctl(SIOCGIWESSID) * =============================================================================*/ @@ -1315,7 +1317,8 @@ /* Push it out ! */ wrq->u.data.length = strlen(essid) + 1; wrq->u.data.flags = 1; /* active */ - copy_to_user(wrq->u.data.pointer, essid, sizeof(essid)); + if (copy_to_user(wrq->u.data.pointer, essid, sizeof(essid))) + err = -EFAULT; } break; diff -Nru a/drivers/net/wireless/wl3501.h b/drivers/net/wireless/wl3501.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/wl3501.h Sun Jul 27 10:13:53 2003 @@ -0,0 +1,552 @@ +#ifndef __WL3501_H__ +#define __WL3501_H__ + +#include +#include "ieee802_11.h" + +/* define for WLA 2.0 */ +#define WL3501_BLKSZ 256 +/* + * ID for input Signals of DRIVER block + * bit[7-5] is block ID: 000 + * bit[4-0] is signal ID +*/ +enum wl3501_signals { + WL3501_SIG_ALARM, + WL3501_SIG_MD_CONFIRM, + WL3501_SIG_MD_IND, + WL3501_SIG_ASSOC_CONFIRM, + WL3501_SIG_ASSOC_IND, + WL3501_SIG_AUTH_CONFIRM, + WL3501_SIG_AUTH_IND, + WL3501_SIG_DEAUTH_CONFIRM, + WL3501_SIG_DEAUTH_IND, + WL3501_SIG_DISASSOC_CONFIRM, + WL3501_SIG_DISASSOC_IND, + WL3501_SIG_GET_CONFIRM, + WL3501_SIG_JOIN_CONFIRM, + WL3501_SIG_PWR_MGMT_CONFIRM, + WL3501_SIG_REASSOC_CONFIRM, + WL3501_SIG_REASSOC_IND, + WL3501_SIG_SCAN_CONFIRM, + WL3501_SIG_SET_CONFIRM, + WL3501_SIG_START_CONFIRM, + WL3501_SIG_RESYNC_CONFIRM, + WL3501_SIG_SITE_CONFIRM, + WL3501_SIG_SAVE_CONFIRM, + WL3501_SIG_RFTEST_CONFIRM, +/* + * ID for input Signals of MLME block + * bit[7-5] is block ID: 010 + * bit[4-0] is signal ID + */ + WL3501_SIG_ASSOC_REQ = 0x20, + WL3501_SIG_AUTH_REQ, + WL3501_SIG_DEAUTH_REQ, + WL3501_SIG_DISASSOC_REQ, + WL3501_SIG_GET_REQ, + WL3501_SIG_JOIN_REQ, + WL3501_SIG_PWR_MGMT_REQ, + WL3501_SIG_REASSOC_REQ, + WL3501_SIG_SCAN_REQ, + WL3501_SIG_SET_REQ, + WL3501_SIG_START_REQ, + WL3501_SIG_MD_REQ, + WL3501_SIG_RESYNC_REQ, + WL3501_SIG_SITE_REQ, + WL3501_SIG_SAVE_REQ, + WL3501_SIG_RF_TEST_REQ, + WL3501_SIG_MM_CONFIRM = 0x60, + WL3501_SIG_MM_IND, +}; + +enum wl3501_mib_attribs { + WL3501_MIB_ATTR_STATION_ID, + WL3501_MIB_ATTR_AUTH_ALGORITHMS, + WL3501_MIB_ATTR_AUTH_TYPE, + WL3501_MIB_ATTR_MEDIUM_OCCUPANCY_LIMIT, + WL3501_MIB_ATTR_CF_POLLABLE, + WL3501_MIB_ATTR_CFP_PERIOD, + WL3501_MIB_ATTR_CFPMAX_DURATION, + WL3501_MIB_ATTR_AUTH_RESP_TMOUT, + WL3501_MIB_ATTR_RX_DTIMS, + WL3501_MIB_ATTR_PRIV_OPT_IMPLEMENTED, + WL3501_MIB_ATTR_PRIV_INVOKED, + WL3501_MIB_ATTR_WEP_DEFAULT_KEYS, + WL3501_MIB_ATTR_WEP_DEFAULT_KEY_ID, + WL3501_MIB_ATTR_WEP_KEY_MAPPINGS, + WL3501_MIB_ATTR_WEP_KEY_MAPPINGS_LEN, + WL3501_MIB_ATTR_EXCLUDE_UNENCRYPTED, + WL3501_MIB_ATTR_WEP_ICV_ERROR_COUNT, + WL3501_MIB_ATTR_WEP_UNDECRYPTABLE_COUNT, + WL3501_MIB_ATTR_WEP_EXCLUDED_COUNT, + WL3501_MIB_ATTR_MAC_ADDR, + WL3501_MIB_ATTR_GROUP_ADDRS, + WL3501_MIB_ATTR_RTS_THRESHOLD, + WL3501_MIB_ATTR_SHORT_RETRY_LIMIT, + WL3501_MIB_ATTR_LONG_RETRY_LIMIT, + WL3501_MIB_ATTR_FRAG_THRESHOLD, + WL3501_MIB_ATTR_MAX_TX_MSDU_LIFETIME, + WL3501_MIB_ATTR_MAX_RX_LIFETIME, + WL3501_MIB_ATTR_MANUFACTURER_ID, + WL3501_MIB_ATTR_PRODUCT_ID, + WL3501_MIB_ATTR_TX_FRAG_COUNT, + WL3501_MIB_ATTR_MULTICAST_TX_FRAME_COUNT, + WL3501_MIB_ATTR_FAILED_COUNT, + WL3501_MIB_ATTR_RX_FRAG_COUNT, + WL3501_MIB_ATTR_MULTICAST_RX_COUNT, + WL3501_MIB_ATTR_FCS_ERROR_COUNT, + WL3501_MIB_ATTR_RETRY_COUNT, + WL3501_MIB_ATTR_MULTIPLE_RETRY_COUNT, + WL3501_MIB_ATTR_RTS_SUCCESS_COUNT, + WL3501_MIB_ATTR_RTS_FAILURE_COUNT, + WL3501_MIB_ATTR_ACK_FAILURE_COUNT, + WL3501_MIB_ATTR_FRAME_DUPLICATE_COUNT, + WL3501_MIB_ATTR_PHY_TYPE, + WL3501_MIB_ATTR_REG_DOMAINS_SUPPORT, + WL3501_MIB_ATTR_CURRENT_REG_DOMAIN, + WL3501_MIB_ATTR_SLOT_TIME, + WL3501_MIB_ATTR_CCA_TIME, + WL3501_MIB_ATTR_RX_TX_TURNAROUND_TIME, + WL3501_MIB_ATTR_TX_PLCP_DELAY, + WL3501_MIB_ATTR_RX_TX_SWITCH_TIME, + WL3501_MIB_ATTR_TX_RAMP_ON_TIME, + WL3501_MIB_ATTR_TX_RF_DELAY, + WL3501_MIB_ATTR_SIFS_TIME, + WL3501_MIB_ATTR_RX_RF_DELAY, + WL3501_MIB_ATTR_RX_PLCP_DELAY, + WL3501_MIB_ATTR_MAC_PROCESSING_DELAY, + WL3501_MIB_ATTR_TX_RAMP_OFF_TIME, + WL3501_MIB_ATTR_PREAMBLE_LEN, + WL3501_MIB_ATTR_PLCP_HEADER_LEN, + WL3501_MIB_ATTR_MPDU_DURATION_FACTOR, + WL3501_MIB_ATTR_AIR_PROPAGATION_TIME, + WL3501_MIB_ATTR_TEMP_TYPE, + WL3501_MIB_ATTR_CW_MIN, + WL3501_MIB_ATTR_CW_MAX, + WL3501_MIB_ATTR_SUPPORT_DATA_RATES_TX, + WL3501_MIB_ATTR_SUPPORT_DATA_RATES_RX, + WL3501_MIB_ATTR_MPDU_MAX_LEN, + WL3501_MIB_ATTR_SUPPORT_TX_ANTENNAS, + WL3501_MIB_ATTR_CURRENT_TX_ANTENNA, + WL3501_MIB_ATTR_SUPPORT_RX_ANTENNAS, + WL3501_MIB_ATTR_DIVERSITY_SUPPORT, + WL3501_MIB_ATTR_DIVERSITY_SELECTION_RS, + WL3501_MIB_ATTR_NR_SUPPORTED_PWR_LEVELS, + WL3501_MIB_ATTR_TX_PWR_LEVEL1, + WL3501_MIB_ATTR_TX_PWR_LEVEL2, + WL3501_MIB_ATTR_TX_PWR_LEVEL3, + WL3501_MIB_ATTR_TX_PWR_LEVEL4, + WL3501_MIB_ATTR_TX_PWR_LEVEL5, + WL3501_MIB_ATTR_TX_PWR_LEVEL6, + WL3501_MIB_ATTR_TX_PWR_LEVEL7, + WL3501_MIB_ATTR_TX_PWR_LEVEL8, + WL3501_MIB_ATTR_CURRENT_TX_PWR_LEVEL, + WL3501_MIB_ATTR_CURRENT_CHAN, + WL3501_MIB_ATTR_CCA_MODE_SUPPORTED, + WL3501_MIB_ATTR_CURRENT_CCA_MODE, + WL3501_MIB_ATTR_ED_THRESHOLD, + WL3501_MIB_ATTR_SINTHESIZER_LOCKED, + WL3501_MIB_ATTR_CURRENT_PWR_STATE, + WL3501_MIB_ATTR_DOZE_TURNON_TIME, + WL3501_MIB_ATTR_RCR33, + WL3501_MIB_ATTR_DEFAULT_CHAN, + WL3501_MIB_ATTR_SSID, + WL3501_MIB_ATTR_PWR_MGMT_ENABLE, + WL3501_MIB_ATTR_NET_CAPABILITY, + WL3501_MIB_ATTR_ROUTING, +}; + +enum wl3501_net_type { + WL3501_NET_TYPE_INFRA, + WL3501_NET_TYPE_ADHOC, + WL3501_NET_TYPE_ANY_BSS, +}; + +enum wl3501_scan_type { + WL3501_SCAN_TYPE_ACTIVE, + WL3501_SCAN_TYPE_PASSIVE, +}; + +enum wl3501_tx_result { + WL3501_TX_RESULT_SUCCESS, + WL3501_TX_RESULT_NO_BSS, + WL3501_TX_RESULT_RETRY_LIMIT, +}; + +enum wl3501_sys_type { + WL3501_SYS_TYPE_OPEN, + WL3501_SYS_TYPE_SHARE_KEY, +}; + +enum wl3501_status { + WL3501_STATUS_SUCCESS, + WL3501_STATUS_INVALID, + WL3501_STATUS_TIMEOUT, + WL3501_STATUS_REFUSED, + WL3501_STATUS_MANY_REQ, + WL3501_STATUS_ALREADY_BSS, +}; + +#define WL3501_MGMT_CAPABILITY_ESS 0x0001 /* see 802.11 p.58 */ +#define WL3501_MGMT_CAPABILITY_IBSS 0x0002 /* - " - */ +#define WL3501_MGMT_CAPABILITY_CF_POLLABLE 0x0004 /* - " - */ +#define WL3501_MGMT_CAPABILITY_CF_POLL_REQUEST 0x0008 /* - " - */ +#define WL3501_MGMT_CAPABILITY_PRIVACY 0x0010 /* - " - */ + +#define IW_REG_DOMAIN_FCC 0x10 /* Channel 1 to 11 USA */ +#define IW_REG_DOMAIN_DOC 0x20 /* Channel 1 to 11 Canada */ +#define IW_REG_DOMAIN_ETSI 0x30 /* Channel 1 to 13 Europe */ +#define IW_REG_DOMAIN_SPAIN 0x31 /* Channel 10 to 11 Spain */ +#define IW_REG_DOMAIN_FRANCE 0x32 /* Channel 10 to 13 France */ +#define IW_REG_DOMAIN_MKK 0x40 /* Channel 14 Japan */ +#define IW_REG_DOMAIN_MKK1 0x41 /* Channel 1-14 Japan */ +#define IW_REG_DOMAIN_ISRAEL 0x50 /* Channel 3 - 9 Israel */ + +#define WL3501_ESSID_MAX_LEN (IW_ESSID_MAX_SIZE + 2) + +struct wl3501_tx_hdr { + u16 tx_cnt; + u8 sync[16]; + u16 sfd; + u8 signal; + u8 service; + u16 len; + u16 crc16; + u16 frame_ctrl; + u16 duration_id; + u8 addr1[ETH_ALEN]; + u8 addr2[ETH_ALEN]; + u8 addr3[ETH_ALEN]; + u16 seq_ctrl; + u8 addr4[ETH_ALEN]; +}; + +struct wl3501_rx_hdr { + u16 rx_next_blk; + u16 rc_next_frame_blk; + u8 rx_blk_ctrl; + u8 rx_next_frame; + u8 rx_next_frame1; + u8 rssi; + char time[8]; + u8 signal; + u8 service; + u16 len; + u16 crc16; + u16 frame_ctrl; + u16 duration; + u8 addr1[ETH_ALEN]; + u8 addr2[ETH_ALEN]; + u8 addr3[ETH_ALEN]; + u16 seq; + u8 addr4[ETH_ALEN]; +}; + +struct wl3501_start_req { + u16 next_blk; + u8 sig_id; + u8 bss_type; + u16 beacon_period; + u16 dtim_period; + u16 probe_delay; + u16 cap_info; + char ssid[WL3501_ESSID_MAX_LEN]; + u8 bss_basic_rate_set[10]; + u8 operational_rate_set[10]; + u8 cf_pset[8]; + u8 phy_pset[3]; + u8 ibss_pset[4]; +}; + +struct wl3501_assoc_req { + u16 next_blk; + u8 sig_id; + u8 reserved; + u16 timeout; + u16 cap_info; + u16 listen_interval; + u8 mac_addr[ETH_ALEN]; +}; + +struct wl3501_assoc_confirm { + u16 next_blk; + u8 sig_id; + u8 reserved; + u16 status; +}; + +struct wl3501_assoc_ind { + u16 next_blk; + u8 sig_id; + u8 mac_addr[ETH_ALEN]; +}; + +struct wl3501_auth_req { + u16 next_blk; + u8 sig_id; + u8 reserved; + u16 type; + u16 timeout; + u8 mac_addr[ETH_ALEN]; +}; + +struct wl3501_auth_confirm { + u16 next_blk; + u8 sig_id; + u8 reserved; + u16 type; + u16 status; + u8 mac_addr[ETH_ALEN]; +}; + +struct wl3501_get_req { + u16 next_blk; + u8 sig_id; + u8 reserved; + u16 mib_attrib; +}; + +struct wl3501_get_confirm { + u16 next_blk; + u8 sig_id; + u8 reserved; + u16 mib_status; + u16 mib_attrib; + u8 mib_value[100]; +}; + +struct wl3501_join_req { + u16 next_blk; + u8 sig_id; + u8 reserved; + u8 operational_rate_set[10]; + u16 reserved2; + u16 timeout; + u16 probe_delay; + u8 timestamp[8]; + u8 local_time[8]; + u16 beacon_period; + u16 dtim_period; + u16 cap_info; + u8 bss_type; + u8 bssid[ETH_ALEN]; + char ssid[WL3501_ESSID_MAX_LEN]; + u8 phy_pset[3]; + u8 cf_pset[8]; + u8 ibss_pset[4]; + u8 bss_basic_rate_set[10]; +}; + +struct wl3501_join_confirm { + u16 next_blk; + u8 sig_id; + u8 reserved; + u16 status; +}; + +struct wl3501_pwr_mgmt_req { + u16 next_blk; + u8 sig_id; + u8 pwr_save; + u8 wake_up; + u8 receive_dtims; +}; + +struct wl3501_pwr_mgmt_confirm { + u16 next_blk; + u8 sig_id; + u8 reserved; + u16 status; +}; + +struct wl3501_scan_req { + u16 next_blk; + u8 sig_id; + u8 bss_type; + u16 probe_delay; + u16 min_chan_time; + u16 max_chan_time; + u8 chan_list[14]; + u8 bssid[ETH_ALEN]; + char ssid[WL3501_ESSID_MAX_LEN]; + enum wl3501_scan_type scan_type; +}; + +struct wl3501_scan_confirm { + u16 next_blk; + u8 sig_id; + u8 reserved; + u16 status; + char timestamp[8]; + char localtime[8]; + u16 beacon_period; + u16 dtim_period; + u16 cap_info; + u8 bss_type; + u8 bssid[ETH_ALEN]; + char ssid[WL3501_ESSID_MAX_LEN]; + u8 phy_pset[3]; + u8 cf_pset[8]; + u8 ibss_pset[4]; + u8 bss_basic_rate_set[10]; + u8 rssi; +}; + +struct wl3501_start_confirm { + u16 next_blk; + u8 sig_id; + u8 reserved; + u16 status; +}; + +struct wl3501_md_req { + u16 next_blk; + u8 sig_id; + u8 routing; + u16 data; + u16 size; + u8 pri; + u8 service_class; + u8 daddr[ETH_ALEN]; + u8 saddr[ETH_ALEN]; +}; + +struct wl3501_md_ind { + u16 next_blk; + u8 sig_id; + u8 routing; + u16 data; + u16 size; + u8 reception; + u8 pri; + u8 service_class; + u8 daddr[ETH_ALEN]; + u8 saddr[ETH_ALEN]; +}; + +struct wl3501_md_confirm { + u16 next_blk; + u8 sig_id; + u8 reserved; + u16 data; + u8 status; + u8 pri; + u8 service_class; +}; + +struct wl3501_resync_req { + u16 next_blk; + u8 sig_id; +}; + +/* Definitions for supporting clone adapters. */ +/* System Interface Registers (SIR space) */ +#define WL3501_NIC_GCR ((u8)0x00) /* SIR0 - General Conf Register */ +#define WL3501_NIC_BSS ((u8)0x01) /* SIR1 - Bank Switching Select Reg */ +#define WL3501_NIC_LMAL ((u8)0x02) /* SIR2 - Local Mem addr Reg [7:0] */ +#define WL3501_NIC_LMAH ((u8)0x03) /* SIR3 - Local Mem addr Reg [14:8] */ +#define WL3501_NIC_IODPA ((u8)0x04) /* SIR4 - I/O Data Port A */ +#define WL3501_NIC_IODPB ((u8)0x05) /* SIR5 - I/O Data Port B */ +#define WL3501_NIC_IODPC ((u8)0x06) /* SIR6 - I/O Data Port C */ +#define WL3501_NIC_IODPD ((u8)0x07) /* SIR7 - I/O Data Port D */ + +/* Bits in GCR */ +#define WL3501_GCR_SWRESET ((u8)0x80) +#define WL3501_GCR_CORESET ((u8)0x40) +#define WL3501_GCR_DISPWDN ((u8)0x20) +#define WL3501_GCR_ECWAIT ((u8)0x10) +#define WL3501_GCR_ECINT ((u8)0x08) +#define WL3501_GCR_INT2EC ((u8)0x04) +#define WL3501_GCR_ENECINT ((u8)0x02) +#define WL3501_GCR_DAM ((u8)0x01) + +/* Bits in BSS (Bank Switching Select Register) */ +#define WL3501_BSS_FPAGE0 ((u8)0x20) /* Flash memory page0 */ +#define WL3501_BSS_FPAGE1 ((u8)0x28) +#define WL3501_BSS_FPAGE2 ((u8)0x30) +#define WL3501_BSS_FPAGE3 ((u8)0x38) +#define WL3501_BSS_SPAGE0 ((u8)0x00) /* SRAM page0 */ +#define WL3501_BSS_SPAGE1 ((u8)0x08) +#define WL3501_BSS_SPAGE2 ((u8)0x10) +#define WL3501_BSS_SPAGE3 ((u8)0x18) + +/* Define Driver Interface */ +/* Refer IEEE 802.11 */ +/* Tx packet header, include PLCP and MPDU */ +/* Tx PLCP Header */ +struct wl3501_80211_tx_plcp_hdr { + u8 sync[16]; + u16 sfd; + u8 signal; + u8 service; + u16 len; + u16 crc16; +} __attribute__ ((packed)); + +struct wl3501_80211_tx_hdr { + struct wl3501_80211_tx_plcp_hdr pclp_hdr; + struct ieee802_11_hdr mac_hdr; +} __attribute__ ((packed)); + +/* + Reserve the beginning Tx space for descriptor use. + + TxBlockOffset --> *----*----*----*----* \ + (TxFreeDesc) | 0 | 1 | 2 | 3 | \ + | 4 | 5 | 6 | 7 | | + | 8 | 9 | 10 | 11 | TX_DESC * 20 + | 12 | 13 | 14 | 15 | | + | 16 | 17 | 18 | 19 | / + TxBufferBegin --> *----*----*----*----* / + (TxBufferHead) | | + (TxBufferTail) | | + | Send Buffer | + | | + | | + *-------------------* + TxBufferEnd -------------------------/ + +*/ + +struct wl3501_card { + int base_addr; + u8 mac_addr[ETH_ALEN]; + spinlock_t lock; + wait_queue_head_t wait; + struct wl3501_get_confirm sig_get_confirm; + struct wl3501_pwr_mgmt_confirm sig_pwr_mgmt_confirm; + u16 tx_buffer_size; + u16 tx_buffer_head; + u16 tx_buffer_tail; + u16 tx_buffer_cnt; + u16 esbq_req_start; + u16 esbq_req_end; + u16 esbq_req_head; + u16 esbq_req_tail; + u16 esbq_confirm_start; + u16 esbq_confirm_end; + u16 esbq_confirm; + u8 essid[WL3501_ESSID_MAX_LEN]; + u8 bssid[ETH_ALEN]; + int net_type; + u8 keep_essid[WL3501_ESSID_MAX_LEN]; + char nick[32]; + char card_name[32]; + char firmware_date[32]; + u8 chan; + u8 cap_info; + u16 start_seg; + u16 bss_cnt; + u16 join_sta_bss; + u8 rssi; + u8 adhoc_times; + u8 reg_domain; + u8 version[2]; + struct wl3501_scan_confirm bss_set[20]; + struct net_device_stats stats; + struct iw_statistics wstats; + struct iw_spy_data spy_data; + struct dev_node_t node; +}; +#endif diff -Nru a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/wl3501_cs.c Sun Jul 27 10:13:52 2003 @@ -0,0 +1,2296 @@ +/* + * WL3501 Wireless LAN PCMCIA Card Driver for Linux + * Written originally for Linux 2.0.30 by Fox Chen, mhchen@golf.ccl.itri.org.tw + * Ported to 2.2, 2.4 & 2.5 by Arnaldo Carvalho de Melo + * Wireless extensions in 2.4 by Gustavo Niemeyer + * + * References used by Fox Chen while writing the original driver for 2.0.30: + * + * 1. WL24xx packet drivers (tooasm.asm) + * 2. Access Point Firmware Interface Specification for IEEE 802.11 SUTRO + * 3. IEEE 802.11 + * 4. Linux network driver (/usr/src/linux/drivers/net) + * 5. ISA card driver - wl24.c + * 6. Linux PCMCIA skeleton driver - skeleton.c + * 7. Linux PCMCIA 3c589 network driver - 3c589_cs.c + * + * Tested with WL2400 firmware 1.2, Linux 2.0.30, and pcmcia-cs-2.9.12 + * 1. Performance: about 165 Kbytes/sec in TCP/IP with Ad-Hoc mode. + * rsh 192.168.1.3 "dd if=/dev/zero bs=1k count=1000" > /dev/null + * (Specification 2M bits/sec. is about 250 Kbytes/sec., but we must deduct + * ETHER/IP/UDP/TCP header, and acknowledgement overhead) + * + * Tested with Planet AP in 2.4.17, 184 Kbytes/s in UDP in Infrastructure mode, + * 173 Kbytes/s in TCP. + * + * Tested with Planet AP in 2.5.73-bk, 216 Kbytes/s in Infrastructure mode + * with a SMP machine (dual pentium 100), using pktgen, 432 pps (pkt_size = 60) + */ +#undef REALLY_SLOW_IO /* most systems can safely undef this */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "wl3501.h" + +#ifndef __i386__ +#define slow_down_io() +#endif + +/* For rough constant delay */ +#define WL3501_NOPLOOP(n) { int x = 0; while (x++ < n) slow_down_io(); } + +/* + * All the PCMCIA modules use PCMCIA_DEBUG to control debugging. If you do not + * define PCMCIA_DEBUG at all, all the debug code will be left out. If you + * compile with PCMCIA_DEBUG=0, the debug code will be present but disabled -- + * but it can then be enabled for specific modules at load time with a + * 'pc_debug=#' option to insmod. + */ +#define PCMCIA_DEBUG 0 +#ifdef PCMCIA_DEBUG +static int pc_debug = PCMCIA_DEBUG; +MODULE_PARM(pc_debug, "i"); +#define dprintk(n, format, args...) \ + { if (pc_debug > (n)) \ + printk(KERN_INFO "%s: " format "\n", __FUNCTION__, ##args); } +#else +#define dprintk(n, format, args...) +#endif + +#define wl3501_outb(a, b) { outb(a, b); slow_down_io(); } +#define wl3501_outb_p(a, b) { outb_p(a, b); slow_down_io(); } +#define wl3501_outsb(a, b, c) { outsb(a, b, c); slow_down_io(); } + +#define WL3501_RELEASE_TIMEOUT (25 * HZ) +#define WL3501_MAX_ADHOC_TRIES 16 + +#define WL3501_RESUME 0 +#define WL3501_SUSPEND 1 + +/* Parameters that can be set with 'insmod' */ +/* Bit map of interrupts to choose from */ +/* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4, and 3 */ +static unsigned long wl3501_irq_mask = 0xdeb8; +static int wl3501_irq_list[4] = { -1 }; + +/* + * The event() function is this driver's Card Services event handler. It will + * be called by Card Services when an appropriate card status event is + * received. The config() and release() entry points are used to configure or + * release a socket, in response to card insertion and ejection events. They + * are invoked from the wl24 event handler. + */ +static void wl3501_config(dev_link_t *link); +static void wl3501_release(unsigned long arg); +static int wl3501_event(event_t event, int pri, event_callback_args_t *args); + +/* + * The dev_info variable is the "key" that is used to match up this + * device driver with appropriate cards, through the card configuration + * database. + */ +static dev_info_t wl3501_dev_info = "wl3501_cs"; + +static int wl3501_chan2freq[] = { + [0] = 2412, [1] = 2417, [2] = 2422, [3] = 2427, [4] = 2432, + [5] = 2437, [6] = 2442, [7] = 2447, [8] = 2452, [9] = 2457, + [10] = 2462, [11] = 2467, [12] = 2472, [13] = 2477, +}; + +static const struct { + int reg_domain; + int min, max, deflt; +} iw_channel_table[] = { + { + .reg_domain = IW_REG_DOMAIN_FCC, + .min = 1, + .max = 11, + .deflt = 1, + }, + { + .reg_domain = IW_REG_DOMAIN_DOC, + .min = 1, + .max = 11, + .deflt = 1, + }, + { + .reg_domain = IW_REG_DOMAIN_ETSI, + .min = 1, + .max = 13, + .deflt = 1, + }, + { + .reg_domain = IW_REG_DOMAIN_SPAIN, + .min = 10, + .max = 11, + .deflt = 10, + }, + { + .reg_domain = IW_REG_DOMAIN_FRANCE, + .min = 10, + .max = 13, + .deflt = 10, + }, + { + .reg_domain = IW_REG_DOMAIN_MKK, + .min = 14, + .max = 14, + .deflt = 14, + }, + { + .reg_domain = IW_REG_DOMAIN_MKK1, + .min = 1, + .max = 14, + .deflt = 1, + }, + { + .reg_domain = IW_REG_DOMAIN_ISRAEL, + .min = 3, + .max = 9, + .deflt = 9, + }, +}; + +/** + * iw_valid_channel - validate channel in regulatory domain + * @reg_comain - regulatory domain + * @channel - channel to validate + * + * Returns 0 if invalid in the specified regulatory domain, non-zero if valid. + */ +static int iw_valid_channel(int reg_domain, int channel) +{ + int i, rc = 0; + + for (i = 0; i < ARRAY_SIZE(iw_channel_table); i++) + if (reg_domain == iw_channel_table[i].reg_domain) { + rc = channel >= iw_channel_table[i].min && + channel <= iw_channel_table[i].max; + break; + } + return rc; +} + +/** + * iw_default_channel - get default channel for a regulatory domain + * @reg_comain - regulatory domain + * + * Returns the default channel for a regulatory domain + */ +static int iw_default_channel(int reg_domain) +{ + int i, rc = 1; + + for (i = 0; i < ARRAY_SIZE(iw_channel_table); i++) + if (reg_domain == iw_channel_table[i].reg_domain) { + rc = iw_channel_table[i].deflt; + break; + } + return rc; +} + +/* + * A linked list of "instances" of the wl24 device. Each actual PCMCIA card + * corresponds to one device instance, and is described by one dev_link_t + * structure (defined in ds.h). + * + * You may not want to use a linked list for this -- for example, the memory + * card driver uses an array of dev_link_t pointers, where minor device numbers + * are used to derive the corresponding array index. + */ +static dev_link_t *wl3501_dev_list; + +static inline void wl3501_switch_page(struct wl3501_card *this, u8 page) +{ + wl3501_outb(page, this->base_addr + WL3501_NIC_BSS); +} + +/* + * Get Ethernet MAC addresss. + * + * WARNING: We switch to FPAGE0 and switc back again. + * Making sure there is no other WL function beening called by ISR. + */ +static int wl3501_get_flash_mac_addr(struct wl3501_card *this) +{ + int base_addr = this->base_addr; + + /* get MAC addr */ + wl3501_outb(WL3501_BSS_FPAGE3, base_addr + WL3501_NIC_BSS); /* BSS */ + wl3501_outb(0x00, base_addr + WL3501_NIC_LMAL); /* LMAL */ + wl3501_outb(0x40, base_addr + WL3501_NIC_LMAH); /* LMAH */ + + /* wait for reading EEPROM */ + WL3501_NOPLOOP(100); + this->mac_addr[0] = inb(base_addr + WL3501_NIC_IODPA); + WL3501_NOPLOOP(100); + this->mac_addr[1] = inb(base_addr + WL3501_NIC_IODPA); + WL3501_NOPLOOP(100); + this->mac_addr[2] = inb(base_addr + WL3501_NIC_IODPA); + WL3501_NOPLOOP(100); + this->mac_addr[3] = inb(base_addr + WL3501_NIC_IODPA); + WL3501_NOPLOOP(100); + this->mac_addr[4] = inb(base_addr + WL3501_NIC_IODPA); + WL3501_NOPLOOP(100); + this->mac_addr[5] = inb(base_addr + WL3501_NIC_IODPA); + WL3501_NOPLOOP(100); + this->reg_domain = inb(base_addr + WL3501_NIC_IODPA); + WL3501_NOPLOOP(100); + wl3501_outb(WL3501_BSS_FPAGE0, base_addr + WL3501_NIC_BSS); + wl3501_outb(0x04, base_addr + WL3501_NIC_LMAL); + wl3501_outb(0x40, base_addr + WL3501_NIC_LMAH); + WL3501_NOPLOOP(100); + this->version[0] = inb(base_addr + WL3501_NIC_IODPA); + WL3501_NOPLOOP(100); + this->version[1] = inb(base_addr + WL3501_NIC_IODPA); + /* switch to SRAM Page 0 (for safety) */ + wl3501_switch_page(this, WL3501_BSS_SPAGE0); + + /* The MAC addr should be 00:60:... */ + return this->mac_addr[0] == 0x00 && this->mac_addr[1] == 0x60; +} + +/** + * wl3501_set_to_wla - Move 'size' bytes from PC to card + * @dest: Card addressing space + * @src: PC addressing space + * @size: Bytes to move + * + * Move 'size' bytes from PC to card. (Shouldn't be interrupted) + */ +void wl3501_set_to_wla(struct wl3501_card *this, u16 dest, void *src, int size) +{ + /* switch to SRAM Page 0 */ + wl3501_switch_page(this, (dest & 0x8000) ? WL3501_BSS_SPAGE1 : + WL3501_BSS_SPAGE0); + /* set LMAL and LMAH */ + wl3501_outb(dest & 0xff, this->base_addr + WL3501_NIC_LMAL); + wl3501_outb(((dest >> 8) & 0x7f), this->base_addr + WL3501_NIC_LMAH); + + /* rep out to Port A */ + wl3501_outsb(this->base_addr + WL3501_NIC_IODPA, src, size); +} + +/** + * wl3501_get_from_wla - Move 'size' bytes from card to PC + * @src: Card addressing space + * @dest: PC addressing space + * @size: Bytes to move + * + * Move 'size' bytes from card to PC. (Shouldn't be interrupted) + */ +void wl3501_get_from_wla(struct wl3501_card *this, u16 src, void *dest, + int size) +{ + /* switch to SRAM Page 0 */ + wl3501_switch_page(this, (src & 0x8000) ? WL3501_BSS_SPAGE1 : + WL3501_BSS_SPAGE0); + /* set LMAL and LMAH */ + wl3501_outb(src & 0xff, this->base_addr + WL3501_NIC_LMAL); + wl3501_outb((src >> 8) & 0x7f, this->base_addr + WL3501_NIC_LMAH); + + /* rep get from Port A */ + insb(this->base_addr + WL3501_NIC_IODPA, dest, size); +} + +/* + * Get/Allocate a free Tx Data Buffer + * + * *--------------*-----------------*----------------------------------* + * | PLCP | MAC Header | DST SRC Data ... | + * | (24 bytes) | (30 bytes) | (6) (6) (Ethernet Row Data) | + * *--------------*-----------------*----------------------------------* + * \ \- IEEE 802.11 -/ \-------------- len --------------/ + * \-struct wl3501_80211_tx_hdr--/ \-------- Ethernet Frame -------/ + * + * Return = Postion in Card + */ +static u16 wl3501_get_tx_buffer(struct wl3501_card *this, u16 len) +{ + u16 next, blk_cnt = 0, zero = 0; + u16 full_len = sizeof(struct wl3501_80211_tx_hdr) + len; + u16 ret = 0; + + if (full_len > this->tx_buffer_cnt * 254) + goto out; + ret = this->tx_buffer_head; + while (full_len) { + if (full_len < 254) + full_len = 0; + else + full_len -= 254; + wl3501_get_from_wla(this, this->tx_buffer_head, &next, + sizeof(next)); + if (!full_len) + wl3501_set_to_wla(this, this->tx_buffer_head, &zero, + sizeof(zero)); + this->tx_buffer_head = next; + blk_cnt++; + /* if buffer is not enough */ + if (!next && full_len) { + this->tx_buffer_head = ret; + ret = 0; + goto out; + } + } + this->tx_buffer_cnt -= blk_cnt; +out: + return ret; +} + +/* + * Free an allocated Tx Buffer. ptr must be correct position. + */ +static void wl3501_free_tx_buffer(struct wl3501_card *this, u16 ptr) +{ + /* check if all space is not free */ + if (!this->tx_buffer_head) + this->tx_buffer_head = ptr; + else + wl3501_set_to_wla(this, this->tx_buffer_tail, + &ptr, sizeof(ptr)); + while (ptr) { + u16 next; + + this->tx_buffer_cnt++; + wl3501_get_from_wla(this, ptr, &next, sizeof(next)); + this->tx_buffer_tail = ptr; + ptr = next; + } +} + +static int wl3501_esbq_req_test(struct wl3501_card *this) +{ + u8 tmp; + + wl3501_get_from_wla(this, this->esbq_req_head + 3, &tmp, sizeof(tmp)); + return tmp & 0x80; +} + +static void wl3501_esbq_req(struct wl3501_card *this, u16 *ptr) +{ + u16 tmp = 0; + + wl3501_set_to_wla(this, this->esbq_req_head, ptr, 2); + wl3501_set_to_wla(this, this->esbq_req_head + 2, &tmp, sizeof(tmp)); + this->esbq_req_head += 4; + if (this->esbq_req_head >= this->esbq_req_end) + this->esbq_req_head = this->esbq_req_start; +} + +static int wl3501_esbq_exec(struct wl3501_card *this, void *sig, int sig_size) +{ + int rc = -EIO; + + if (wl3501_esbq_req_test(this)) { + u16 ptr = wl3501_get_tx_buffer(this, sig_size); + if (ptr) { + wl3501_set_to_wla(this, ptr, sig, sig_size); + wl3501_esbq_req(this, &ptr); + rc = 0; + } + } + return rc; +} + +static int wl3501_get_mib_value(struct wl3501_card *this, u8 index, + void *bf, int size) +{ + struct wl3501_get_req sig = { + .sig_id = WL3501_SIG_GET_REQ, + .mib_attrib = index, + }; + unsigned long flags; + int rc = -EIO; + + spin_lock_irqsave(&this->lock, flags); + if (wl3501_esbq_req_test(this)) { + u16 ptr = wl3501_get_tx_buffer(this, sizeof(sig)); + if (ptr) { + wl3501_set_to_wla(this, ptr, &sig, sizeof(sig)); + wl3501_esbq_req(this, &ptr); + this->sig_get_confirm.mib_status = 255; + spin_unlock_irqrestore(&this->lock, flags); + rc = wait_event_interruptible(this->wait, + this->sig_get_confirm.mib_status != 255); + if (!rc) + memcpy(bf, this->sig_get_confirm.mib_value, + size); + goto out; + } + } + spin_unlock_irqrestore(&this->lock, flags); +out: + return rc; +} + +static int wl3501_pwr_mgmt(struct wl3501_card *this, int suspend) +{ + struct wl3501_pwr_mgmt_req sig = { + .sig_id = WL3501_SIG_PWR_MGMT_REQ, + .pwr_save = suspend, + .wake_up = !suspend, + .receive_dtims = 10, + }; + unsigned long flags; + int rc = -EIO; + + spin_lock_irqsave(&this->lock, flags); + if (wl3501_esbq_req_test(this)) { + u16 ptr = wl3501_get_tx_buffer(this, sizeof(sig)); + if (ptr) { + wl3501_set_to_wla(this, ptr, &sig, sizeof(sig)); + wl3501_esbq_req(this, &ptr); + this->sig_pwr_mgmt_confirm.status = 255; + spin_unlock_irqrestore(&this->lock, flags); + rc = wait_event_interruptible(this->wait, + this->sig_pwr_mgmt_confirm.status != 255); + printk(KERN_INFO "%s: %s status=%d\n", __FUNCTION__, + suspend ? "suspend" : "resume", + this->sig_pwr_mgmt_confirm.status); + goto out; + } + } + spin_unlock_irqrestore(&this->lock, flags); +out: + return rc; +} + +/** + * wl3501_send_pkt - Send a packet. + * @this - card + * + * Send a packet. + * + * data = Ethernet raw frame. (e.g. data[0] - data[5] is Dest MAC Addr, + * data[6] - data[11] is Src MAC Addr) + * Ref: IEEE 802.11 + */ +static int wl3501_send_pkt(struct wl3501_card *this, u8 *data, u16 len) +{ + u16 bf, sig_bf, next, tmplen, pktlen; + struct wl3501_md_req sig = { + .sig_id = WL3501_SIG_MD_REQ, + }; + u8 *pdata = (char *)data; + int rc = -EIO; + + if (wl3501_esbq_req_test(this)) { + sig_bf = wl3501_get_tx_buffer(this, sizeof(sig)); + rc = -ENOMEM; + if (!sig_bf) /* No free buffer available */ + goto out; + bf = wl3501_get_tx_buffer(this, len + 26 + 24); + if (!bf) { + /* No free buffer available */ + wl3501_free_tx_buffer(this, sig_bf); + goto out; + } + rc = 0; + memcpy(&sig.daddr[0], pdata, 12); + pktlen = len - 12; + pdata += 12; + sig.data = bf; + if (((*pdata) * 256 + (*(pdata + 1))) > 1500) { + u8 addr4[ETH_ALEN] = { + [0] = 0xAA, [1] = 0xAA, [2] = 0x03, [4] = 0x00, + }; + + wl3501_set_to_wla(this, bf + 2 + + offsetof(struct wl3501_tx_hdr, addr4), + addr4, sizeof(addr4)); + sig.size = pktlen + 24 + 4 + 6; + if (pktlen > (254 - sizeof(struct wl3501_tx_hdr))) { + tmplen = 254 - sizeof(struct wl3501_tx_hdr); + pktlen -= tmplen; + } else { + tmplen = pktlen; + pktlen = 0; + } + wl3501_set_to_wla(this, + bf + 2 + sizeof(struct wl3501_tx_hdr), + pdata, tmplen); + pdata += tmplen; + wl3501_get_from_wla(this, bf, &next, sizeof(next)); + bf = next; + } else { + sig.size = pktlen + 24 + 4 - 2; + pdata += 2; + pktlen -= 2; + if (pktlen > (254 - sizeof(struct wl3501_tx_hdr) + 6)) { + tmplen = 254 - sizeof(struct wl3501_tx_hdr) + 6; + pktlen -= tmplen; + } else { + tmplen = pktlen; + pktlen = 0; + } + wl3501_set_to_wla(this, bf + 2 + + offsetof(struct wl3501_tx_hdr, addr4), + pdata, tmplen); + pdata += tmplen; + wl3501_get_from_wla(this, bf, &next, sizeof(next)); + bf = next; + } + while (pktlen > 0) { + if (pktlen > 254) { + tmplen = 254; + pktlen -= 254; + } else { + tmplen = pktlen; + pktlen = 0; + } + wl3501_set_to_wla(this, bf + 2, pdata, tmplen); + pdata += tmplen; + wl3501_get_from_wla(this, bf, &next, sizeof(next)); + bf = next; + } + wl3501_set_to_wla(this, sig_bf, &sig, sizeof(sig)); + wl3501_esbq_req(this, &sig_bf); + } +out: + return rc; +} + +static int wl3501_mgmt_resync(struct wl3501_card *this) +{ + struct wl3501_resync_req sig = { + .sig_id = WL3501_SIG_RESYNC_REQ, + }; + + return wl3501_esbq_exec(this, &sig, sizeof(sig)); +} + +static inline int wl3501_fw_bss_type(struct wl3501_card *this) +{ + return this->net_type == IW_MODE_INFRA ? WL3501_NET_TYPE_INFRA : + WL3501_NET_TYPE_ADHOC; +} + +static inline int wl3501_fw_cap_info(struct wl3501_card *this) +{ + return this->net_type == IW_MODE_INFRA ? WL3501_MGMT_CAPABILITY_ESS : + WL3501_MGMT_CAPABILITY_IBSS; +} + +static int wl3501_mgmt_scan(struct wl3501_card *this, u16 chan_time) +{ + struct wl3501_scan_req sig = { + .sig_id = WL3501_SIG_SCAN_REQ, + .scan_type = WL3501_SCAN_TYPE_ACTIVE, + .probe_delay = 0x10, + .min_chan_time = chan_time, + .max_chan_time = chan_time, + .bss_type = wl3501_fw_bss_type(this), + }; + + this->bss_cnt = this->join_sta_bss = 0; + return wl3501_esbq_exec(this, &sig, sizeof(sig)); +} + +static int wl3501_mgmt_join(struct wl3501_card *this, u16 stas) +{ + struct wl3501_join_req sig = { + .sig_id = WL3501_SIG_JOIN_REQ, + .timeout = 10, + .phy_pset = { + [2] = this->chan, + }, + }; + + memcpy(&sig.beacon_period, &this->bss_set[stas].beacon_period, 72); + return wl3501_esbq_exec(this, &sig, sizeof(sig)); +} + +static int wl3501_mgmt_start(struct wl3501_card *this) +{ + struct wl3501_start_req sig = { + .sig_id = WL3501_SIG_START_REQ, + .beacon_period = 400, + .dtim_period = 1, + .phy_pset = { + [0] = 3, [1] = 1, [2] = this->chan, + }, + .bss_basic_rate_set = { + [0] = 0x01, [1] = 0x02, [2] = 0x82, [3] = 0x84, + }, + .operational_rate_set = { + [0] = 0x01, [1] = 0x02, [2] = 0x82, [3] = 0x84, + }, + .ibss_pset = { + [0] = 6, [1] = 2, [2] = 10, + }, + .bss_type = wl3501_fw_bss_type(this), + .cap_info = wl3501_fw_cap_info(this), + }; + + memcpy(sig.ssid, this->essid, WL3501_ESSID_MAX_LEN); + memcpy(this->keep_essid, this->essid, WL3501_ESSID_MAX_LEN); + return wl3501_esbq_exec(this, &sig, sizeof(sig)); +} + +static void wl3501_mgmt_scan_confirm(struct wl3501_card *this, u16 addr) +{ + u16 i = 0; + int matchflag = 0; + struct wl3501_scan_confirm sig; + + dprintk(3, "entry"); + wl3501_get_from_wla(this, addr, &sig, sizeof(sig)); + if (sig.status == WL3501_STATUS_SUCCESS) { + dprintk(3, "success"); + if ((this->net_type == IW_MODE_INFRA && + (sig.cap_info & WL3501_MGMT_CAPABILITY_ESS)) || + (this->net_type == IW_MODE_ADHOC && + (sig.cap_info & WL3501_MGMT_CAPABILITY_IBSS)) || + this->net_type == IW_MODE_AUTO) { + if (!this->essid[1]) + matchflag = 1; + else if (this->essid[1] == 3 && + !strncmp((char *)&this->essid[2], "ANY", 3)) + matchflag = 1; + else if (this->essid[1] != sig.ssid[1]) + matchflag = 0; + else if (memcmp(&this->essid[2], &sig.ssid[2], + this->essid[1])) + matchflag = 0; + else + matchflag = 1; + if (matchflag) { + for (i = 0; i < this->bss_cnt; i++) { + if (!memcmp(this->bss_set[i].bssid, + sig.bssid, ETH_ALEN)) { + matchflag = 0; + break; + } + } + } + if (matchflag && (i < 20)) { + memcpy(&this->bss_set[i].beacon_period, + &sig.beacon_period, 73); + this->bss_cnt++; + this->rssi = sig.rssi; + } + } + } else if (sig.status == WL3501_STATUS_TIMEOUT) { + dprintk(3, "timeout"); + this->join_sta_bss = 0; + for (i = this->join_sta_bss; i < this->bss_cnt; i++) + if (!wl3501_mgmt_join(this, i)) + break; + this->join_sta_bss = i; + if (this->join_sta_bss == this->bss_cnt) { + if (this->net_type == IW_MODE_INFRA) + wl3501_mgmt_scan(this, 100); + else { + this->adhoc_times++; + if (this->adhoc_times > WL3501_MAX_ADHOC_TRIES) + wl3501_mgmt_start(this); + else + wl3501_mgmt_scan(this, 100); + } + } + } +} + +/** + * wl3501_block_interrupt - Mask interrupt from SUTRO + * @this - card + * + * Mask interrupt from SUTRO. (i.e. SUTRO cannot interrupt the HOST) + * Return: 1 if interrupt is originally enabled + */ +static int wl3501_block_interrupt(struct wl3501_card *this) +{ + u8 old = inb(this->base_addr + WL3501_NIC_GCR); + u8 new = old & (~(WL3501_GCR_ECINT | WL3501_GCR_INT2EC | + WL3501_GCR_ENECINT)); + + wl3501_outb(new, this->base_addr + WL3501_NIC_GCR); + return old & WL3501_GCR_ENECINT; +} + +/** + * wl3501_unblock_interrupt - Enable interrupt from SUTRO + * @this - card + * + * Enable interrupt from SUTRO. (i.e. SUTRO can interrupt the HOST) + * Return: 1 if interrupt is originally enabled + */ +static int wl3501_unblock_interrupt(struct wl3501_card *this) +{ + u8 old = inb(this->base_addr + WL3501_NIC_GCR); + u8 new = (old & ~(WL3501_GCR_ECINT | WL3501_GCR_INT2EC)) | + WL3501_GCR_ENECINT; + + wl3501_outb(new, this->base_addr + WL3501_NIC_GCR); + return old & WL3501_GCR_ENECINT; +} + +/** + * wl3501_receive - Receive data from Receive Queue. + * + * Receive data from Receive Queue. + * + * @this: card + * @bf: address of host + * @size: size of buffer. + */ +static u16 wl3501_receive(struct wl3501_card *this, u8 *bf, u16 size) +{ + u16 next_addr, next_addr1; + u8 *data = bf + 12; + + size -= 12; + wl3501_get_from_wla(this, this->start_seg + 2, + &next_addr, sizeof(next_addr)); + if (size > WL3501_BLKSZ - sizeof(struct wl3501_rx_hdr)) { + wl3501_get_from_wla(this, + this->start_seg + + sizeof(struct wl3501_rx_hdr), data, + WL3501_BLKSZ - + sizeof(struct wl3501_rx_hdr)); + size -= WL3501_BLKSZ - sizeof(struct wl3501_rx_hdr); + data += WL3501_BLKSZ - sizeof(struct wl3501_rx_hdr); + } else { + wl3501_get_from_wla(this, + this->start_seg + + sizeof(struct wl3501_rx_hdr), + data, size); + size = 0; + } + while (size > 0) { + if (size > WL3501_BLKSZ - 5) { + wl3501_get_from_wla(this, next_addr + 5, data, + WL3501_BLKSZ - 5); + size -= WL3501_BLKSZ - 5; + data += WL3501_BLKSZ - 5; + wl3501_get_from_wla(this, next_addr + 2, &next_addr1, + sizeof(next_addr1)); + next_addr = next_addr1; + } else { + wl3501_get_from_wla(this, next_addr + 5, data, size); + size = 0; + } + } + return 0; +} + +static void wl3501_esbq_req_free(struct wl3501_card *this) +{ + u8 tmp; + u16 addr; + + if (this->esbq_req_head == this->esbq_req_tail) + goto out; + wl3501_get_from_wla(this, this->esbq_req_tail + 3, &tmp, sizeof(tmp)); + if (!(tmp & 0x80)) + goto out; + wl3501_get_from_wla(this, this->esbq_req_tail, &addr, sizeof(addr)); + wl3501_free_tx_buffer(this, addr); + this->esbq_req_tail += 4; + if (this->esbq_req_tail >= this->esbq_req_end) + this->esbq_req_tail = this->esbq_req_start; +out: + return; +} + +static int wl3501_esbq_confirm(struct wl3501_card *this) +{ + u8 tmp; + + wl3501_get_from_wla(this, this->esbq_confirm + 3, &tmp, sizeof(tmp)); + return tmp & 0x80; +} + +static void wl3501_online(struct net_device *dev) +{ + struct wl3501_card *this = dev->priv; + + printk(KERN_INFO "%s: Wireless LAN online. BSSID: " + "%02X %02X %02X %02X %02X %02X\n", dev->name, + this->bssid[0], this->bssid[1], this->bssid[2], + this->bssid[3], this->bssid[4], this->bssid[5]); + netif_wake_queue(dev); +} + +static void wl3501_esbq_confirm_done(struct wl3501_card *this) +{ + u8 tmp = 0; + + wl3501_set_to_wla(this, this->esbq_confirm + 3, &tmp, sizeof(tmp)); + this->esbq_confirm += 4; + if (this->esbq_confirm >= this->esbq_confirm_end) + this->esbq_confirm = this->esbq_confirm_start; +} + +static int wl3501_mgmt_auth(struct wl3501_card *this) +{ + struct wl3501_auth_req sig = { + .sig_id = WL3501_SIG_AUTH_REQ, + .type = WL3501_SYS_TYPE_OPEN, + .timeout = 1000, + }; + + dprintk(3, "entry"); + memcpy(sig.mac_addr, this->bssid, ETH_ALEN); + return wl3501_esbq_exec(this, &sig, sizeof(sig)); +} + +static int wl3501_mgmt_association(struct wl3501_card *this) +{ + struct wl3501_assoc_req sig = { + .sig_id = WL3501_SIG_ASSOC_REQ, + .timeout = 1000, + .listen_interval = 5, + .cap_info = this->cap_info, + }; + + dprintk(3, "entry"); + memcpy(sig.mac_addr, this->bssid, ETH_ALEN); + return wl3501_esbq_exec(this, &sig, sizeof(sig)); +} + +static void wl3501_mgmt_join_confirm(struct net_device *dev, u16 addr) +{ + struct wl3501_card *this = dev->priv; + struct wl3501_join_confirm sig; + + dprintk(3, "entry"); + wl3501_get_from_wla(this, addr, &sig, sizeof(sig)); + if (sig.status == WL3501_STATUS_SUCCESS) { + if (this->net_type == IW_MODE_INFRA) { + if (this->join_sta_bss < this->bss_cnt) { + const int i = this->join_sta_bss; + memcpy(this->bssid, + this->bss_set[i].bssid, ETH_ALEN); + this->chan = this->bss_set[i].phy_pset[2]; + memcpy(this->keep_essid, this->bss_set[i].ssid, + WL3501_ESSID_MAX_LEN); + wl3501_mgmt_auth(this); + } + } else { + const int i = this->join_sta_bss; + memcpy(this->bssid, this->bss_set[i].bssid, ETH_ALEN); + this->chan = this->bss_set[i].phy_pset[2]; + memcpy(this->keep_essid, + this->bss_set[i].ssid, WL3501_ESSID_MAX_LEN); + wl3501_online(dev); + } + } else { + int i; + this->join_sta_bss++; + for (i = this->join_sta_bss; i < this->bss_cnt; i++) + if (!wl3501_mgmt_join(this, i)) + break; + this->join_sta_bss = i; + if (this->join_sta_bss == this->bss_cnt) { + if (this->net_type == IW_MODE_INFRA) + wl3501_mgmt_scan(this, 100); + else { + this->adhoc_times++; + if (this->adhoc_times > WL3501_MAX_ADHOC_TRIES) + wl3501_mgmt_start(this); + else + wl3501_mgmt_scan(this, 100); + } + } + } +} + +static inline void wl3501_alarm_interrupt(struct net_device *dev, + struct wl3501_card *this) +{ + if (this->net_type == IW_MODE_INFRA) { + printk(KERN_INFO "Wireless LAN offline\n"); + netif_stop_queue(dev); + wl3501_mgmt_resync(this); + } +} + +static inline void wl3501_md_confirm_interrupt(struct net_device *dev, + struct wl3501_card *this, + u16 addr) +{ + struct wl3501_md_confirm sig; + + dprintk(3, "entry"); + wl3501_get_from_wla(this, addr, &sig, sizeof(sig)); + wl3501_free_tx_buffer(this, sig.data); + if (netif_queue_stopped(dev)) + netif_wake_queue(dev); +} + +static inline void wl3501_md_ind_interrupt(struct net_device *dev, + struct wl3501_card *this, u16 addr) +{ + struct wl3501_md_ind sig; + struct sk_buff *skb; + u8 rssi, addr4[ETH_ALEN]; + u16 pkt_len; + + wl3501_get_from_wla(this, addr, &sig, sizeof(sig)); + this->start_seg = sig.data; + wl3501_get_from_wla(this, + sig.data + offsetof(struct wl3501_rx_hdr, rssi), + &rssi, sizeof(rssi)); + this->rssi = rssi <= 63 ? (rssi * 100) / 64 : 255; + + wl3501_get_from_wla(this, + sig.data + + offsetof(struct wl3501_rx_hdr, addr4), + &addr4, sizeof(addr4)); + if (!(addr4[0] == 0xAA && addr4[1] == 0xAA && + addr4[2] == 0x03 && addr4[4] == 0x00)) { + printk(KERN_INFO "Insupported packet type!\n"); + return; + } + pkt_len = sig.size + 12 - 24 - 4 - 6; + + skb = dev_alloc_skb(pkt_len + 5); + + if (!skb) { + printk(KERN_WARNING "%s: Can't alloc a sk_buff of size %d.\n", + dev->name, pkt_len); + this->stats.rx_dropped++; + } else { + skb->dev = dev; + skb_reserve(skb, 2); /* IP headers on 16 bytes boundaries */ + eth_copy_and_sum(skb, (unsigned char *)&sig.daddr, 12, 0); + wl3501_receive(this, skb->data, pkt_len); + skb_put(skb, pkt_len); + skb->protocol = eth_type_trans(skb, dev); + dev->last_rx = jiffies; + this->stats.rx_packets++; + this->stats.rx_bytes += skb->len; + netif_rx(skb); + } +} + +static inline void wl3501_get_confirm_interrupt(struct wl3501_card *this, + u16 addr, void *sig, int size) +{ + dprintk(3, "entry"); + wl3501_get_from_wla(this, addr, &this->sig_get_confirm, + sizeof(this->sig_get_confirm)); + wake_up(&this->wait); +} + +static inline void wl3501_start_confirm_interrupt(struct net_device *dev, + struct wl3501_card *this, + u16 addr) +{ + struct wl3501_start_confirm sig; + + dprintk(3, "entry"); + wl3501_get_from_wla(this, addr, &sig, sizeof(sig)); + if (sig.status == WL3501_STATUS_SUCCESS) + netif_wake_queue(dev); +} + +static inline void wl3501_assoc_confirm_interrupt(struct net_device *dev, + u16 addr) +{ + struct wl3501_card *this = dev->priv; + struct wl3501_assoc_confirm sig; + + dprintk(3, "entry"); + wl3501_get_from_wla(this, addr, &sig, sizeof(sig)); + + if (sig.status == WL3501_STATUS_SUCCESS) + wl3501_online(dev); +} + +static inline void wl3501_auth_confirm_interrupt(struct wl3501_card *this, + u16 addr) +{ + struct wl3501_auth_confirm sig; + + dprintk(3, "entry"); + wl3501_get_from_wla(this, addr, &sig, sizeof(sig)); + + if (sig.status == WL3501_STATUS_SUCCESS) + wl3501_mgmt_association(this); + else + wl3501_mgmt_resync(this); +} + +static inline void wl3501_rx_interrupt(struct net_device *dev) +{ + int morepkts; + u16 addr; + u8 sig_id; + struct wl3501_card *this = dev->priv; + + dprintk(3, "entry"); +loop: + morepkts = 0; + if (!wl3501_esbq_confirm(this)) + goto free; + wl3501_get_from_wla(this, this->esbq_confirm, &addr, sizeof(addr)); + wl3501_get_from_wla(this, addr + 2, &sig_id, sizeof(sig_id)); + + switch (sig_id) { + case WL3501_SIG_DEAUTH_IND: + case WL3501_SIG_DISASSOC_IND: + case WL3501_SIG_ALARM: + wl3501_alarm_interrupt(dev, this); + break; + case WL3501_SIG_MD_CONFIRM: + wl3501_md_confirm_interrupt(dev, this, addr); + break; + case WL3501_SIG_MD_IND: + wl3501_md_ind_interrupt(dev, this, addr); + break; + case WL3501_SIG_GET_CONFIRM: + wl3501_get_confirm_interrupt(this, addr, + &this->sig_get_confirm, + sizeof(this->sig_get_confirm)); + break; + case WL3501_SIG_PWR_MGMT_CONFIRM: + wl3501_get_confirm_interrupt(this, addr, + &this->sig_pwr_mgmt_confirm, + sizeof(this->sig_pwr_mgmt_confirm)); + break; + case WL3501_SIG_START_CONFIRM: + wl3501_start_confirm_interrupt(dev, this, addr); + break; + case WL3501_SIG_SCAN_CONFIRM: + wl3501_mgmt_scan_confirm(this, addr); + break; + case WL3501_SIG_JOIN_CONFIRM: + wl3501_mgmt_join_confirm(dev, addr); + break; + case WL3501_SIG_ASSOC_CONFIRM: + wl3501_assoc_confirm_interrupt(dev, addr); + break; + case WL3501_SIG_AUTH_CONFIRM: + wl3501_auth_confirm_interrupt(this, addr); + break; + case WL3501_SIG_RESYNC_CONFIRM: + wl3501_mgmt_resync(this); /* FIXME: should be resync_confirm */ + break; + } + wl3501_esbq_confirm_done(this); + morepkts = 1; + /* free request if necessary */ +free: + wl3501_esbq_req_free(this); + if (morepkts) + goto loop; +} + +static inline void wl3501_ack_interrupt(struct wl3501_card *this) +{ + wl3501_outb(WL3501_GCR_ECINT, this->base_addr + WL3501_NIC_GCR); +} + +/** + * wl3501_interrupt - Hardware interrupt from card. + * @irq - Interrupt number + * @dev_id - net_device + * @regs - registers + * + * We must acknowledge the interrupt as soon as possible, and block the + * interrupt from the same card immediately to prevent re-entry. + * + * Before accessing the Control_Status_Block, we must lock SUTRO first. + * On the other hand, to prevent SUTRO from malfunctioning, we must + * unlock the SUTRO as soon as possible. + */ +static irqreturn_t wl3501_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *)dev_id; + struct wl3501_card *this; + int handled = 1; + + if (!dev) + goto unknown; + this = dev->priv; + spin_lock(&this->lock); + wl3501_ack_interrupt(this); + wl3501_block_interrupt(this); + wl3501_rx_interrupt(dev); + wl3501_unblock_interrupt(this); + spin_unlock(&this->lock); +out: + return IRQ_RETVAL(handled); +unknown: + handled = 0; + printk(KERN_ERR "%s: irq %d for unknown device.\n", __FUNCTION__, irq); + goto out; +} + +static int wl3501_reset_board(struct wl3501_card *this) +{ + u8 tmp = 0; + int i, rc = 0; + + /* Coreset */ + wl3501_outb_p(WL3501_GCR_CORESET, this->base_addr + WL3501_NIC_GCR); + wl3501_outb_p(0, this->base_addr + WL3501_NIC_GCR); + wl3501_outb_p(WL3501_GCR_CORESET, this->base_addr + WL3501_NIC_GCR); + + /* Reset SRAM 0x480 to zero */ + wl3501_set_to_wla(this, 0x480, &tmp, sizeof(tmp)); + + /* Start up */ + wl3501_outb_p(0, this->base_addr + WL3501_NIC_GCR); + + WL3501_NOPLOOP(1024 * 50); + + wl3501_unblock_interrupt(this); /* acme: was commented */ + + /* Polling Self_Test_Status */ + for (i = 0; i < 10000; i++) { + wl3501_get_from_wla(this, 0x480, &tmp, sizeof(tmp)); + + if (tmp == 'W') { + /* firmware complete all test successfully */ + tmp = 'A'; + wl3501_set_to_wla(this, 0x480, &tmp, sizeof(tmp)); + goto out; + } + WL3501_NOPLOOP(10); + } + printk(KERN_WARNING "%s: failed to reset the board!\n", __FUNCTION__); + rc = -ENODEV; +out: + return rc; +} + +static int wl3501_init_firmware(struct wl3501_card *this) +{ + u16 ptr, next; + int rc = wl3501_reset_board(this); + + if (rc) + goto fail; + this->card_name[0] = '\0'; + wl3501_get_from_wla(this, 0x1a00, + this->card_name, sizeof(this->card_name)); + this->card_name[sizeof(this->card_name) - 1] = '\0'; + this->firmware_date[0] = '\0'; + wl3501_get_from_wla(this, 0x1a40, + this->firmware_date, sizeof(this->firmware_date)); + this->firmware_date[sizeof(this->firmware_date) - 1] = '\0'; + /* Switch to SRAM Page 0 */ + wl3501_switch_page(this, WL3501_BSS_SPAGE0); + /* Read parameter from card */ + wl3501_get_from_wla(this, 0x482, &this->esbq_req_start, 2); + wl3501_get_from_wla(this, 0x486, &this->esbq_req_end, 2); + wl3501_get_from_wla(this, 0x488, &this->esbq_confirm_start, 2); + wl3501_get_from_wla(this, 0x48c, &this->esbq_confirm_end, 2); + wl3501_get_from_wla(this, 0x48e, &this->tx_buffer_head, 2); + wl3501_get_from_wla(this, 0x492, &this->tx_buffer_size, 2); + this->esbq_req_tail = this->esbq_req_head = this->esbq_req_start; + this->esbq_req_end += this->esbq_req_start; + this->esbq_confirm = this->esbq_confirm_start; + this->esbq_confirm_end += this->esbq_confirm_start; + /* Initial Tx Buffer */ + this->tx_buffer_cnt = 1; + ptr = this->tx_buffer_head; + next = ptr + WL3501_BLKSZ; + while ((next - this->tx_buffer_head) < this->tx_buffer_size) { + this->tx_buffer_cnt++; + wl3501_set_to_wla(this, ptr, &next, sizeof(next)); + ptr = next; + next = ptr + WL3501_BLKSZ; + } + rc = 0; + next = 0; + wl3501_set_to_wla(this, ptr, &next, sizeof(next)); + this->tx_buffer_tail = ptr; +out: + return rc; +fail: + printk(KERN_WARNING "%s: failed!\n", __FUNCTION__); + goto out; +} + +static int wl3501_close(struct net_device *dev) +{ + struct wl3501_card *this = dev->priv; + int rc = -ENODEV; + unsigned long flags; + dev_link_t *link; + + spin_lock_irqsave(&this->lock, flags); + /* Check if the device is in wl3501_dev_list */ + for (link = wl3501_dev_list; link; link = link->next) + if (link->priv == dev) + break; + if (!link) + goto out; + link->open--; + + /* Stop wl3501_hard_start_xmit() from now on */ + netif_stop_queue(dev); + wl3501_ack_interrupt(this); + + /* Mask interrupts from the SUTRO */ + wl3501_block_interrupt(this); + + if (link->state & DEV_STALE_CONFIG) { + link->release.expires = jiffies + WL3501_RELEASE_TIMEOUT; + link->state |= DEV_RELEASE_PENDING; + add_timer(&link->release); + } + rc = 0; + printk(KERN_INFO "%s: WL3501 closed\n", dev->name); +out: + spin_unlock_irqrestore(&this->lock, flags); + return rc; +} + +/** + * wl3501_reset - Reset the SUTRO. + * @dev - network device + * + * It is almost the same as wl3501_open(). In fact, we may just wl3501_close() + * and wl3501_open() again, but I wouldn't like to free_irq() when the driver + * is running. It seems to be dangerous. + */ +static int wl3501_reset(struct net_device *dev) +{ + struct wl3501_card *this = dev->priv; + int rc = -ENODEV; + + wl3501_block_interrupt(this); + + if (wl3501_init_firmware(this)) { + printk(KERN_WARNING "%s: Can't initialize Firmware!\n", + dev->name); + /* Free IRQ, and mark IRQ as unused */ + free_irq(dev->irq, dev); + goto out; + } + + /* + * Queue has to be started only when the Card is Started + */ + netif_stop_queue(dev); + this->adhoc_times = 0; + wl3501_ack_interrupt(this); + wl3501_unblock_interrupt(this); + wl3501_mgmt_scan(this, 100); + dprintk(1, "%s: device reset", dev->name); + rc = 0; +out: + return rc; +} + +static void wl3501_tx_timeout(struct net_device *dev) +{ + struct wl3501_card *this = dev->priv; + struct net_device_stats *stats = &this->stats; + unsigned long flags; + int rc; + + stats->tx_errors++; + spin_lock_irqsave(&this->lock, flags); + rc = wl3501_reset(dev); + spin_unlock_irqrestore(&this->lock, flags); + if (rc) + printk(KERN_ERR "%s: Error %d resetting card on Tx timeout!\n", + dev->name, rc); + else { + dev->trans_start = jiffies; + netif_wake_queue(dev); + } +} + +/* + * Return : 0 - OK + * 1 - Could not transmit (dev_queue_xmit will queue it) + * and try to sent it later + */ +static int wl3501_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + int enabled, rc; + struct wl3501_card *this = dev->priv; + unsigned long flags; + + spin_lock_irqsave(&this->lock, flags); + enabled = wl3501_block_interrupt(this); + dev->trans_start = jiffies; + rc = wl3501_send_pkt(this, skb->data, skb->len); + if (enabled) + wl3501_unblock_interrupt(this); + if (rc) { + ++this->stats.tx_dropped; + netif_stop_queue(dev); + } else { + ++this->stats.tx_packets; + this->stats.tx_bytes += skb->len; + kfree_skb(skb); + + if (this->tx_buffer_cnt < 2) + netif_stop_queue(dev); + } + spin_unlock_irqrestore(&this->lock, flags); + return rc; +} + +static int wl3501_open(struct net_device *dev) +{ + int rc = -ENODEV; + struct wl3501_card *this = dev->priv; + unsigned long flags; + dev_link_t *link; + + spin_lock_irqsave(&this->lock, flags); + /* Check if the device is in wl3501_dev_list */ + for (link = wl3501_dev_list; link; link = link->next) + if (link->priv == dev) + break; + if (!DEV_OK(link)) + goto out; + netif_device_attach(dev); + link->open++; + + /* Initial WL3501 firmware */ + dprintk(1, "%s: Initialize WL3501 firmware...", dev->name); + if (wl3501_init_firmware(this)) + goto fail; + /* Initial device variables */ + this->adhoc_times = 0; + /* Acknowledge Interrupt, for cleaning last state */ + wl3501_ack_interrupt(this); + + /* Enable interrupt from card after all */ + wl3501_unblock_interrupt(this); + wl3501_mgmt_scan(this, 100); + rc = 0; + dprintk(1, "%s: WL3501 opened", dev->name); + printk(KERN_INFO "%s: Card Name: %s\n" + "%s: Firmware Date: %s\n", + dev->name, this->card_name, + dev->name, this->firmware_date); +out: + spin_unlock_irqrestore(&this->lock, flags); + return rc; +fail: + printk(KERN_WARNING "%s: Can't initialize firmware!\n", dev->name); + goto out; +} + +/** + * wl3501_init - "initialize" board + * @dev - network device + * + * We never need to do anything when a wl3501 device is "initialized" by the net + * software, because we only register already-found cards. + */ +static int wl3501_init(struct net_device *dev) +{ + return 0; +} + +struct net_device_stats *wl3501_get_stats(struct net_device *dev) +{ + struct wl3501_card *this = dev->priv; + + return &this->stats; +} + +struct iw_statistics *wl3501_get_wireless_stats(struct net_device *dev) +{ + struct wl3501_card *this = dev->priv; + struct iw_statistics *wstats = &this->wstats; + u32 value; /* size checked: it is u32 */ + + memset(wstats, 0, sizeof(*wstats)); + wstats->status = netif_running(dev); + if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_WEP_ICV_ERROR_COUNT, + &value, sizeof(value))) + wstats->discard.code += value; + if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_WEP_UNDECRYPTABLE_COUNT, + &value, sizeof(value))) + wstats->discard.code += value; + if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_WEP_EXCLUDED_COUNT, + &value, sizeof(value))) + wstats->discard.code += value; + if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_RETRY_COUNT, + &value, sizeof(value))) + wstats->discard.retries = value; + if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_FAILED_COUNT, + &value, sizeof(value))) + wstats->discard.misc += value; + if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_RTS_FAILURE_COUNT, + &value, sizeof(value))) + wstats->discard.misc += value; + if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_ACK_FAILURE_COUNT, + &value, sizeof(value))) + wstats->discard.misc += value; + if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_FRAME_DUPLICATE_COUNT, + &value, sizeof(value))) + wstats->discard.misc += value; + return wstats; +} + +static inline int wl3501_ethtool_ioctl(struct net_device *dev, void *uaddr) +{ + u32 ethcmd; + int rc = -EFAULT; + + if (copy_from_user(ðcmd, uaddr, sizeof(ethcmd))) + goto out; + + switch (ethcmd) { + case ETHTOOL_GDRVINFO: { + struct ethtool_drvinfo info = { .cmd = ETHTOOL_GDRVINFO, }; + + strlcpy(info.driver, wl3501_dev_info, sizeof(info.driver)); + rc = copy_to_user(uaddr, &info, sizeof(info)) ? -EFAULT : 1; + } + default: + rc = -EOPNOTSUPP; + break; + } +out: + return rc; +} + +/** + * wl3501_ioctl - Perform IOCTL call functions + * @dev - network device + * @ifreq - request + * @cmd - command + * + * Perform IOCTL call functions here. Some are privileged operations and the + * effective uid is checked in those cases. + * + * This part is optional. Needed only if you want to run wlu (unix version). + * + * CAUTION: To prevent interrupted by wl3501_interrupt() and timer-based + * wl3501_hard_start_xmit() from other interrupts, this should be run + * single-threaded. + */ +static int wl3501_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + int rc = -ENODEV; + + if (netif_device_present(dev)) { + rc = -EOPNOTSUPP; + if (cmd == SIOCETHTOOL) + rc = wl3501_ethtool_ioctl(dev, (void *)rq->ifr_data); + } + return rc; +} + +/** + * wl3501_detach - deletes a driver "instance" + * @link - FILL_IN + * + * This deletes a driver "instance". The device is de-registered with Card + * Services. If it has been released, all local data structures are freed. + * Otherwise, the structures will be freed when the device is released. + */ +static void wl3501_detach(dev_link_t *link) +{ + dev_link_t **linkp; + + /* Locate device structure */ + for (linkp = &wl3501_dev_list; *linkp; linkp = &(*linkp)->next) + if (*linkp == link) + break; + if (!*linkp) + goto out; + + /* If the device is currently configured and active, we won't actually + * delete it yet. Instead, it is marked so that when the release() + * function is called, that will trigger a proper detach(). */ + + if (link->state & DEV_CONFIG) { +#ifdef PCMCIA_DEBUG + printk(KERN_DEBUG "wl3501_cs: detach postponed, '%s' " + "still locked\n", link->dev->dev_name); +#endif + link->state |= DEV_STALE_LINK; + goto out; + } + + /* Break the link with Card Services */ + if (link->handle) + CardServices(DeregisterClient, link->handle); + + /* Unlink device structure, free pieces */ + *linkp = link->next; + + if (link->priv) + kfree(link->priv); + kfree(link); +out: + return; +} + +/** + * wl3501_flush_stale_links - Remove zombie instances + * + * Remove zombie instances (card removed, detach pending) + */ +static void wl3501_flush_stale_links(void) +{ + dev_link_t *link, *next; + + for (link = wl3501_dev_list; link; link = next) { + next = link->next; + if (link->state & DEV_STALE_LINK) + wl3501_detach(link); + } +} + +static int wl3501_get_name(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + strlcpy(wrqu->name, "IEEE 802.11-DS", sizeof(wrqu->name)); + return 0; +} + +static int wl3501_set_freq(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct wl3501_card *this = dev->priv; + int channel = wrqu->freq.m; + int rc = -EINVAL; + + if (iw_valid_channel(this->reg_domain, channel)) { + this->chan = channel; + rc = wl3501_reset(dev); + } + return rc; +} + +static int wl3501_get_freq(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct wl3501_card *this = dev->priv; + + wrqu->freq.m = wl3501_chan2freq[this->chan - 1] * 100000; + wrqu->freq.e = 1; + return 0; +} + +static int wl3501_set_mode(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int rc = -EINVAL; + + if (wrqu->mode == IW_MODE_INFRA || + wrqu->mode == IW_MODE_ADHOC || + wrqu->mode == IW_MODE_AUTO) { + struct wl3501_card *this = dev->priv; + + this->net_type = wrqu->mode; + rc = wl3501_reset(dev); + } + return rc; +} + +static int wl3501_get_mode(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct wl3501_card *this = dev->priv; + + wrqu->mode = this->net_type; + return 0; +} + +static int wl3501_get_sens(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct wl3501_card *this = dev->priv; + + wrqu->sens.value = this->rssi; + wrqu->sens.disabled = !wrqu->sens.value; + wrqu->sens.fixed = 1; + return 0; +} + +static int wl3501_get_range(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct iw_range *range = (struct iw_range *)extra; + + /* Set the length (very important for backward compatibility) */ + wrqu->data.length = sizeof(*range); + + /* Set all the info we don't care or don't know about to zero */ + memset(range, 0, sizeof(*range)); + + /* Set the Wireless Extension versions */ + range->we_version_compiled = WIRELESS_EXT; + range->we_version_source = 1; + range->throughput = 2 * 1000 * 1000; /* ~2 Mb/s */ + /* FIXME: study the code to fill in more fields... */ + return 0; +} + +static int wl3501_set_wap(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct wl3501_card *this = dev->priv; + static const u8 bcast[ETH_ALEN] = { 255, 255, 255, 255, 255, 255 }; + int rc = -EINVAL; + + /* FIXME: we support other ARPHRDs...*/ + if (wrqu->ap_addr.sa_family != ARPHRD_ETHER) + goto out; + if (!memcmp(bcast, wrqu->ap_addr.sa_data, ETH_ALEN)) { + /* FIXME: rescan? */ + } else + memcpy(this->bssid, wrqu->ap_addr.sa_data, ETH_ALEN); + /* FIXME: rescan? deassoc & scan? */ + rc = 0; +out: + return rc; +} + +static int wl3501_get_wap(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct wl3501_card *this = dev->priv; + + wrqu->ap_addr.sa_family = ARPHRD_ETHER; + memcpy(wrqu->ap_addr.sa_data, this->bssid, ETH_ALEN); + return 0; +} + +static int wl3501_set_essid(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct wl3501_card *this = dev->priv; + int rc = 0; + + if (wrqu->data.flags) { + strlcpy(this->essid + 2, extra, min_t(u16, wrqu->data.length, + IW_ESSID_MAX_SIZE)); + rc = wl3501_reset(dev); + } + return rc; +} + +static int wl3501_get_essid(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct wl3501_card *this = dev->priv; + unsigned long flags; + + spin_lock_irqsave(&this->lock, flags); + wrqu->essid.flags = 1; + wrqu->essid.length = IW_ESSID_MAX_SIZE; + strlcpy(extra, this->essid + 2, IW_ESSID_MAX_SIZE); + spin_unlock_irqrestore(&this->lock, flags); + return 0; +} + +static int wl3501_set_nick(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct wl3501_card *this = dev->priv; + + if (wrqu->data.length > sizeof(this->nick)) + return -E2BIG; + strlcpy(this->nick, extra, wrqu->data.length); + return 0; +} + +static int wl3501_get_nick(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct wl3501_card *this = dev->priv; + + strlcpy(extra, this->nick, 32); + wrqu->data.length = strlen(extra); + return 0; +} + +static int wl3501_get_rate(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + /* + * FIXME: have to see from where to get this info, perhaps this card + * works at 1 Mbit/s too... for now leave at 2 Mbit/s that is the most + * common with the Planet Access Points. -acme + */ + wrqu->bitrate.value = 2000000; + wrqu->bitrate.fixed = 1; + return 0; +} + +static int wl3501_get_rts_threshold(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + u16 threshold; /* size checked: it is u16 */ + struct wl3501_card *this = dev->priv; + int rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_RTS_THRESHOLD, + &threshold, sizeof(threshold)); + if (!rc) { + wrqu->rts.value = threshold; + wrqu->rts.disabled = threshold >= 2347; + wrqu->rts.fixed = 1; + } + return rc; +} + +static int wl3501_get_frag_threshold(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + u16 threshold; /* size checked: it is u16 */ + struct wl3501_card *this = dev->priv; + int rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_FRAG_THRESHOLD, + &threshold, sizeof(threshold)); + if (!rc) { + wrqu->frag.value = threshold; + wrqu->frag.disabled = threshold >= 2346; + wrqu->frag.fixed = 1; + } + return rc; +} + +static int wl3501_get_txpow(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + u16 txpow; + struct wl3501_card *this = dev->priv; + int rc = wl3501_get_mib_value(this, + WL3501_MIB_ATTR_CURRENT_TX_PWR_LEVEL, + &txpow, sizeof(txpow)); + if (!rc) { + wrqu->txpower.value = txpow; + wrqu->txpower.disabled = 0; + /* + * From the MIB values I think this can be configurable, + * as it lists several tx power levels -acme + */ + wrqu->txpower.fixed = 0; + wrqu->txpower.flags = IW_TXPOW_MWATT; + } + return rc; +} + +static int wl3501_get_retry(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + u8 retry; /* size checked: it is u8 */ + struct wl3501_card *this = dev->priv; + int rc = wl3501_get_mib_value(this, + WL3501_MIB_ATTR_LONG_RETRY_LIMIT, + &retry, sizeof(retry)); + if (rc) + goto out; + if (wrqu->retry.flags & IW_RETRY_MAX) { + wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MAX; + goto set_value; + } + rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_SHORT_RETRY_LIMIT, + &retry, sizeof(retry)); + if (rc) + goto out; + wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MIN; +set_value: + wrqu->retry.value = retry; + wrqu->retry.disabled = 0; +out: + return rc; +} + +static int wl3501_get_encode(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + u8 implemented, restricted, keys[100], len_keys, tocopy; + struct wl3501_card *this = dev->priv; + int rc = wl3501_get_mib_value(this, + WL3501_MIB_ATTR_PRIV_OPT_IMPLEMENTED, + &implemented, sizeof(implemented)); + if (rc) + goto out; + if (!implemented) { + wrqu->encoding.flags = IW_ENCODE_DISABLED; + goto out; + } + rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_EXCLUDE_UNENCRYPTED, + &restricted, sizeof(restricted)); + if (rc) + goto out; + wrqu->encoding.flags = restricted ? IW_ENCODE_RESTRICTED : + IW_ENCODE_OPEN; + rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_WEP_KEY_MAPPINGS_LEN, + &len_keys, sizeof(len_keys)); + if (rc) + goto out; + rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_WEP_KEY_MAPPINGS, + keys, len_keys); + if (rc) + goto out; + tocopy = min_t(u8, len_keys, wrqu->encoding.length); + tocopy = min_t(u8, tocopy, 100); + wrqu->encoding.length = tocopy; + memset(extra, 0, tocopy); + memcpy(extra, keys, tocopy); +out: + return rc; +} + +static int wl3501_get_power(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + u8 pwr_state; + struct wl3501_card *this = dev->priv; + int rc = wl3501_get_mib_value(this, + WL3501_MIB_ATTR_CURRENT_PWR_STATE, + &pwr_state, sizeof(pwr_state)); + if (rc) + goto out; + wrqu->power.disabled = !pwr_state; + wrqu->power.flags = IW_POWER_ON; +out: + return rc; +} + +static const iw_handler wl3501_handler[] = { + [SIOCGIWNAME - SIOCIWFIRST] = wl3501_get_name, + [SIOCSIWFREQ - SIOCIWFIRST] = wl3501_set_freq, + [SIOCGIWFREQ - SIOCIWFIRST] = wl3501_get_freq, + [SIOCSIWMODE - SIOCIWFIRST] = wl3501_set_mode, + [SIOCGIWMODE - SIOCIWFIRST] = wl3501_get_mode, + [SIOCGIWSENS - SIOCIWFIRST] = wl3501_get_sens, + [SIOCGIWRANGE - SIOCIWFIRST] = wl3501_get_range, + [SIOCSIWSPY - SIOCIWFIRST] = iw_handler_set_spy, + [SIOCGIWSPY - SIOCIWFIRST] = iw_handler_get_spy, + [SIOCSIWTHRSPY - SIOCIWFIRST] = iw_handler_set_thrspy, + [SIOCGIWTHRSPY - SIOCIWFIRST] = iw_handler_get_thrspy, + [SIOCSIWAP - SIOCIWFIRST] = wl3501_set_wap, + [SIOCGIWAP - SIOCIWFIRST] = wl3501_get_wap, + [SIOCSIWESSID - SIOCIWFIRST] = wl3501_set_essid, + [SIOCGIWESSID - SIOCIWFIRST] = wl3501_get_essid, + [SIOCSIWNICKN - SIOCIWFIRST] = wl3501_set_nick, + [SIOCGIWNICKN - SIOCIWFIRST] = wl3501_get_nick, + [SIOCGIWRATE - SIOCIWFIRST] = wl3501_get_rate, + [SIOCGIWRTS - SIOCIWFIRST] = wl3501_get_rts_threshold, + [SIOCGIWFRAG - SIOCIWFIRST] = wl3501_get_frag_threshold, + [SIOCGIWTXPOW - SIOCIWFIRST] = wl3501_get_txpow, + [SIOCGIWRETRY - SIOCIWFIRST] = wl3501_get_retry, + [SIOCGIWENCODE - SIOCIWFIRST] = wl3501_get_encode, + [SIOCGIWPOWER - SIOCIWFIRST] = wl3501_get_power, +}; + +static const struct iw_handler_def wl3501_handler_def = { + .num_standard = sizeof(wl3501_handler) / sizeof(iw_handler), + .standard = (iw_handler *)wl3501_handler, + .spy_offset = offsetof(struct wl3501_card, spy_data), +}; + +/** + * wl3501_attach - creates an "instance" of the driver + * + * Creates an "instance" of the driver, allocating local data structures for + * one device. The device is registered with Card Services. + * + * The dev_link structure is initialized, but we don't actually configure the + * card at this point -- we wait until we receive a card insertion event. + */ +static dev_link_t *wl3501_attach(void) +{ + client_reg_t client_reg; + dev_link_t *link; + struct net_device *dev; + int ret, i; + + wl3501_flush_stale_links(); + + /* Initialize the dev_link_t structure */ + link = kmalloc(sizeof(*link), GFP_KERNEL); + if (!link) + goto out; + memset(link, 0, sizeof(struct dev_link_t)); + init_timer(&link->release); + link->release.function = wl3501_release; + link->release.data = (unsigned long)link; + + /* The io structure describes IO port mapping */ + link->io.NumPorts1 = 16; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + link->io.IOAddrLines = 5; + + /* Interrupt setup */ + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; + link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID; + link->irq.IRQInfo2 = wl3501_irq_mask; + if (wl3501_irq_list[0] != -1) + for (i = 0; i < 4; i++) + link->irq.IRQInfo2 |= 1 << wl3501_irq_list[i]; + link->irq.Handler = wl3501_interrupt; + + /* General socket configuration */ + link->conf.Attributes = CONF_ENABLE_IRQ; + link->conf.Vcc = 50; + link->conf.IntType = INT_MEMORY_AND_IO; + link->conf.ConfigIndex = 1; + link->conf.Present = PRESENT_OPTION; + + dev = alloc_etherdev(sizeof(struct wl3501_card)); + if (!dev) + goto out_link; + dev->init = wl3501_init; + dev->open = wl3501_open; + dev->stop = wl3501_close; + dev->hard_start_xmit = wl3501_hard_start_xmit; + dev->tx_timeout = wl3501_tx_timeout; + dev->watchdog_timeo = 5 * HZ; + dev->get_stats = wl3501_get_stats; + dev->get_wireless_stats = wl3501_get_wireless_stats; + dev->do_ioctl = wl3501_ioctl; + dev->wireless_handlers = (struct iw_handler_def *)&wl3501_handler_def; + netif_stop_queue(dev); + link->priv = link->irq.Instance = dev; + + /* Register with Card Services */ + link->next = wl3501_dev_list; + wl3501_dev_list = link; + client_reg.dev_info = &wl3501_dev_info; + client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; + client_reg.EventMask = CS_EVENT_CARD_INSERTION | + CS_EVENT_RESET_PHYSICAL | + CS_EVENT_CARD_RESET | + CS_EVENT_CARD_REMOVAL | + CS_EVENT_PM_SUSPEND | + CS_EVENT_PM_RESUME; + client_reg.event_handler = wl3501_event; + client_reg.Version = 0x0210; + client_reg.event_callback_args.client_data = link; + ret = CardServices(RegisterClient, &link->handle, &client_reg); + if (ret) { + cs_error(link->handle, RegisterClient, ret); + wl3501_detach(link); + link = NULL; + } +out: + return link; +out_link: + kfree(link); + link = NULL; + goto out; +} + +#define CS_CHECK(fn, args...) \ +while ((last_ret = CardServices(last_fn = (fn), args)) != 0) goto cs_failed + +/** + * wl3501_config - configure the PCMCIA socket and make eth device available + * @link - FILL_IN + * + * wl3501_config() is scheduled to run after a CARD_INSERTION event is + * received, to configure the PCMCIA socket, and to make the ethernet device + * available to the system. + */ +static void wl3501_config(dev_link_t *link) +{ + tuple_t tuple; + cisparse_t parse; + client_handle_t handle = link->handle; + struct net_device *dev = link->priv; + int i = 0, j, last_fn, last_ret; + unsigned char bf[64]; + struct wl3501_card *this; + + /* This reads the card's CONFIG tuple to find its config registers. */ + tuple.Attributes = 0; + tuple.DesiredTuple = CISTPL_CONFIG; + CS_CHECK(GetFirstTuple, handle, &tuple); + tuple.TupleData = bf; + tuple.TupleDataMax = sizeof(bf); + tuple.TupleOffset = 0; + CS_CHECK(GetTupleData, handle, &tuple); + CS_CHECK(ParseTuple, handle, &tuple, &parse); + link->conf.ConfigBase = parse.config.base; + link->conf.Present = parse.config.rmask[0]; + + /* Configure card */ + link->state |= DEV_CONFIG; + + /* Try allocating IO ports. This tries a few fixed addresses. If you + * want, you can also read the card's config table to pick addresses -- + * see the serial driver for an example. */ + + for (j = 0x280; j < 0x400; j += 0x20) { + /* The '^0x300' is so that we probe 0x300-0x3ff first, then + * 0x200-0x2ff, and so on, because this seems safer */ + link->io.BasePort1 = j; + link->io.BasePort2 = link->io.BasePort1 + 0x10; + i = CardServices(RequestIO, link->handle, &link->io); + if (i == CS_SUCCESS) + break; + } + if (i != CS_SUCCESS) { + cs_error(link->handle, RequestIO, i); + goto failed; + } + + /* Now allocate an interrupt line. Note that this does not actually + * assign a handler to the interrupt. */ + + CS_CHECK(RequestIRQ, link->handle, &link->irq); + + /* This actually configures the PCMCIA socket -- setting up the I/O + * windows and the interrupt mapping. */ + + CS_CHECK(RequestConfiguration, link->handle, &link->conf); + + dev->irq = link->irq.AssignedIRQ; + dev->base_addr = link->io.BasePort1; + if (register_netdev(dev)) { + printk(KERN_NOTICE "wl3501_cs: register_netdev() failed\n"); + goto failed; + } + + SET_MODULE_OWNER(dev); + + this = dev->priv; + /* + * At this point, the dev_node_t structure(s) should be initialized and + * arranged in a linked list at link->dev. + */ + link->dev = &this->node; + link->state &= ~DEV_CONFIG_PENDING; + + this->base_addr = dev->base_addr; + + if (!wl3501_get_flash_mac_addr(this)) { + printk(KERN_WARNING "%s: Cant read MAC addr in flash ROM?\n", + dev->name); + goto failed; + } + strcpy(this->node.dev_name, dev->name); + + /* print probe information */ + printk(KERN_INFO "%s: wl3501 @ 0x%3.3x, IRQ %d, MAC addr in flash ROM:", + dev->name, this->base_addr, (int)dev->irq); + for (i = 0; i < 6; i++) { + dev->dev_addr[i] = ((char *)&this->mac_addr)[i]; + printk("%c%02x", i ? ':' : ' ', dev->dev_addr[i]); + } + printk("\n"); + /* + * Initialize card parameters - added by jss + */ + this->net_type = IW_MODE_INFRA; + this->bss_cnt = 0; + this->join_sta_bss = 0; + this->adhoc_times = 0; + this->essid[0] = 0; + this->essid[1] = 3; + this->essid[2] = 'A'; + this->essid[3] = 'N'; + this->essid[4] = 'Y'; + this->card_name[0] = '\0'; + this->firmware_date[0] = '\0'; + this->rssi = 255; + this->chan = iw_default_channel(this->reg_domain); + strlcpy(this->nick, "Planet WL3501", sizeof(this->nick)); + spin_lock_init(&this->lock); + init_waitqueue_head(&this->wait); + netif_start_queue(dev); + goto out; +cs_failed: + cs_error(link->handle, last_fn, last_ret); +failed: + wl3501_release((unsigned long)link); +out: + return; +} + +/** + * wl3501_release - unregister the net, release PCMCIA configuration + * @arg - link + * + * After a card is removed, wl3501_release() will unregister the net device, + * and release the PCMCIA configuration. If the device is still open, this + * will be postponed until it is closed. + */ +static void wl3501_release(unsigned long arg) +{ + dev_link_t *link = (dev_link_t *)arg; + struct net_device *dev = link->priv; + + /* If the device is currently in use, we won't release until it is + * actually closed. */ + if (link->open) { + dprintk(1, "release postponed, '%s' still open", + link->dev->dev_name); + link->state |= DEV_STALE_CONFIG; + goto out; + } + + /* Unlink the device chain */ + if (link->dev) { + unregister_netdev(dev); + link->dev = NULL; + } + + /* Don't bother checking to see if these succeed or not */ + CardServices(ReleaseConfiguration, link->handle); + CardServices(ReleaseIO, link->handle, &link->io); + CardServices(ReleaseIRQ, link->handle, &link->irq); + link->state &= ~DEV_CONFIG; + + if (link->state & DEV_STALE_LINK) + wl3501_detach(link); +out: + return; +} + +/** + * wl3501_event - The card status event handler + * @event - event + * @pri - priority + * @args - arguments for this event + * + * The card status event handler. Mostly, this schedules other stuff to run + * after an event is received. A CARD_REMOVAL event also sets some flags to + * discourage the net drivers from trying to talk to the card any more. + * + * When a CARD_REMOVAL event is received, we immediately set a flag to block + * future accesses to this device. All the functions that actually access the + * device should check this flag to make sure the card is still present. + */ +static int wl3501_event(event_t event, int pri, event_callback_args_t *args) +{ + dev_link_t *link = args->client_data; + struct net_device *dev = link->priv; + + switch (event) { + case CS_EVENT_CARD_REMOVAL: + link->state &= ~DEV_PRESENT; + if (link->state & DEV_CONFIG) { + while (link->open > 0) + wl3501_close(dev); + netif_device_detach(dev); + link->release.expires = jiffies + + WL3501_RELEASE_TIMEOUT; + add_timer(&link->release); + } + break; + case CS_EVENT_CARD_INSERTION: + link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; + wl3501_config(link); + break; + case CS_EVENT_PM_SUSPEND: + link->state |= DEV_SUSPEND; + wl3501_pwr_mgmt(dev->priv, WL3501_SUSPEND); + /* Fall through... */ + case CS_EVENT_RESET_PHYSICAL: + if (link->state & DEV_CONFIG) { + if (link->open) + netif_device_detach(dev); + CardServices(ReleaseConfiguration, link->handle); + } + break; + case CS_EVENT_PM_RESUME: + link->state &= ~DEV_SUSPEND; + wl3501_pwr_mgmt(dev->priv, WL3501_RESUME); + /* Fall through... */ + case CS_EVENT_CARD_RESET: + if (link->state & DEV_CONFIG) { + CardServices(RequestConfiguration, link->handle, + &link->conf); + if (link->open) { + wl3501_reset(dev); + netif_device_attach(dev); + } + } + break; + } + return 0; +} + +static struct pcmcia_driver wl3501_driver = { + .owner = THIS_MODULE, + .drv = { + .name = "wl3501_cs", + }, + .attach = wl3501_attach, + .detach = wl3501_detach, +}; + +static int __init wl3501_init_module(void) +{ + servinfo_t serv; + + dprintk(0, ": loading"); + CardServices(GetCardServicesInfo, &serv); + if (serv.Revision != CS_RELEASE_CODE) { + printk(KERN_NOTICE + "wl3501_cs: Card Services release does not match!\n" + "Compiled with 0x%x, but current is 0x%lx\n", + CS_RELEASE_CODE, (unsigned long)serv.Revision); + /* return -1; */ + } + pcmcia_register_driver(&wl3501_driver); + return 0; +} + +static void __exit wl3501_exit_module(void) +{ + dprintk(0, ": unloading"); + pcmcia_unregister_driver(&wl3501_driver); + while (wl3501_dev_list) { + del_timer(&wl3501_dev_list->release); + /* Mark the device as non-existing to minimize calls to card */ + wl3501_dev_list->state &= ~DEV_PRESENT; + if (wl3501_dev_list->state & DEV_CONFIG) + wl3501_release((unsigned long)wl3501_dev_list); + wl3501_detach(wl3501_dev_list); + } +} + +module_init(wl3501_init_module); +module_exit(wl3501_exit_module); + +MODULE_PARM(wl3501_irq_mask, "i"); +MODULE_PARM(wl3501_irq_list, "1-4i"); +MODULE_AUTHOR("Fox Chen , " + "Arnaldo Carvalho de Melo ," + "Gustavo Niemeyer "); +MODULE_DESCRIPTION("Planet wl3501 wireless driver"); +MODULE_LICENSE("GPL"); diff -Nru a/drivers/net/zorro8390.c b/drivers/net/zorro8390.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/zorro8390.c Sun Jul 27 10:13:47 2003 @@ -0,0 +1,425 @@ +/* + * Amiga Linux/m68k and Linux/PPC Zorro NS8390 Ethernet Driver + * + * (C) Copyright 1998-2000 by some Elitist 680x0 Users(TM) + * + * --------------------------------------------------------------------------- + * + * This program is based on all the other NE2000 drivers for Linux + * + * --------------------------------------------------------------------------- + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of the Linux + * distribution for more details. + * + * --------------------------------------------------------------------------- + * + * The Ariadne II and X-Surf are Zorro-II boards containing Realtek RTL8019AS + * Ethernet Controllers. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "8390.h" + + +#define NE_BASE (dev->base_addr) +#define NE_CMD (0x00*2) +#define NE_DATAPORT (0x10*2) /* NatSemi-defined port window offset. */ +#define NE_RESET (0x1f*2) /* Issue a read to reset, a write to clear. */ +#define NE_IO_EXTENT (0x20*2) + +#define NE_EN0_ISR (0x07*2) +#define NE_EN0_DCFG (0x0e*2) + +#define NE_EN0_RSARLO (0x08*2) +#define NE_EN0_RSARHI (0x09*2) +#define NE_EN0_RCNTLO (0x0a*2) +#define NE_EN0_RXCR (0x0c*2) +#define NE_EN0_TXCR (0x0d*2) +#define NE_EN0_RCNTHI (0x0b*2) +#define NE_EN0_IMR (0x0f*2) + +#define NESM_START_PG 0x40 /* First page of TX buffer */ +#define NESM_STOP_PG 0x80 /* Last page +1 of RX ring */ + + +#define WORDSWAP(a) ((((a)>>8)&0xff) | ((a)<<8)) + +#ifdef MODULE +static struct net_device *root_zorro8390_dev; +#endif + +static const struct card_info { + zorro_id id; + const char *name; + unsigned int offset; +} cards[] __initdata = { + { ZORRO_PROD_VILLAGE_TRONIC_ARIADNE2, "Ariadne II", 0x0600 }, + { ZORRO_PROD_INDIVIDUAL_COMPUTERS_X_SURF, "X-Surf", 0x8600 }, +}; + +static int __init zorro8390_probe(void); +static int __init zorro8390_init(struct net_device *dev, unsigned long board, + const char *name, unsigned long ioaddr); +static int zorro8390_open(struct net_device *dev); +static int zorro8390_close(struct net_device *dev); +static void zorro8390_reset_8390(struct net_device *dev); +static void zorro8390_get_8390_hdr(struct net_device *dev, + struct e8390_pkt_hdr *hdr, int ring_page); +static void zorro8390_block_input(struct net_device *dev, int count, + struct sk_buff *skb, int ring_offset); +static void zorro8390_block_output(struct net_device *dev, const int count, + const unsigned char *buf, + const int start_page); +static void __exit zorro8390_cleanup(void); + +static int __init zorro8390_probe(void) +{ + struct net_device *dev; + struct zorro_dev *z = NULL; + unsigned long board, ioaddr; + int err = -ENODEV; + int i; + + while ((z = zorro_find_device(ZORRO_WILDCARD, z))) { + for (i = ARRAY_SIZE(cards)-1; i >= 0; i--) + if (z->id == cards[i].id) + break; + if (i < 0) + continue; + board = z->resource.start; + ioaddr = board+cards[i].offset; + dev = init_etherdev(0, 0); + SET_MODULE_OWNER(dev); + if (!dev) + return -ENOMEM; + if (!request_mem_region(ioaddr, NE_IO_EXTENT*2, dev->name)) { + kfree(dev); + continue; + } + if ((err = zorro8390_init(dev, board, cards[i].name, + ZTWO_VADDR(ioaddr)))) { + release_mem_region(ioaddr, NE_IO_EXTENT*2); + kfree(dev); + return err; + } + err = 0; + } + + if (err == -ENODEV) + printk("No Ariadne II or X-Surf ethernet card found.\n"); + return err; +} + +static int __init zorro8390_init(struct net_device *dev, unsigned long board, + const char *name, unsigned long ioaddr) +{ + int i; + unsigned char SA_prom[32]; + int start_page, stop_page; + static u32 zorro8390_offsets[16] = { + 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, + 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e, + }; + + /* Reset card. Who knows what dain-bramaged state it was left in. */ + { + unsigned long reset_start_time = jiffies; + + z_writeb(z_readb(ioaddr + NE_RESET), ioaddr + NE_RESET); + + while ((z_readb(ioaddr + NE_EN0_ISR) & ENISR_RESET) == 0) + if (jiffies - reset_start_time > 2*HZ/100) { + printk(" not found (no reset ack).\n"); + return -ENODEV; + } + + z_writeb(0xff, ioaddr + NE_EN0_ISR); /* Ack all intr. */ + } + + /* Read the 16 bytes of station address PROM. + We must first initialize registers, similar to NS8390_init(eifdev, 0). + We can't reliably read the SAPROM address without this. + (I learned the hard way!). */ + { + struct { + u32 value; + u32 offset; + } program_seq[] = { + {E8390_NODMA+E8390_PAGE0+E8390_STOP, NE_CMD}, /* Select page 0*/ + {0x48, NE_EN0_DCFG}, /* Set byte-wide (0x48) access. */ + {0x00, NE_EN0_RCNTLO}, /* Clear the count regs. */ + {0x00, NE_EN0_RCNTHI}, + {0x00, NE_EN0_IMR}, /* Mask completion irq. */ + {0xFF, NE_EN0_ISR}, + {E8390_RXOFF, NE_EN0_RXCR}, /* 0x20 Set to monitor */ + {E8390_TXOFF, NE_EN0_TXCR}, /* 0x02 and loopback mode. */ + {32, NE_EN0_RCNTLO}, + {0x00, NE_EN0_RCNTHI}, + {0x00, NE_EN0_RSARLO}, /* DMA starting at 0x0000. */ + {0x00, NE_EN0_RSARHI}, + {E8390_RREAD+E8390_START, NE_CMD}, + }; + for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++) { + z_writeb(program_seq[i].value, ioaddr + program_seq[i].offset); + } + } + for (i = 0; i < 16; i++) { + SA_prom[i] = z_readb(ioaddr + NE_DATAPORT); + (void)z_readb(ioaddr + NE_DATAPORT); + } + + /* We must set the 8390 for word mode. */ + z_writeb(0x49, ioaddr + NE_EN0_DCFG); + start_page = NESM_START_PG; + stop_page = NESM_STOP_PG; + + dev->base_addr = ioaddr; + dev->irq = IRQ_AMIGA_PORTS; + + /* Install the Interrupt handler */ + i = request_irq(IRQ_AMIGA_PORTS, ei_interrupt, SA_SHIRQ, dev->name, dev); + if (i) return i; + + /* Allocate dev->priv and fill in 8390 specific dev fields. */ + if (ethdev_init(dev)) { + printk("Unable to get memory for dev->priv.\n"); + return -ENOMEM; + } + + for(i = 0; i < ETHER_ADDR_LEN; i++) { +#ifdef DEBUG + printk(" %2.2x", SA_prom[i]); +#endif + dev->dev_addr[i] = SA_prom[i]; + } + + printk("%s: %s at 0x%08lx, Ethernet Address " + "%02x:%02x:%02x:%02x:%02x:%02x\n", dev->name, name, board, + dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], + dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + + ei_status.name = name; + ei_status.tx_start_page = start_page; + ei_status.stop_page = stop_page; + ei_status.word16 = 1; + + ei_status.rx_start_page = start_page + TX_PAGES; + + ei_status.reset_8390 = &zorro8390_reset_8390; + ei_status.block_input = &zorro8390_block_input; + ei_status.block_output = &zorro8390_block_output; + ei_status.get_8390_hdr = &zorro8390_get_8390_hdr; + ei_status.reg_offset = zorro8390_offsets; + dev->open = &zorro8390_open; + dev->stop = &zorro8390_close; +#ifdef MODULE + ei_status.priv = (unsigned long)root_zorro8390_dev; + root_zorro8390_dev = dev; +#endif + NS8390_init(dev, 0); + return 0; +} + +static int zorro8390_open(struct net_device *dev) +{ + ei_open(dev); + return 0; +} + +static int zorro8390_close(struct net_device *dev) +{ + if (ei_debug > 1) + printk("%s: Shutting down ethercard.\n", dev->name); + ei_close(dev); + return 0; +} + +/* Hard reset the card. This used to pause for the same period that a + 8390 reset command required, but that shouldn't be necessary. */ +static void zorro8390_reset_8390(struct net_device *dev) +{ + unsigned long reset_start_time = jiffies; + + if (ei_debug > 1) + printk("resetting the 8390 t=%ld...", jiffies); + + z_writeb(z_readb(NE_BASE + NE_RESET), NE_BASE + NE_RESET); + + ei_status.txing = 0; + ei_status.dmaing = 0; + + /* This check _should_not_ be necessary, omit eventually. */ + while ((z_readb(NE_BASE+NE_EN0_ISR) & ENISR_RESET) == 0) + if (jiffies - reset_start_time > 2*HZ/100) { + printk("%s: ne_reset_8390() did not complete.\n", dev->name); + break; + } + z_writeb(ENISR_RESET, NE_BASE + NE_EN0_ISR); /* Ack intr. */ +} + +/* Grab the 8390 specific header. Similar to the block_input routine, but + we don't need to be concerned with ring wrap as the header will be at + the start of a page, so we optimize accordingly. */ + +static void zorro8390_get_8390_hdr(struct net_device *dev, + struct e8390_pkt_hdr *hdr, int ring_page) +{ + int nic_base = dev->base_addr; + int cnt; + short *ptrs; + + /* This *shouldn't* happen. If it does, it's the last thing you'll see */ + if (ei_status.dmaing) { + printk("%s: DMAing conflict in ne_get_8390_hdr " + "[DMAstat:%d][irqlock:%d].\n", dev->name, ei_status.dmaing, + ei_status.irqlock); + return; + } + + ei_status.dmaing |= 0x01; + z_writeb(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD); + z_writeb(ENISR_RDC, nic_base + NE_EN0_ISR); + z_writeb(sizeof(struct e8390_pkt_hdr), nic_base + NE_EN0_RCNTLO); + z_writeb(0, nic_base + NE_EN0_RCNTHI); + z_writeb(0, nic_base + NE_EN0_RSARLO); /* On page boundary */ + z_writeb(ring_page, nic_base + NE_EN0_RSARHI); + z_writeb(E8390_RREAD+E8390_START, nic_base + NE_CMD); + + ptrs = (short*)hdr; + for (cnt = 0; cnt < (sizeof(struct e8390_pkt_hdr)>>1); cnt++) + *ptrs++ = z_readw(NE_BASE + NE_DATAPORT); + + z_writeb(ENISR_RDC, nic_base + NE_EN0_ISR); /* Ack intr. */ + + hdr->count = WORDSWAP(hdr->count); + + ei_status.dmaing &= ~0x01; +} + +/* Block input and output, similar to the Crynwr packet driver. If you + are porting to a new ethercard, look at the packet driver source for hints. + The NEx000 doesn't share the on-board packet memory -- you have to put + the packet out through the "remote DMA" dataport using z_writeb. */ + +static void zorro8390_block_input(struct net_device *dev, int count, + struct sk_buff *skb, int ring_offset) +{ + int nic_base = dev->base_addr; + char *buf = skb->data; + short *ptrs; + int cnt; + + /* This *shouldn't* happen. If it does, it's the last thing you'll see */ + if (ei_status.dmaing) { + printk("%s: DMAing conflict in ne_block_input " + "[DMAstat:%d][irqlock:%d].\n", + dev->name, ei_status.dmaing, ei_status.irqlock); + return; + } + ei_status.dmaing |= 0x01; + z_writeb(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD); + z_writeb(ENISR_RDC, nic_base + NE_EN0_ISR); + z_writeb(count & 0xff, nic_base + NE_EN0_RCNTLO); + z_writeb(count >> 8, nic_base + NE_EN0_RCNTHI); + z_writeb(ring_offset & 0xff, nic_base + NE_EN0_RSARLO); + z_writeb(ring_offset >> 8, nic_base + NE_EN0_RSARHI); + z_writeb(E8390_RREAD+E8390_START, nic_base + NE_CMD); + ptrs = (short*)buf; + for (cnt = 0; cnt < (count>>1); cnt++) + *ptrs++ = z_readw(NE_BASE + NE_DATAPORT); + if (count & 0x01) + buf[count-1] = z_readb(NE_BASE + NE_DATAPORT); + + z_writeb(ENISR_RDC, nic_base + NE_EN0_ISR); /* Ack intr. */ + ei_status.dmaing &= ~0x01; +} + +static void zorro8390_block_output(struct net_device *dev, int count, + const unsigned char *buf, + const int start_page) +{ + int nic_base = NE_BASE; + unsigned long dma_start; + short *ptrs; + int cnt; + + /* Round the count up for word writes. Do we need to do this? + What effect will an odd byte count have on the 8390? + I should check someday. */ + if (count & 0x01) + count++; + + /* This *shouldn't* happen. If it does, it's the last thing you'll see */ + if (ei_status.dmaing) { + printk("%s: DMAing conflict in ne_block_output." + "[DMAstat:%d][irqlock:%d]\n", dev->name, ei_status.dmaing, + ei_status.irqlock); + return; + } + ei_status.dmaing |= 0x01; + /* We should already be in page 0, but to be safe... */ + z_writeb(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base + NE_CMD); + + z_writeb(ENISR_RDC, nic_base + NE_EN0_ISR); + + /* Now the normal output. */ + z_writeb(count & 0xff, nic_base + NE_EN0_RCNTLO); + z_writeb(count >> 8, nic_base + NE_EN0_RCNTHI); + z_writeb(0x00, nic_base + NE_EN0_RSARLO); + z_writeb(start_page, nic_base + NE_EN0_RSARHI); + + z_writeb(E8390_RWRITE+E8390_START, nic_base + NE_CMD); + ptrs = (short*)buf; + for (cnt = 0; cnt < count>>1; cnt++) + z_writew(*ptrs++, NE_BASE+NE_DATAPORT); + + dma_start = jiffies; + + while ((z_readb(NE_BASE + NE_EN0_ISR) & ENISR_RDC) == 0) + if (jiffies - dma_start > 2*HZ/100) { /* 20ms */ + printk("%s: timeout waiting for Tx RDC.\n", dev->name); + zorro8390_reset_8390(dev); + NS8390_init(dev,1); + break; + } + + z_writeb(ENISR_RDC, nic_base + NE_EN0_ISR); /* Ack intr. */ + ei_status.dmaing &= ~0x01; + return; +} + +static void __exit zorro8390_cleanup(void) +{ +#ifdef MODULE + struct net_device *dev, *next; + + while ((dev = root_zorro8390_dev)) { + next = (struct net_device *)(ei_status.priv); + unregister_netdev(dev); + free_irq(IRQ_AMIGA_PORTS, dev); + release_mem_region(ZTWO_PADDR(dev->base_addr), NE_IO_EXTENT*2); + kfree(dev); + root_zorro8390_dev = next; + } +#endif +} + +module_init(zorro8390_probe); +module_exit(zorro8390_cleanup); + +MODULE_LICENSE("GPL"); diff -Nru a/drivers/parisc/led.c b/drivers/parisc/led.c --- a/drivers/parisc/led.c Sun Jul 27 10:13:43 2003 +++ b/drivers/parisc/led.c Sun Jul 27 10:13:43 2003 @@ -14,6 +14,10 @@ * TODO: * - speed-up calculations with inlined assembler * - interface to write to second row of LCD from /proc (if technically possible) + * + * Changes: + * - Audit copy_from_user in led_proc_write. + * Daniele Bellucci */ #include @@ -160,7 +164,9 @@ memset(lbuf, 0, count); - copy_from_user(lbuf, buf, count); + if (copy_from_user(lbuf, buf, count)) + return -EFAULT; + cur = lbuf; /* skip initial spaces */ diff -Nru a/drivers/parport/Kconfig b/drivers/parport/Kconfig --- a/drivers/parport/Kconfig Sun Jul 27 10:13:52 2003 +++ b/drivers/parport/Kconfig Sun Jul 27 10:13:52 2003 @@ -36,7 +36,7 @@ config PARPORT_PC tristate "PC-style hardware" - depends on PARPORT + depends on PARPORT && (!SPARC64 || PCI) ---help--- You should say Y here if you have a PC-style parallel port. All IBM PC compatible computers and some Alphas have PC-style diff -Nru a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c --- a/drivers/parport/parport_pc.c Sun Jul 27 10:13:52 2003 +++ b/drivers/parport/parport_pc.c Sun Jul 27 10:13:52 2003 @@ -94,7 +94,8 @@ } superios[NR_SUPERIOS] __devinitdata = { {0,},}; static int user_specified __devinitdata = 0; -#if defined(CONFIG_PARPORT_PC_FIFO) || defined(CONFIG_PARPORT_PC_SUPERIO) +#if defined(CONFIG_PARPORT_PC_SUPERIO) || \ + (defined(CONFIG_PARPORT_1284) && defined(CONFIG_PARPORT_PC_FIFO)) static int verbose_probing; #endif static int registered_parport; @@ -3116,7 +3117,8 @@ MODULE_PARM(irq, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "s"); MODULE_PARM_DESC(dma, "DMA channel"); MODULE_PARM(dma, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "s"); -#if defined(CONFIG_PARPORT_PC_FIFO) || defined(CONFIG_PARPORT_PC_SUPERIO) +#if defined(CONFIG_PARPORT_PC_SUPERIO) || \ + (defined(CONFIG_PARPORT_1284) && defined(CONFIG_PARPORT_PC_FIFO)) MODULE_PARM_DESC(verbose_probing, "Log chit-chat during initialisation"); MODULE_PARM(verbose_probing, "i"); #endif diff -Nru a/drivers/pci/Makefile b/drivers/pci/Makefile --- a/drivers/pci/Makefile Sun Jul 27 10:13:51 2003 +++ b/drivers/pci/Makefile Sun Jul 27 10:13:51 2003 @@ -2,7 +2,7 @@ # Makefile for the PCI bus specific drivers. # -obj-y += access.o bus.o probe.o pci.o pool.o quirks.o \ +obj-y += access.o bus.o probe.o remove.o pci.o pool.o quirks.o \ names.o pci-driver.o search.o pci-sysfs.o obj-$(CONFIG_PM) += power.o obj-$(CONFIG_PROC_FS) += proc.o diff -Nru a/drivers/pci/hotplug/Kconfig b/drivers/pci/hotplug/Kconfig --- a/drivers/pci/hotplug/Kconfig Sun Jul 27 10:13:44 2003 +++ b/drivers/pci/hotplug/Kconfig Sun Jul 27 10:13:44 2003 @@ -99,22 +99,17 @@ When in doubt, say N. config HOTPLUG_PCI_CPCI - tristate "CompactPCI Hotplug driver" + bool "CompactPCI Hotplug driver" depends on HOTPLUG_PCI help Say Y here if you have a CompactPCI system card with CompactPCI hotswap support per the PICMG 2.1 specification. - This code is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called cpci_hotplug. If you want to compile it - as a module, say M here and read . - When in doubt, say N. config HOTPLUG_PCI_CPCI_ZT5550 tristate "Ziatech ZT5550 CompactPCI Hotplug driver" - depends on HOTPLUG_PCI_CPCI && X86 + depends on HOTPLUG_PCI && HOTPLUG_PCI_CPCI && X86 help Say Y here if you have an Performance Technologies (formerly Intel, formerly just Ziatech) Ziatech ZT5550 CompactPCI system card. @@ -128,7 +123,7 @@ config HOTPLUG_PCI_CPCI_GENERIC tristate "Generic port I/O CompactPCI Hotplug driver" - depends on HOTPLUG_PCI_CPCI && X86 + depends on HOTPLUG_PCI && HOTPLUG_PCI_CPCI && X86 help Say Y here if you have a CompactPCI system card that exposes the #ENUM hotswap signal as a bit in a system register that can be read through diff -Nru a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c --- a/drivers/pci/hotplug/acpiphp_glue.c Sun Jul 27 10:13:43 2003 +++ b/drivers/pci/hotplug/acpiphp_glue.c Sun Jul 27 10:13:43 2003 @@ -607,7 +607,7 @@ /* check if this bridge has ejectable slots */ if (detect_ejectable_slots(handle) > 0) { - dbg("found PCI-to-PCI bridge at PCI %s\n", dev->slot_name); + dbg("found PCI-to-PCI bridge at PCI %s\n", pci_name(dev)); add_p2p_bridge(handle, seg, bus, device, function); } @@ -693,7 +693,7 @@ if (func->flags & FUNC_HAS_PS0) { dbg("%s: executing _PS0 on %s\n", __FUNCTION__, - func->pci_dev->slot_name); + pci_name(func->pci_dev)); status = acpi_evaluate_object(func->handle, "_PS0", NULL, NULL); if (ACPI_FAILURE(status)) { warn("%s: _PS0 failed\n", __FUNCTION__); diff -Nru a/drivers/pci/hotplug/acpiphp_pci.c b/drivers/pci/hotplug/acpiphp_pci.c --- a/drivers/pci/hotplug/acpiphp_pci.c Sun Jul 27 10:13:39 2003 +++ b/drivers/pci/hotplug/acpiphp_pci.c Sun Jul 27 10:13:39 2003 @@ -212,7 +212,7 @@ int count; struct pci_resource *res; - dbg("Device %s\n", dev->slot_name); + dbg("Device %s\n", pci_name(dev)); for (count = 0; address[count]; count++) { /* for 6 BARs */ pci_read_config_dword(dev, address[count], &bar); @@ -337,7 +337,7 @@ struct pci_dev *dev; dev = func->pci_dev; - dbg("Hot-pluggable device %s\n", dev->slot_name); + dbg("Hot-pluggable device %s\n", pci_name(dev)); for (count = 0; address[count]; count++) { /* for 6 BARs */ pci_read_config_dword(dev, address[count], &bar); diff -Nru a/drivers/pci/hotplug/cpci_hotplug.h b/drivers/pci/hotplug/cpci_hotplug.h --- a/drivers/pci/hotplug/cpci_hotplug.h Sun Jul 27 10:13:41 2003 +++ b/drivers/pci/hotplug/cpci_hotplug.h Sun Jul 27 10:13:41 2003 @@ -75,7 +75,6 @@ extern int cpci_hp_unregister_controller(struct cpci_hp_controller *controller); extern int cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last); extern int cpci_hp_unregister_bus(struct pci_bus *bus); -extern struct slot *cpci_find_slot(struct pci_bus *bus, unsigned int devfn); extern int cpci_hp_start(void); extern int cpci_hp_stop(void); diff -Nru a/drivers/pci/hotplug/cpci_hotplug_core.c b/drivers/pci/hotplug/cpci_hotplug_core.c --- a/drivers/pci/hotplug/cpci_hotplug_core.c Sun Jul 27 10:13:44 2003 +++ b/drivers/pci/hotplug/cpci_hotplug_core.c Sun Jul 27 10:13:44 2003 @@ -427,34 +427,6 @@ return 0; } -struct slot * -cpci_find_slot(struct pci_bus *bus, unsigned int devfn) -{ - struct slot *slot; - struct slot *found; - struct list_head *tmp; - - if(!bus) { - return NULL; - } - - spin_lock(&list_lock); - if(!slots) { - spin_unlock(&list_lock); - return NULL; - } - found = NULL; - list_for_each(tmp, &slot_list) { - slot = list_entry(tmp, struct slot, slot_list); - if(slot->bus == bus && slot->devfn == devfn) { - found = slot; - break; - } - } - spin_unlock(&list_lock); - return found; -} - /* This is the interrupt mode interrupt handler */ irqreturn_t cpci_hp_intr(int irq, void *data, struct pt_regs *regs) @@ -924,6 +896,5 @@ EXPORT_SYMBOL_GPL(cpci_hp_unregister_controller); EXPORT_SYMBOL_GPL(cpci_hp_register_bus); EXPORT_SYMBOL_GPL(cpci_hp_unregister_bus); -EXPORT_SYMBOL_GPL(cpci_find_slot); EXPORT_SYMBOL_GPL(cpci_hp_start); EXPORT_SYMBOL_GPL(cpci_hp_stop); diff -Nru a/drivers/pci/hotplug/cpci_hotplug_pci.c b/drivers/pci/hotplug/cpci_hotplug_pci.c --- a/drivers/pci/hotplug/cpci_hotplug_pci.c Sun Jul 27 10:13:48 2003 +++ b/drivers/pci/hotplug/cpci_hotplug_pci.c Sun Jul 27 10:13:48 2003 @@ -448,7 +448,7 @@ } static int configure_visit_pci_dev(struct pci_dev_wrapped *wrapped_dev, - struct pci_bus_wrapped *wrapped_bus) + struct pci_bus_wrapped *wrapped_bus) { int rc; struct pci_dev *dev = wrapped_dev->dev; @@ -461,8 +461,8 @@ * We need to fix up the hotplug representation with the Linux * representation. */ - slot = cpci_find_slot(dev->bus, dev->devfn); - if(slot) { + if(wrapped_dev->data) { + slot = (struct slot*) wrapped_dev->data; slot->dev = dev; } @@ -494,9 +494,7 @@ return -ENODEV; /* Remove the Linux representation */ - if(pci_remove_device_safe(dev) == 0) { - kfree(dev); - } else { + if(pci_remove_device_safe(dev)) { err("Could not remove device\n"); return -1; } @@ -504,8 +502,8 @@ /* * Now remove the hotplug representation. */ - slot = cpci_find_slot(dev->bus, dev->devfn); - if(slot) { + if(wrapped_dev->data) { + slot = (struct slot*) wrapped_dev->data; slot->dev = NULL; } else { dbg("No hotplug representation for %02x:%02x.%x", @@ -574,13 +572,18 @@ /* Still NULL? Well then scan for it! */ if(slot->dev == NULL) { + int n; dbg("pci_dev still null"); /* * This will generate pci_dev structures for all functions, but * we will only call this case when lookup fails. */ - slot->dev = pci_scan_slot(slot->bus, slot->devfn); + n = pci_scan_slot(slot->bus, slot->devfn); + dbg("%s: pci_scan_slot returned %d", __FUNCTION__, n); + if(n > 0) + pci_bus_add_devices(slot->bus); + slot->dev = pci_find_slot(slot->bus->number, slot->devfn); if(slot->dev == NULL) { err("Could not find PCI device for slot %02x", slot->number); return 0; @@ -603,6 +606,10 @@ continue; wrapped_dev.dev = dev; wrapped_bus.bus = slot->dev->bus; + if(i) + wrapped_dev.data = NULL; + else + wrapped_dev.data = (void*) slot; rc = pci_visit_dev(&configure_functions, &wrapped_dev, &wrapped_bus); } } @@ -635,9 +642,14 @@ if(dev) { wrapped_dev.dev = dev; wrapped_bus.bus = dev->bus; + if(i) + wrapped_dev.data = NULL; + else + wrapped_dev.data = (void*) slot; dbg("%s - unconfigure phase 2", __FUNCTION__); rc = pci_visit_dev(&unconfigure_functions_phase2, - &wrapped_dev, &wrapped_bus); + &wrapped_dev, + &wrapped_bus); if(rc) break; } diff -Nru a/drivers/pci/hotplug.c b/drivers/pci/hotplug.c --- a/drivers/pci/hotplug.c Sun Jul 27 10:13:51 2003 +++ b/drivers/pci/hotplug.c Sun Jul 27 10:13:51 2003 @@ -10,8 +10,6 @@ #define DBG(x...) #endif -static void pci_free_resources(struct pci_dev *dev); - int pci_hotplug (struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size) { @@ -57,7 +55,7 @@ envp[i++] = scratch; length += snprintf (scratch, buffer_size - length, "PCI_SLOT_NAME=%s", - pdev->slot_name); + pci_name(pdev)); if ((buffer_size - length <= 0) || (i >= num_envp)) return -ENOMEM; @@ -172,105 +170,3 @@ } EXPORT_SYMBOL(pci_visit_dev); -static void pci_destroy_dev(struct pci_dev *dev) -{ - pci_proc_detach_device(dev); - device_unregister(&dev->dev); - - /* Remove the device from the device lists, and prevent any further - * list accesses from this device */ - spin_lock(&pci_bus_lock); - list_del(&dev->bus_list); - list_del(&dev->global_list); - dev->bus_list.next = dev->bus_list.prev = NULL; - dev->global_list.next = dev->global_list.prev = NULL; - spin_unlock(&pci_bus_lock); - - pci_free_resources(dev); - pci_dev_put(dev); -} - -/** - * pci_remove_device_safe - remove an unused hotplug device - * @dev: the device to remove - * - * Delete the device structure from the device lists and - * notify userspace (/sbin/hotplug), but only if the device - * in question is not being used by a driver. - * Returns 0 on success. - */ -int pci_remove_device_safe(struct pci_dev *dev) -{ - if (pci_dev_driver(dev)) - return -EBUSY; - pci_destroy_dev(dev); - return 0; -} -EXPORT_SYMBOL(pci_remove_device_safe); - -static void -pci_free_resources(struct pci_dev *dev) -{ - int i; - - for (i = 0; i < PCI_NUM_RESOURCES; i++) { - struct resource *res = dev->resource + i; - if (res->parent) - release_resource(res); - } -} - -/** - * pci_remove_bus_device - remove a PCI device and any children - * @dev: the device to remove - * - * Remove a PCI device from the device lists, informing the drivers - * that the device has been removed. We also remove any subordinate - * buses and children in a depth-first manner. - * - * For each device we remove, delete the device structure from the - * device lists, remove the /proc entry, and notify userspace - * (/sbin/hotplug). - */ -void pci_remove_bus_device(struct pci_dev *dev) -{ - if (dev->subordinate) { - struct pci_bus *b = dev->subordinate; - - pci_remove_behind_bridge(dev); - pci_proc_detach_bus(b); - - spin_lock(&pci_bus_lock); - list_del(&b->node); - spin_unlock(&pci_bus_lock); - - kfree(b); - dev->subordinate = NULL; - } - - pci_destroy_dev(dev); -} - -/** - * pci_remove_behind_bridge - remove all devices behind a PCI bridge - * @dev: PCI bridge device - * - * Remove all devices on the bus, except for the parent bridge. - * This also removes any child buses, and any devices they may - * contain in a depth-first manner. - */ -void pci_remove_behind_bridge(struct pci_dev *dev) -{ - struct list_head *l, *n; - - if (dev->subordinate) { - list_for_each_safe(l, n, &dev->subordinate->devices) { - struct pci_dev *dev = pci_dev_b(l); - - pci_remove_bus_device(dev); - } - } -} - -EXPORT_SYMBOL(pci_remove_bus_device); -EXPORT_SYMBOL(pci_remove_behind_bridge); diff -Nru a/drivers/pci/pci.c b/drivers/pci/pci.c --- a/drivers/pci/pci.c Sun Jul 27 10:13:43 2003 +++ b/drivers/pci/pci.c Sun Jul 27 10:13:43 2003 @@ -506,7 +506,7 @@ pci_resource_flags(pdev, bar) & IORESOURCE_IO ? "I/O" : "mem", bar + 1, /* PCI BAR # */ pci_resource_len(pdev, bar), pci_resource_start(pdev, bar), - pdev->slot_name); + pci_name(pdev)); return -EBUSY; } @@ -555,7 +555,7 @@ pci_resource_flags(pdev, i) & IORESOURCE_IO ? "I/O" : "mem", i + 1, /* PCI BAR # */ pci_resource_len(pdev, i), pci_resource_start(pdev, i), - pdev->slot_name); + pci_name(pdev)); while(--i >= 0) pci_release_region(pdev, i); @@ -576,7 +576,7 @@ pci_read_config_word(dev, PCI_COMMAND, &cmd); if (! (cmd & PCI_COMMAND_MASTER)) { - DBG("PCI: Enabling bus mastering for device %s\n", dev->slot_name); + DBG("PCI: Enabling bus mastering for device %s\n", pci_name(dev)); cmd |= PCI_COMMAND_MASTER; pci_write_config_word(dev, PCI_COMMAND, cmd); } @@ -620,7 +620,7 @@ return 0; printk(KERN_WARNING "PCI: cache line size of %d is not supported " - "by device %s\n", pci_cache_line_size << 2, dev->slot_name); + "by device %s\n", pci_cache_line_size << 2, pci_name(dev)); return -EINVAL; } @@ -653,7 +653,7 @@ pci_read_config_word(dev, PCI_COMMAND, &cmd); if (! (cmd & PCI_COMMAND_INVALIDATE)) { - DBG("PCI: Enabling Mem-Wr-Inval for device %s\n", dev->slot_name); + DBG("PCI: Enabling Mem-Wr-Inval for device %s\n", pci_name(dev)); cmd |= PCI_COMMAND_INVALIDATE; pci_write_config_word(dev, PCI_COMMAND, cmd); } diff -Nru a/drivers/pci/pci.ids b/drivers/pci/pci.ids --- a/drivers/pci/pci.ids Sun Jul 27 10:13:46 2003 +++ b/drivers/pci/pci.ids Sun Jul 27 10:13:46 2003 @@ -1855,6 +1855,7 @@ 8001 Schizo PCI Bus Module a000 Ultra IIi a001 Ultra IIe + a801 Tomatillo PCI Bus Module 108f Systemsoft 1090 Encore Computer Corporation 1091 Intergraph Corporation @@ -5831,6 +5832,7 @@ 1737 Linksys 173b Altima (nee Broadcom) 03e8 AC1000 Gigabit Ethernet + 03e9 AC1001 Gigabit Ethernet 03ea AC9100 Gigabit Ethernet 1743 Peppercon AG 8139 ROL/F-100 Fast Ethernet Adapter with ROL diff -Nru a/drivers/pci/pool.c b/drivers/pci/pool.c --- a/drivers/pci/pool.c Sun Jul 27 10:13:51 2003 +++ b/drivers/pci/pool.c Sun Jul 27 10:13:51 2003 @@ -233,7 +233,7 @@ struct pci_page, page_list); if (is_page_busy (pool->blocks_per_page, page->bitmap)) { printk (KERN_ERR "pci_pool_destroy %s/%s, %p busy\n", - pool->dev ? pool->dev->slot_name : NULL, + pool->dev ? pci_name(pool->dev) : NULL, pool->name, page->vaddr); /* leak the still-in-use consistent memory */ list_del (&page->page_list); @@ -359,7 +359,7 @@ if ((page = pool_find_page (pool, dma)) == 0) { printk (KERN_ERR "pci_pool_free %s/%s, %p/%lx (bad dma)\n", - pool->dev ? pool->dev->slot_name : NULL, + pool->dev ? pci_name(pool->dev) : NULL, pool->name, vaddr, (unsigned long) dma); return; } @@ -372,13 +372,13 @@ #ifdef CONFIG_DEBUG_SLAB if (((dma - page->dma) + (void *)page->vaddr) != vaddr) { printk (KERN_ERR "pci_pool_free %s/%s, %p (bad vaddr)/%Lx\n", - pool->dev ? pool->dev->slot_name : NULL, + pool->dev ? pci_name(pool->dev) : NULL, pool->name, vaddr, (unsigned long long) dma); return; } if (page->bitmap [map] & (1UL << block)) { printk (KERN_ERR "pci_pool_free %s/%s, dma %Lx already free\n", - pool->dev ? pool->dev->slot_name : NULL, + pool->dev ? pci_name(pool->dev) : NULL, pool->name, (unsigned long long)dma); return; } diff -Nru a/drivers/pci/quirks.c b/drivers/pci/quirks.c --- a/drivers/pci/quirks.c Sun Jul 27 10:13:40 2003 +++ b/drivers/pci/quirks.c Sun Jul 27 10:13:40 2003 @@ -33,7 +33,7 @@ while ((d = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0, d))) { pci_read_config_byte(d, 0x82, &dlc); if (!(dlc & 1<<1)) { - printk(KERN_ERR "PCI: PIIX3: Enabling Passive Release on %s\n", d->slot_name); + printk(KERN_ERR "PCI: PIIX3: Enabling Passive Release on %s\n", pci_name(d)); dlc |= 1<<1; pci_write_config_byte(d, 0x82, dlc); } @@ -437,7 +437,7 @@ if (new_irq != irq) { printk(KERN_INFO "PCI: Via IRQ fixup for %s, from %d to %d\n", - dev->slot_name, irq, new_irq); + pci_name(dev), irq, new_irq); udelay(15); pci_write_config_byte(dev, PCI_INTERRUPT_LINE, new_irq); @@ -598,7 +598,7 @@ return; printk(KERN_INFO "PCI: Ignoring BAR%d-%d of IDE controller %s\n", - first_bar, last_bar, dev->slot_name); + first_bar, last_bar, pci_name(dev)); } /* @@ -856,7 +856,7 @@ (f->vendor == dev->vendor || f->vendor == (u16) PCI_ANY_ID) && (f->device == dev->device || f->device == (u16) PCI_ANY_ID)) { #ifdef DEBUG - printk(KERN_INFO "PCI: Calling quirk %p for %s\n", f->hook, dev->slot_name); + printk(KERN_INFO "PCI: Calling quirk %p for %s\n", f->hook, pci_name(dev)); #endif f->hook(dev); } diff -Nru a/drivers/pci/remove.c b/drivers/pci/remove.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/pci/remove.c Sun Jul 27 10:13:53 2003 @@ -0,0 +1,113 @@ +#include +#include +#include "pci.h" + +#undef DEBUG + +#ifdef DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + +static void pci_free_resources(struct pci_dev *dev) +{ + int i; + + for (i = 0; i < PCI_NUM_RESOURCES; i++) { + struct resource *res = dev->resource + i; + if (res->parent) + release_resource(res); + } +} + +static void pci_destroy_dev(struct pci_dev *dev) +{ + pci_proc_detach_device(dev); + device_unregister(&dev->dev); + + /* Remove the device from the device lists, and prevent any further + * list accesses from this device */ + spin_lock(&pci_bus_lock); + list_del(&dev->bus_list); + list_del(&dev->global_list); + dev->bus_list.next = dev->bus_list.prev = NULL; + dev->global_list.next = dev->global_list.prev = NULL; + spin_unlock(&pci_bus_lock); + + pci_free_resources(dev); + pci_dev_put(dev); +} + +/** + * pci_remove_device_safe - remove an unused hotplug device + * @dev: the device to remove + * + * Delete the device structure from the device lists and + * notify userspace (/sbin/hotplug), but only if the device + * in question is not being used by a driver. + * Returns 0 on success. + */ +int pci_remove_device_safe(struct pci_dev *dev) +{ + if (pci_dev_driver(dev)) + return -EBUSY; + pci_destroy_dev(dev); + return 0; +} +EXPORT_SYMBOL(pci_remove_device_safe); + +/** + * pci_remove_bus_device - remove a PCI device and any children + * @dev: the device to remove + * + * Remove a PCI device from the device lists, informing the drivers + * that the device has been removed. We also remove any subordinate + * buses and children in a depth-first manner. + * + * For each device we remove, delete the device structure from the + * device lists, remove the /proc entry, and notify userspace + * (/sbin/hotplug). + */ +void pci_remove_bus_device(struct pci_dev *dev) +{ + if (dev->subordinate) { + struct pci_bus *b = dev->subordinate; + + pci_remove_behind_bridge(dev); + pci_proc_detach_bus(b); + + spin_lock(&pci_bus_lock); + list_del(&b->node); + spin_unlock(&pci_bus_lock); + + kfree(b); + dev->subordinate = NULL; + } + + pci_destroy_dev(dev); +} + +/** + * pci_remove_behind_bridge - remove all devices behind a PCI bridge + * @dev: PCI bridge device + * + * Remove all devices on the bus, except for the parent bridge. + * This also removes any child buses, and any devices they may + * contain in a depth-first manner. + */ +void pci_remove_behind_bridge(struct pci_dev *dev) +{ + struct list_head *l, *n; + + if (dev->subordinate) { + list_for_each_safe(l, n, &dev->subordinate->devices) { + struct pci_dev *dev = pci_dev_b(l); + + pci_remove_bus_device(dev); + } + } +} + +EXPORT_SYMBOL(pci_remove_bus_device); +EXPORT_SYMBOL(pci_remove_behind_bridge); diff -Nru a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c --- a/drivers/pci/setup-bus.c Sun Jul 27 10:13:52 2003 +++ b/drivers/pci/setup-bus.c Sun Jul 27 10:13:52 2003 @@ -81,7 +81,7 @@ struct pci_bus_region region; printk("PCI: Bus %d, cardbus bridge: %s\n", - bus->number, bridge->slot_name); + bus->number, pci_name(bridge)); pcibios_resource_to_bus(bridge, ®ion, bus->resource[0]); if (bus->resource[0]->flags & IORESOURCE_IO) { @@ -344,7 +344,7 @@ if (order > 11) { printk(KERN_WARNING "PCI: region %s/%d " "too large: %lx-%lx\n", - dev->slot_name, i, r->start, r->end); + pci_name(dev), i, r->start, r->end); r->flags = 0; continue; } @@ -513,7 +513,7 @@ default: printk(KERN_INFO "PCI: not setting up bridge %s " - "for bus %d\n", dev->slot_name, b->number); + "for bus %d\n", pci_name(dev), b->number); break; } } diff -Nru a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c --- a/drivers/pci/setup-res.c Sun Jul 27 10:13:50 2003 +++ b/drivers/pci/setup-res.c Sun Jul 27 10:13:50 2003 @@ -68,7 +68,7 @@ if ((new ^ check) & mask) { printk(KERN_ERR "PCI: Error while updating region " - "%s/%d (%08x != %08x)\n", dev->slot_name, resno, + "%s/%d (%08x != %08x)\n", pci_name(dev), resno, new, check); } @@ -80,7 +80,7 @@ if (check != new) { printk(KERN_ERR "PCI: Error updating region " "%s/%d (high %08x != %08x)\n", - dev->slot_name, resno, new, check); + pci_name(dev), resno, new, check); } } } @@ -101,7 +101,7 @@ printk(KERN_ERR "PCI: %s region %d of %s %s [%lx:%lx]\n", root ? "Address space collision on" : "No parent found for", - resource, dtype, dev->slot_name, res->start, res->end); + resource, dtype, pci_name(dev), res->start, res->end); } return err; @@ -139,7 +139,7 @@ if (ret) { printk(KERN_ERR "PCI: Failed to allocate resource %d(%lx-%lx) for %s\n", - resno, res->start, res->end, dev->slot_name); + resno, res->start, res->end, pci_name(dev)); } else if (resno < PCI_BRIDGE_RESOURCES) { pci_update_resource(dev, res, resno); } diff -Nru a/drivers/pcmcia/hd64465_ss.c b/drivers/pcmcia/hd64465_ss.c --- a/drivers/pcmcia/hd64465_ss.c Sun Jul 27 10:13:47 2003 +++ b/drivers/pcmcia/hd64465_ss.c Sun Jul 27 10:13:47 2003 @@ -1,5 +1,5 @@ /* - * $Id$ + * $Id: hd64465_ss.c,v 1.7 2003/07/06 14:42:50 lethal Exp $ * * Device driver for the PCMCIA controller module of the * Hitachi HD64465 handheld companion chip. @@ -24,7 +24,6 @@ * * by Greg Banks * (c) 2000 PocketPenguins Inc - * */ #include @@ -37,28 +36,26 @@ #include #include #include -#include +#include #include #include -#include +#include +#include #include #include #include +#include +#include #include #include -#include #include "cs_internal.h" #define MODNAME "hd64465_ss" /* #define HD64465_DEBUG 1 */ -#ifndef HD64465_DEBUG -#define HD64465_DEBUG 0 -#endif - #if HD64465_DEBUG #define DPRINTK(args...) printk(MODNAME ": " args) #else @@ -66,7 +63,8 @@ #endif extern int hd64465_io_debug; - +extern void * p3_ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags); +extern void p3_iounmap(void *addr); /*============================================================*/ @@ -74,37 +72,22 @@ typedef struct hs_socket_t { + unsigned int number; u_int irq; u_long mem_base; + void *io_base; u_long mem_length; - void (*handler)(void *info, u_int events); - void *handler_info; - u_int pending_events; u_int ctrl_base; socket_state_t state; pccard_io_map io_maps[MAX_IO_WIN]; pccard_mem_map mem_maps[MAX_WIN]; - struct vm_struct *io_vma; /* allocated kernel vm for mapping IO space */ + struct pcmcia_socket socket; } hs_socket_t; -#define HS_MAX_SOCKETS 2 -static hs_socket_t hs_sockets[HS_MAX_SOCKETS]; -static spinlock_t hs_pending_event_lock = SPIN_LOCK_UNLOCKED; -/* Calculate socket number from ptr into hs_sockets[] */ -#define hs_sockno(sp) (sp - hs_sockets) -static socket_cap_t hs_socket_cap = -{ - SS_CAP_PCCARD /* support 16 bit cards */ - |SS_CAP_STATIC_MAP /* mappings are fixed in host memory */ - , - 0xffde/*0xffff*/, /* IRQs mapped in s/w so can do any, really */ - HD64465_PCC_WINDOW, /* 16MB fixed window size */ - 0, /* no PCI support */ - 0, /* no CardBus support */ - 0 /* no bus operations needed */ -}; +#define HS_MAX_SOCKETS 2 +static hs_socket_t hs_sockets[HS_MAX_SOCKETS]; #define hs_in(sp, r) inb((sp)->ctrl_base + (r)) #define hs_out(sp, v, r) outb(v, (sp)->ctrl_base + (r)) @@ -179,7 +162,7 @@ { unsigned short cscier; - DPRINTK("hs_socket_enable_ireq(sock=%d)\n", hs_sockno(sp)); + DPRINTK("hs_socket_enable_ireq(sock=%d)\n", sp->number); cscier = hs_in(sp, CSCIER); cscier &= ~HD64465_PCCCSCIER_PIREQE_MASK; @@ -191,7 +174,7 @@ { unsigned short cscier; - DPRINTK("hs_socket_disable_ireq(sock=%d)\n", hs_sockno(sp)); + DPRINTK("hs_socket_disable_ireq(sock=%d)\n", sp->number); cscier = hs_in(sp, CSCIER); cscier &= ~HD64465_PCCCSCIER_PIREQE_MASK; @@ -255,7 +238,7 @@ */ static void hs_map_irq(hs_socket_t *sp, unsigned int irq) { - DPRINTK("hs_map_irq(sock=%d irq=%d)\n", hs_sockno(sp), irq); + DPRINTK("hs_map_irq(sock=%d irq=%d)\n", sp->number, irq); if (irq >= HS_NUM_MAPPED_IRQS) return; @@ -272,7 +255,7 @@ */ static void hs_unmap_irq(hs_socket_t *sp, unsigned int irq) { - DPRINTK("hs_unmap_irq(sock=%d irq=%d)\n", hs_sockno(sp), irq); + DPRINTK("hs_unmap_irq(sock=%d irq=%d)\n", sp->number, irq); if (irq >= HS_NUM_MAPPED_IRQS) return; @@ -301,7 +284,7 @@ { u_int psr; u_int vcci = 0; - u_int sock = hs_sockno(sp); + u_int sock = sp->number; DPRINTK("hs_set_voltage(%d, %d, %d)\n", sock, Vcc, Vpp); @@ -359,13 +342,12 @@ /*============================================================*/ -static int hs_init(unsigned int sock) +static int hs_init(struct pcmcia_socket *s) { - hs_socket_t *sp = &hs_sockets[sock]; + hs_socket_t *sp = container_of(s, struct hs_socket_t, socket); - DPRINTK("hs_init(%d)\n", sock); + DPRINTK("hs_init(%d)\n", sp->number); - sp->pending_events = 0; sp->state.Vcc = 0; sp->state.Vpp = 0; hs_set_voltages(sp, 0, 0); @@ -375,9 +357,12 @@ /*============================================================*/ -static int hs_suspend(unsigned int sock) +static int hs_suspend(struct pcmcia_socket *s) { - DPRINTK("hs_suspend(%d)\n", sock); +#ifdef HD64465_DEBUG + hs_socket_t *sp = container_of(s, struct hs_socket_t, socket); + DPRINTK("hs_suspend(%d)\n", sp->number); +#endif /* TODO */ @@ -386,32 +371,10 @@ /*============================================================*/ -static int hs_register_callback(unsigned int sock, - void (*handler)(void *, unsigned int), void * info) -{ - hs_socket_t *sp = &hs_sockets[sock]; - - DPRINTK("hs_register_callback(%d)\n", sock); - sp->handler = handler; - sp->handler_info = info; - return 0; -} - -/*============================================================*/ -static int hs_inquire_socket(unsigned int sock, socket_cap_t *cap) +static int hs_get_status(struct pcmcia_socket *s, u_int *value) { - DPRINTK("hs_inquire_socket(%d)\n", sock); - - *cap = hs_socket_cap; - return 0; -} - -/*============================================================*/ - -static int hs_get_status(unsigned int sock, u_int *value) -{ - hs_socket_t *sp = &hs_sockets[sock]; + hs_socket_t *sp = container_of(s, struct hs_socket_t, socket); unsigned int isr; u_int status = 0; @@ -473,9 +436,9 @@ /*============================================================*/ -static int hs_get_socket(unsigned int sock, socket_state_t *state) +static int hs_get_socket(struct pcmcia_socket *s, socket_state_t *state) { - hs_socket_t *sp = &hs_sockets[sock]; + hs_socket_t *sp = container_of(s, struct hs_socket_t, socket); DPRINTK("hs_get_socket(%d)\n", sock); @@ -485,9 +448,9 @@ /*============================================================*/ -static int hs_set_socket(unsigned int sock, socket_state_t *state) +static int hs_set_socket(struct pcmcia_socket *s, socket_state_t *state) { - hs_socket_t *sp = &hs_sockets[sock]; + hs_socket_t *sp = container_of(s, struct hs_socket_t, socket); u_long flags; u_int changed; unsigned short cscier; @@ -495,12 +458,12 @@ DPRINTK("hs_set_socket(sock=%d, flags=%x, csc_mask=%x, Vcc=%d, Vpp=%d, io_irq=%d)\n", sock, state->flags, state->csc_mask, state->Vcc, state->Vpp, state->io_irq); - save_and_cli(flags); /* Don't want interrupts happening here */ + local_irq_save(flags); /* Don't want interrupts happening here */ if (state->Vpp != sp->state.Vpp || state->Vcc != sp->state.Vcc) { if (!hs_set_voltages(sp, state->Vcc, state->Vpp)) { - restore_flags(flags); + local_irq_restore(flags); return -EINVAL; } } @@ -588,7 +551,7 @@ /* hd64465_io_debug = 0; */ sp->state = *state; - restore_flags(flags); + local_irq_restore(flags); #if HD64465_DEBUG > 10 if (state->flags & SS_OUTPUT_ENA) @@ -599,10 +562,11 @@ /*============================================================*/ -static int hs_set_io_map(unsigned int sock, struct pccard_io_map *io) +static int hs_set_io_map(struct pcmcia_socket *s, struct pccard_io_map *io) { - hs_socket_t *sp = &hs_sockets[sock]; + hs_socket_t *sp = container_of(s, struct hs_socket_t, socket); int map = io->map; + int sock = sp->number; struct pccard_io_map *sio; pgprot_t prot; @@ -639,10 +603,9 @@ printk(KERN_INFO MODNAME ": MAP_0WS unimplemented\n"); if (io->flags & MAP_ACTIVE) { - unsigned long pstart, psize, paddrbase, vaddrbase; + unsigned long pstart, psize, paddrbase; paddrbase = virt_to_phys((void*)(sp->mem_base + 2 * HD64465_PCC_WINDOW)); - vaddrbase = (unsigned long)sp->io_vma->addr; pstart = io->start & PAGE_MASK; psize = ((io->stop + PAGE_SIZE) & PAGE_MASK) - pstart; @@ -653,26 +616,17 @@ * page will be mapped. But the code allows for weird cards * that might want IO ports > 4K. */ - DPRINTK("remap_page_range(vaddr=0x%08lx, paddr=0x%08lx, size=0x%08lxx)\n", - vaddrbase + pstart, paddrbase + pstart, psize); -#error This does not work. Firstly remap_page_range() uses current->mm for -#error the address space, which is wrong for kernel mappings. remap_page_range -#error also does flush_{cache,tlb}_range() which ONLY works for user mappings. -#error Next, remap_page_range() now wants to take a vm_area_struct arg. - remap_page_range(vaddrbase + pstart, paddrbase + pstart, psize, prot); + sp->io_base = p3_ioremap(paddrbase + pstart, psize, pgprot_val(prot)); /* * Change the mapping used by inb() outb() etc */ - hd64465_port_map( - io->start, + hd64465_port_map(io->start, io->stop - io->start + 1, - vaddrbase + io->start,0); + (unsigned long)sp->io_base + io->start, 0); } else { - hd64465_port_unmap( - sio->start, - sio->stop - sio->start + 1); - /* TODO: remap_page_range() to mark pages not present ? */ + hd64465_port_unmap(sio->start, sio->stop - sio->start + 1); + p3_iounmap(sp->io_base); } *sio = *io; @@ -681,9 +635,9 @@ /*============================================================*/ -static int hs_set_mem_map(unsigned int sock, struct pccard_mem_map *mem) +static int hs_set_mem_map(struct pcmcia_socket *s, struct pccard_mem_map *mem) { - hs_socket_t *sp = &hs_sockets[sock]; + hs_socket_t *sp = container_of(s, struct hs_socket_t, socket); struct pccard_mem_map *smem; int map = mem->map; unsigned long paddr, size; @@ -722,13 +676,6 @@ /*============================================================*/ -static void hs_proc_setup(unsigned int sock, struct proc_dir_entry *base) -{ - DPRINTK("hs_proc_setup(%d)\n", sock); -} - -/*============================================================*/ - /* * This function is registered with the HD64465 glue code to do a * secondary demux step on the PCMCIA interrupts. It handles @@ -756,35 +703,9 @@ /* * Interrupt handling routine. - * - * This uses the schedule_work() technique to cause reportable events - * such as card insertion and removal to be handled in keventd's - * process context. */ - -static void hs_events_bh(void *dummy) -{ - hs_socket_t *sp; - u_int events; - int i; - - for (i=0; ipending_events; - sp->pending_events = 0; - spin_unlock_irq(&hs_pending_event_lock); - - if (sp->handler) - sp->handler(sp->handler_info, events); - } -} - -static DECLARE_WORK(hs_events_task, hs_events_bh, NULL); - -static void hs_interrupt(int irq, void *dev, struct pt_regs *regs) +static irqreturn_t hs_interrupt(int irq, void *dev, struct pt_regs *regs) { hs_socket_t *sp = (hs_socket_t *)dev; u_int events = 0; @@ -801,7 +722,7 @@ if ((hs_in(sp, ISR) & HD64465_PCCISR_PCD_MASK) != 0) { printk(KERN_NOTICE MODNAME ": socket %d, card not a supported card type or not inserted correctly\n", - hs_sockno(sp)); + sp->number); /* Don't do the rest unless a card is present */ cscr &= ~(HD64465_PCCCSCR_PCDC| HD64465_PCCCSCR_PRC| @@ -839,34 +760,22 @@ hs_out(sp, cscr, CSCR); - if (events) { - /* - * Arrange for events to be reported to the registered - * event handler function (from CardServices) in a process - * context (keventd) "soon". - */ - spin_lock(&hs_pending_event_lock); - sp->pending_events |= events; - spin_unlock(&hs_pending_event_lock); - - schedule_work(&hs_events_task); - } + if (events) + pcmcia_parse_events(&sp->socket, events); + + return IRQ_HANDLED; } /*============================================================*/ static struct pccard_operations hs_operations = { - .owner = THIS_MODULE, .init = hs_init, .suspend = hs_suspend, - .register_callback = hs_register_callback, - .inquire_socket = hs_inquire_socket, .get_status = hs_get_status, .get_socket = hs_get_socket, .set_socket = hs_set_socket, .set_io_map = hs_set_io_map, .set_mem_map = hs_set_mem_map, - .proc_setup = hs_proc_setup, }; static int hs_init_socket(hs_socket_t *sp, int irq, unsigned long mem_base, @@ -886,9 +795,6 @@ for (i=0 ; imem_maps[i].map = i; - if ((sp->io_vma = get_vm_area(HS_IO_MAP_SIZE, VM_IOREMAP)) == 0) - return -ENOMEM; - hd64465_register_irq_demux(sp->irq, hs_irq_demux, sp); if ((err = request_irq(sp->irq, hs_interrupt, SA_INTERRUPT, MODNAME, sp)) < 0) @@ -925,9 +831,8 @@ hs_reset_socket(sp, 1); - printk(KERN_INFO "HD64465 PCMCIA bridge socket %d at 0x%08lx irq %d io window %ldK@0x%08lx\n", - i, sp->mem_base, sp->irq, - sp->io_vma->size>>10, (unsigned long)sp->io_vma->addr); + printk(KERN_INFO "HD64465 PCMCIA bridge socket %d at 0x%08lx irq %d\n", + i, sp->mem_base, sp->irq); return 0; } @@ -935,7 +840,10 @@ static void hs_exit_socket(hs_socket_t *sp) { unsigned short cscier, gcr; + unsigned long flags; + local_irq_save(flags); + /* turn off interrupts in hardware */ cscier = hs_in(sp, CSCIER); cscier = (cscier & IER_MASK) | IER_OFF; @@ -955,19 +863,13 @@ free_irq(sp->irq, hs_interrupt); hd64465_unregister_irq_demux(sp->irq); } - if (sp->io_vma != 0) - vfree(sp->io_vma->addr); -} -static struct pcmcia_socket_class_data hd64465_data = { - .nsock = HS_MAX_SOCKETS, - .ops = &hs_operations, -}; + local_irq_restore(flags); +} static struct device_driver hd64465_driver = { .name = "hd64465-pcmcia", .bus = &platform_bus_type, - .devclass = &pcmcia_socket_class, .suspend = pcmcia_socket_dev_suspend, .resume = pcmcia_socket_dev_resume, }; @@ -996,7 +898,8 @@ } /* hd64465_io_debug = 1; */ - register_driver(&hd64465_driver); + if (driver_register(&hd64465_driver)) + return -EINVAL; /* Wake both sockets out of STANDBY mode */ /* TODO: wait 15ms */ @@ -1014,14 +917,22 @@ v |= HD64465_PCCCSCR_PSWSEL; outb(v, HD64465_REG_PCC0CSCR); - hs_set_voltages(&hs_sockets[0], 0, 0); - hs_set_voltages(&hs_sockets[1], 0, 0); - /* * Setup hs_sockets[] structures and request system resources. * TODO: on memory allocation failure, power down the socket * before quitting. */ + for (i=0; iprivate[3]) #define rl_config(socket) ((socket)->private[4]) +static void ricoh_zoom_video(struct pcmcia_socket *sock, int onoff) +{ + u8 reg; + struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket); + + reg = config_readb(socket, RL5C4XX_MISC_CONTROL); + if (onoff) + /* Zoom zoom, we will all go together, zoom zoom, zoom zoom */ + reg |= RL5C4XX_ZV_ENABLE; + else + reg &= ~RL5C4XX_ZV_ENABLE; + + config_writeb(socket, RL5C4XX_MISC_CONTROL, reg); +} + +static void ricoh_set_zv(struct pcmcia_socket *sock) +{ + struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket); + if(socket->dev->vendor == PCI_VENDOR_ID_RICOH) + { + switch(socket->dev->device) + { + /* There may be more .. */ + case PCI_DEVICE_ID_RICOH_RL5C478: + sock->zoom_video = ricoh_zoom_video; + break; + } + } +} + static int ricoh_init(struct pcmcia_socket *sock) { struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket); yenta_init(sock); + ricoh_set_zv(sock); config_writew(socket, RL5C4XX_MISC, rl_misc(socket)); config_writew(socket, RL5C4XX_16BIT_CTL, rl_ctl(socket)); diff -Nru a/drivers/pcmcia/ti113x.h b/drivers/pcmcia/ti113x.h --- a/drivers/pcmcia/ti113x.h Sun Jul 27 10:13:44 2003 +++ b/drivers/pcmcia/ti113x.h Sun Jul 27 10:13:44 2003 @@ -148,14 +148,96 @@ return 0; } +/* + * Zoom video control for TI122x/113x chips + */ + +static void ti_zoom_video(struct pcmcia_socket *sock, int onoff) +{ + u8 reg; + struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket); + + /* If we don't have a Zoom Video switch this is harmless, + we just tristate the unused (ZV) lines */ + reg = config_readb(socket, TI113X_CARD_CONTROL); + if (onoff) + /* Zoom zoom, we will all go together, zoom zoom, zoom zoom */ + reg |= TI113X_CCR_ZVENABLE; + else + reg &= ~TI113X_CCR_ZVENABLE; + config_writeb(socket, TI113X_CARD_CONTROL, reg); +} + +/* + * The 145x series can also use this. They have an additional + * ZV autodetect mode we don't use but don't actually need. + * FIXME: manual says its in func0 and func1 but disagrees with + * itself about this - do we need to force func0, if so we need + * to know a lot more about socket pairings in pcmcia_socket than + * we do now.. uggh. + */ + +static void ti1250_zoom_video(struct pcmcia_socket *sock, int onoff) +{ + struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket); + int shift = 0; + u8 reg; + + ti_zoom_video(sock, onoff); + + reg = config_readb(socket, 0x84); + reg |= (1<<7); /* ZV bus enable */ + + if(PCI_FUNC(socket->dev->devfn)==1) + shift = 1; + + if(onoff) + { + reg &= ~(1<<6); /* Clear select bit */ + reg |= shift<<6; /* Favour our socket */ + reg |= 1<dev->vendor == PCI_VENDOR_ID_TI) + { + switch(socket->dev->device) + { + /* There may be more .. */ + case PCI_DEVICE_ID_TI_1220: + case PCI_DEVICE_ID_TI_1221: + case PCI_DEVICE_ID_TI_1225: + sock->zoom_video = ti_zoom_video; + break; + case PCI_DEVICE_ID_TI_1250: + case PCI_DEVICE_ID_TI_1251A: + case PCI_DEVICE_ID_TI_1251B: + case PCI_DEVICE_ID_TI_1450: + sock->zoom_video = ti1250_zoom_video; + } + } +} static int ti_init(struct pcmcia_socket *sock) { struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket); yenta_init(sock); + ti_set_zv(sock); ti_intctl(socket); return 0; } + /* * Generic TI init - TI has an extension for the * INTCTL register that sets the PCI CSC interrupt. @@ -176,9 +258,6 @@ if (new != reg) exca_writeb(socket, I365_INTCTL, new); -#if 0 - /* THIS CAUSES HANGS! Disabled for now, do not know why */ - /* * If ISA interrupts don't work, then fall back to routing card * interrupts to the PCI interrupt of the socket. @@ -190,7 +269,7 @@ u8 irqmux, devctl; devctl = config_readb(socket, TI113X_DEVICE_CONTROL); - if (devctl & TI113X_DCR_IMODE_MASK != TI12XX_DCR_IMODE_ALL_SERIAL) { + if ((devctl & TI113X_DCR_IMODE_MASK) != TI12XX_DCR_IMODE_ALL_SERIAL) { printk (KERN_INFO "ti113x: Routing card interrupts to PCI\n"); devctl &= ~TI113X_DCR_IMODE_MASK; @@ -203,7 +282,6 @@ config_writeb(socket, TI113X_DEVICE_CONTROL, devctl); } } -#endif socket->socket.ops->init = ti_init; return 0; @@ -220,6 +298,7 @@ { struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket); yenta_init(sock); + ti_set_zv(sock); config_writel(socket, TI113X_SYSTEM_CONTROL, ti_sysctl(socket)); config_writeb(socket, TI113X_CARD_CONTROL, ti_cardctl(socket)); @@ -248,6 +327,7 @@ struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket); yenta_init(sock); ti113x_init(sock); + ti_set_zv(sock); ti_irqmux(socket) = config_readl(socket, TI122X_IRQMUX); ti_irqmux(socket) = (ti_irqmux(socket) & ~0x0f) | 0x02; /* route INTA */ if (!(ti_sysctl(socket) & TI122X_SCR_INTRTIE)) diff -Nru a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c --- a/drivers/pcmcia/yenta_socket.c Sun Jul 27 10:13:47 2003 +++ b/drivers/pcmcia/yenta_socket.c Sun Jul 27 10:13:47 2003 @@ -297,6 +297,8 @@ } exca_writeb(socket, I365_CSCINT, reg); exca_readb(socket, I365_CSC); + if(sock->zoom_video) + sock->zoom_video(sock, state->flags & SS_ZVCARD); } config_writew(socket, CB_BRIDGE_CONTROL, bridge); /* Socket event mask: get card insert/remove events.. */ diff -Nru a/drivers/pnp/isapnp/core.c b/drivers/pnp/isapnp/core.c --- a/drivers/pnp/isapnp/core.c Sun Jul 27 10:13:46 2003 +++ b/drivers/pnp/isapnp/core.c Sun Jul 27 10:13:46 2003 @@ -255,14 +255,22 @@ static int isapnp_next_rdp(void) { int rdp = isapnp_rdp; + static int old_rdp = 0; + + if(old_rdp) + { + release_region(old_rdp, 1); + old_rdp = 0; + } while (rdp <= 0x3ff) { /* * We cannot use NE2000 probe spaces for ISAPnP or we * will lock up machines. */ - if ((rdp < 0x280 || rdp > 0x380) && !check_region(rdp, 1)) + if ((rdp < 0x280 || rdp > 0x380) && request_region(rdp, 1, "ISAPnP")) { isapnp_rdp = rdp; + old_rdp = rdp; return 0; } rdp += RDP_STEP; diff -Nru a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c --- a/drivers/s390/block/dasd.c Sun Jul 27 10:13:45 2003 +++ b/drivers/s390/block/dasd.c Sun Jul 27 10:13:45 2003 @@ -16,7 +16,6 @@ #include #include #include -#include #include #include diff -Nru a/drivers/s390/block/dasd_genhd.c b/drivers/s390/block/dasd_genhd.c --- a/drivers/s390/block/dasd_genhd.c Sun Jul 27 10:13:50 2003 +++ b/drivers/s390/block/dasd_genhd.c Sun Jul 27 10:13:50 2003 @@ -9,7 +9,7 @@ * * Dealing with devices registered to multiple major numbers. * - * $Revision: 1.29 $ + * $Revision: 1.31 $ */ #include @@ -17,7 +17,6 @@ #include #include #include -#include #include @@ -200,7 +199,6 @@ dasd_destroy_partitions(struct dasd_device * device) { del_gendisk(device->gdp); - put_disk(device->gdp); } int diff -Nru a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c --- a/drivers/s390/block/dasd_ioctl.c Sun Jul 27 10:13:47 2003 +++ b/drivers/s390/block/dasd_ioctl.c Sun Jul 27 10:13:47 2003 @@ -14,7 +14,6 @@ #include #include #include -#include #include #include diff -Nru a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c --- a/drivers/s390/block/xpram.c Sun Jul 27 10:13:49 2003 +++ b/drivers/s390/block/xpram.c Sun Jul 27 10:13:49 2003 @@ -31,7 +31,6 @@ #include #include #include -#include #include #include /* HDIO_GETGEO */ #include diff -Nru a/drivers/s390/char/tape_block.c b/drivers/s390/char/tape_block.c --- a/drivers/s390/char/tape_block.c Sun Jul 27 10:13:49 2003 +++ b/drivers/s390/char/tape_block.c Sun Jul 27 10:13:49 2003 @@ -13,7 +13,6 @@ #include #include #include -#include #include #include diff -Nru a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c --- a/drivers/s390/cio/chsc.c Sun Jul 27 10:13:46 2003 +++ b/drivers/s390/cio/chsc.c Sun Jul 27 10:13:46 2003 @@ -1,7 +1,7 @@ /* * drivers/s390/cio/chsc.c * S/390 common I/O routines -- channel subsystem call - * $Revision: 1.73 $ + * $Revision: 1.74 $ * * Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH, * IBM Corporation @@ -206,6 +206,7 @@ if (!page) return -ENOMEM; + err = 0; for (irq = 0; irq <= highest_subchannel; irq++) { /* * retrieve information for each sch @@ -222,13 +223,14 @@ "not work\n", err); cio_chsc_err_msg = 1; } - return err; + goto out; } clear_page(page); } cio_chsc_desc_avail = 1; +out: free_page((unsigned long)page); - return 0; + return err; } __initcall(chsc_get_sch_descriptions); @@ -428,7 +430,7 @@ ret = css_probe_device(irq); if (ret == -ENXIO) /* We're through */ - return; + break; continue; } diff -Nru a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c --- a/drivers/s390/cio/cio.c Sun Jul 27 10:13:52 2003 +++ b/drivers/s390/cio/cio.c Sun Jul 27 10:13:52 2003 @@ -1,7 +1,7 @@ /* * drivers/s390/cio/cio.c * S/390 common I/O routines -- low level i/o calls - * $Revision: 1.98 $ + * $Revision: 1.100 $ * * Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH, * IBM Corporation @@ -16,10 +16,12 @@ #include #include #include +#include #include #include #include +#include #include "airq.h" #include "cio.h" @@ -442,6 +444,11 @@ if (sch->schib.pmcw.ena) break; } + if (ret == -EBUSY) { + struct irb irb; + if (tsch(sch->irq, &irb) != 0) + break; + } } sprintf (dbf_txt, "ret:%d", ret); CIO_TRACE_EVENT (2, dbf_txt); @@ -608,6 +615,7 @@ tpi_info = (struct tpi_info *) __LC_SUBCHANNEL_ID; irb = (struct irb *) __LC_IRB; do { + kstat_cpu(smp_processor_id()).irqs[IO_INTERRUPT]++; /* * Non I/O-subchannel thin interrupts are processed differently */ diff -Nru a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c --- a/drivers/s390/cio/device.c Sun Jul 27 10:13:49 2003 +++ b/drivers/s390/cio/device.c Sun Jul 27 10:13:49 2003 @@ -1,7 +1,7 @@ /* * drivers/s390/cio/device.c * bus driver for ccw devices - * $Revision: 1.58 $ + * $Revision: 1.60 $ * * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, * IBM Corporation @@ -434,6 +434,13 @@ return ret; } +void +ccw_device_unregister(void *data) +{ + device_unregister((struct device *)data); +} + + static void ccw_device_release(struct device *dev) { @@ -513,17 +520,11 @@ wake_up(&ccw_device_init_wq); } -static void +static int io_subchannel_recog(struct ccw_device *cdev, struct subchannel *sch) { int rc; - if (!get_device(&sch->dev)) { - if (cdev->dev.release) - cdev->dev.release(&cdev->dev); - return; - } - sch->dev.driver_data = cdev; sch->driver = &io_subchannel_driver; cdev->ccwlock = &sch->lock; @@ -540,9 +541,6 @@ snprintf (cdev->dev.bus_id, DEVICE_ID_SIZE, "0:%04x", sch->schib.pmcw.dev); - /* Do first half of device_register. */ - device_initialize(&cdev->dev); - /* Increase counter of devices currently in recognition. */ atomic_inc(&ccw_device_init_count); @@ -551,13 +549,10 @@ rc = ccw_device_recognition(cdev); spin_unlock_irq(cdev->ccwlock); if (rc) { - sch->dev.driver_data = 0; - put_device(&sch->dev); - if (cdev->dev.release) - cdev->dev.release(&cdev->dev); if (atomic_dec_and_test(&ccw_device_init_count)) wake_up(&ccw_device_init_wq); } + return rc; } static int @@ -565,6 +560,7 @@ { struct subchannel *sch; struct ccw_device *cdev; + int rc; sch = to_subchannel(pdev); if (sch->dev.driver_data) { @@ -573,8 +569,20 @@ * Register it and exit. This happens for all early * device, e.g. the console. */ - ccw_device_register(sch->dev.driver_data); + cdev = sch->dev.driver_data; + device_initialize(&cdev->dev); + ccw_device_register(cdev); subchannel_add_files(&sch->dev); + /* + * Check if the device is already online. If it is + * the reference count needs to be corrected + * (see ccw_device_online and css_init_done for the + * ugly details). + */ + if (cdev->private->state != DEV_STATE_NOT_OPER && + cdev->private->state != DEV_STATE_OFFLINE && + cdev->private->state != DEV_STATE_BOXED) + get_device(&cdev->dev); return 0; } cdev = kmalloc (sizeof(*cdev), GFP_KERNEL); @@ -592,7 +600,23 @@ .parent = pdev, .release = ccw_device_release, }; - io_subchannel_recog(cdev, to_subchannel(pdev)); + /* Do first half of device_register. */ + device_initialize(&cdev->dev); + + if (!get_device(&sch->dev)) { + if (cdev->dev.release) + cdev->dev.release(&cdev->dev); + return 0; + } + + rc = io_subchannel_recog(cdev, to_subchannel(pdev)); + if (rc) { + sch->dev.driver_data = 0; + put_device(&sch->dev); + if (cdev->dev.release) + cdev->dev.release(&cdev->dev); + } + return 0; } @@ -604,6 +628,8 @@ static int ccw_device_console_enable (struct ccw_device *cdev, struct subchannel *sch) { + int rc; + /* Initialize the ccw_device structure. */ cdev->dev = (struct device) { .parent = &sch->dev, @@ -613,7 +639,11 @@ .parent = &css_bus_device, .bus = &css_bus_type, }; - io_subchannel_recog(cdev, sch); + + rc = io_subchannel_recog(cdev, sch); + if (rc) + return rc; + /* Now wait for the async. recognition to come to an end. */ while (!dev_fsm_final_state(cdev)) wait_cons_dev(); diff -Nru a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h --- a/drivers/s390/cio/device.h Sun Jul 27 10:13:50 2003 +++ b/drivers/s390/cio/device.h Sun Jul 27 10:13:50 2003 @@ -65,6 +65,8 @@ void io_subchannel_recog_done(struct ccw_device *cdev); +void ccw_device_unregister(void *); + int ccw_device_recognition(struct ccw_device *); int ccw_device_online(struct ccw_device *); int ccw_device_offline(struct ccw_device *); diff -Nru a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c --- a/drivers/s390/cio/device_fsm.c Sun Jul 27 10:13:45 2003 +++ b/drivers/s390/cio/device_fsm.c Sun Jul 27 10:13:45 2003 @@ -188,7 +188,7 @@ wake_up(&cdev->private->wait_q); - if (state != DEV_STATE_ONLINE) + if (css_init_done && state != DEV_STATE_ONLINE) put_device (&cdev->dev); } @@ -293,7 +293,7 @@ if (cdev->private->state != DEV_STATE_OFFLINE) return -EINVAL; sch = to_subchannel(cdev->dev.parent); - if (!get_device(&cdev->dev)) + if (css_init_done && !get_device(&cdev->dev)) return -ENODEV; if (cio_enable_subchannel(sch, sch->schib.pmcw.isc) != 0) { /* Couldn't enable the subchannel for i/o. Sick device. */ @@ -384,7 +384,9 @@ ccw_device_offline_notoper(struct ccw_device *cdev, enum dev_event dev_event) { cdev->private->state = DEV_STATE_NOT_OPER; - device_unregister(&cdev->dev); + INIT_WORK(&cdev->private->kick_work, + ccw_device_unregister, (void *) &cdev->dev); + queue_work(ccw_device_work, &cdev->private->kick_work); wake_up(&cdev->private->wait_q); } @@ -403,8 +405,10 @@ // FIXME: not-oper indication to device driver ? ccw_device_call_handler(cdev); } + INIT_WORK(&cdev->private->kick_work, + ccw_device_unregister, (void *) &cdev->dev); + queue_work(ccw_device_work, &cdev->private->kick_work); wake_up(&cdev->private->wait_q); - device_unregister(&cdev->dev); } /* diff -Nru a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c --- a/drivers/s390/cio/qdio.c Sun Jul 27 10:13:47 2003 +++ b/drivers/s390/cio/qdio.c Sun Jul 27 10:13:47 2003 @@ -55,7 +55,7 @@ #include "ioasm.h" #include "chsc.h" -#define VERSION_QDIO_C "$Revision: 1.51 $" +#define VERSION_QDIO_C "$Revision: 1.55 $" /****************** MODULE PARAMETER VARIABLES ********************/ MODULE_AUTHOR("Utz Bacher "); @@ -1643,6 +1643,7 @@ default: BUG(); } + ccw_device_set_timeout(cdev, 0); wake_up(&cdev->private->wait_q); } @@ -1891,26 +1892,25 @@ result=-EIO; goto exit; } - /* 4: request block - * 2: general char - * 512: chsc char */ - if ((scsc_area->general_char[1] & 0x00800000) != 0x00800000) { + /* Check for bit 41. */ + if ((scsc_area->general_char[1] & 0x00400000) != 0x00400000) { QDIO_PRINT_WARN("Adapter interruption facility not " \ "installed.\n"); result=-ENOENT; goto exit; } - if ((scsc_area->chsc_char[2] & 0x00180000) != 0x00180000) { + /* Check for bits 107 and 108. */ + if ((scsc_area->chsc_char[3] & 0x00180000) != 0x00180000) { QDIO_PRINT_WARN("Set Chan Subsys. Char. & Fast-CHSCs " \ "not available.\n"); result=-ENOENT; goto exit; } - /* Check for hydra thin interrupts. */ + /* Check for hydra thin interrupts (bit 67). */ hydra_thinints = ((scsc_area->general_char[2] & 0x10000000) == 0x10000000); - sprintf(dbf_text,"hydra_ti%1x", hydra_thinints); + sprintf(dbf_text,"hydrati%1x", hydra_thinints); QDIO_DBF_TEXT0(0,setup,dbf_text); exit: free_page ((unsigned long) scsc_area); @@ -2413,8 +2413,10 @@ QDIO_DBF_TEXT0(0,setup,dbf_text); QDIO_DBF_TEXT0(0,trace,dbf_text); - if (qdio_establish_irq_check_for_errors(cdev, cstat, dstat)) + if (qdio_establish_irq_check_for_errors(cdev, cstat, dstat)) { + ccw_device_set_timeout(cdev, 0); return; + } irq_ptr = cdev->private->qdio_data; @@ -2439,7 +2441,7 @@ qdio_initialize_set_siga_flags_output(irq_ptr); qdio_set_state(irq_ptr,QDIO_IRQ_STATE_ESTABLISHED); - + ccw_device_set_timeout(cdev, 0); } int @@ -2698,6 +2700,8 @@ "returned %i, next try returned %i\n", irq_ptr->irq,result,result2); result=result2; + if (result) + ccw_device_set_timeout(cdev, 0); } spin_unlock_irqrestore(get_ccwdev_lock(cdev),saveflags); @@ -3000,7 +3004,6 @@ int buffer_length, int *eof, void *data) { int c=0; - int irq; /* we are always called with buffer_length=4k, so we all deliver on the first read */ @@ -3020,7 +3023,7 @@ perf_stats.siga_ins); _OUTP_IT("Number of SIGA out's issued : %u\n", perf_stats.siga_outs); - _OUTP_IT("Number of PCIs caught : %u\n", + _OUTP_IT("Number of PCIs caught : %u\n", perf_stats.pcis); _OUTP_IT("Number of adapter interrupts caught : %u\n", perf_stats.thinints); @@ -3037,27 +3040,6 @@ perf_stats.outbound_cnt); _OUTP_IT("\n"); - /* - * FIXME: Rather use driver_for_each_dev, if we had it. - * I know this loop destroys our layering, but at least gets the - * performance stats out... - */ - for (irq=0;irq <= highest_subchannel; irq++) { - struct qdio_irq *irq_ptr; - struct ccw_device *cdev; - - if (!ioinfo[irq]) - continue; - cdev = ioinfo[irq]->dev.driver_data; - if (!cdev) - continue; - irq_ptr = cdev->private->qdio_data; - if (!irq_ptr) - continue; - _OUTP_IT("Polling time on irq %4x " \ - ": %u\n", - irq_ptr->irq,irq_ptr->input_qs[0]->timing.threshold); - } return c; } diff -Nru a/drivers/s390/net/qeth.c b/drivers/s390/net/qeth.c --- a/drivers/s390/net/qeth.c Sun Jul 27 10:13:52 2003 +++ b/drivers/s390/net/qeth.c Sun Jul 27 10:13:52 2003 @@ -1,6 +1,6 @@ /* * - * linux/drivers/s390/net/qeth.c ($Revision: 1.118 $) + * linux/drivers/s390/net/qeth.c ($Revision: 1.126 $) * * Linux on zSeries OSA Express and HiperSockets support * @@ -165,7 +165,7 @@ "reserved for low memory situations"); /****************** MODULE STUFF **********************************/ -#define VERSION_QETH_C "$Revision: 1.118 $" +#define VERSION_QETH_C "$Revision: 1.126 $" static const char *version = "qeth S/390 OSA-Express driver (" VERSION_QETH_C "/" VERSION_QETH_H "/" VERSION_QETH_MPC_H QETH_VERSION_IPV6 QETH_VERSION_VLAN ")"; @@ -1156,7 +1156,7 @@ return skb; } -static struct sk_buff * +static inline struct sk_buff * qeth_get_next_skb(struct qeth_card *card, int *element_ptr, int *pos_in_el_ptr, void **hdr_ptr, struct qdio_buffer *buffer) @@ -1464,8 +1464,21 @@ skb->ip_summed = card->options.checksum_type; if (card->options.checksum_type == HW_CHECKSUMMING) { /* do we have a checksummed packet? */ - if (*(__u8 *) (hdr_ptr + 11) & QETH_EXT_HEADER_CSUM_TRANSP_REQ) { - /* skb->ip_summed is set already */ + + /* + * we only check for TCP/UDP checksums when the pseudo + * header was also checked successfully -- for the + * rest of the packets, it's not clear, whether the + * upper layer csum is alright. And they shouldn't + * occur too often anyway in real life + */ + + if ((*(__u8*)(hdr_ptr+11) & (QETH_EXT_HEADER_CSUM_HDR_REQ | + QETH_EXT_HEADER_CSUM_TRANSP_REQ)) == + (QETH_EXT_HEADER_CSUM_HDR_REQ | + QETH_EXT_HEADER_CSUM_TRANSP_REQ)) { +#if 0 + /* csum does not need to be set inbound anyway */ /* * vlan is not an issue here, it's still in @@ -1485,11 +1498,15 @@ (&skb->data[ip_len + QETH_TCP_CSUM_OFFSET]); } +#endif /* 0 */ + skb->ip_summed=CHECKSUM_UNNECESSARY; } else { /* make the stack check it */ skb->ip_summed = SW_CHECKSUMMING; } - } + } else + skb->ip_summed=card->options.checksum_type; + __qeth_rebuild_skb_vlan(card, skb, hdr_ptr); } @@ -1596,7 +1613,7 @@ #endif } -static __u8 +static inline __u8 __qeth_get_flags_v4(int multicast) { if (multicast == RTN_MULTICAST) @@ -1606,7 +1623,7 @@ return QETH_CAST_UNICAST; } -static __u8 +static inline __u8 __qeth_get_flags_v6(int multicast) { if (multicast == RTN_MULTICAST) @@ -1625,7 +1642,7 @@ QETH_HEADER_IPV6; } -static void +static inline void qeth_fill_header(struct qeth_hdr *hdr, struct sk_buff *skb, int version, int multicast) { @@ -1681,7 +1698,7 @@ __max(QETH_DBF_DATA_LEN, QETH_DBF_DATA_LEN)); } -static int inline +static inline int qeth_fill_buffer(struct qdio_buffer *buffer, char *dataptr, int length, int element) { @@ -1735,7 +1752,7 @@ return element; } -static void +static inline void qeth_flush_packed_packets(struct qeth_card *card, int queue, int under_int) { struct qdio_buffer *buffer; @@ -1900,7 +1917,7 @@ return ERROR_LINK_FAILURE; /* should never happen */ } -static void +static inline void qeth_free_buffer(struct qeth_card *card, int queue, int bufno, int qdio_error, int siga_error) { @@ -2013,7 +2030,7 @@ card->send_retries[queue][bufno] = 0; } -static void +static inline void qeth_free_all_skbs(struct qeth_card *card) { int q, b; @@ -2049,7 +2066,7 @@ } #ifdef QETH_VLAN -void +static inline void qeth_insert_ipv6_vlan_tag(struct sk_buff *__skb) { @@ -2088,7 +2105,7 @@ #endif } -static void +static inline void qeth_send_packet_fast(struct qeth_card *card, struct sk_buff *skb, struct net_device *dev, int queue, int version, int multicast) @@ -2183,7 +2200,7 @@ /* no checks, if all elements are used, as then we would not be here (at most 127 buffers are enqueued) */ -static void +static inline void qeth_send_packet_packed(struct qeth_card *card, struct sk_buff *skb, struct net_device *dev, int queue, int version, int multicast) @@ -2391,7 +2408,7 @@ } } -static int +static inline int qeth_do_send_packet(struct qeth_card *card, struct sk_buff *skb, struct net_device *dev) { @@ -2829,23 +2846,27 @@ if (!buffer) { if (atomic_read(&card->escape_softsetup)) - result = 0; + return 0; else - result = -1; - } else { - reply = (struct ipa_cmd *) PDU_ENCAPSULATION(buffer); - if ((update_cmd) && (reply)) - memcpy(cmd, reply, sizeof (struct ipa_cmd)); - result = reply->return_code; - - /* some special sausages: */ - if ((ipa_cmd == IPA_CMD_SETASSPARMS) && (result == 0)) { - result = reply->data.setassparms.return_code; - } - if ((ipa_cmd == IPA_CMD_SETADAPTERPARMS) && (result == 0)) { - result = reply->data.setadapterparms.return_code; - } + return -1; + } + reply = (struct ipa_cmd *) PDU_ENCAPSULATION(buffer); + if ((update_cmd) && (reply)) + memcpy(cmd, reply, sizeof (struct ipa_cmd)); + result = reply->return_code; + + /* some special sausages: */ + if ((ipa_cmd == IPA_CMD_SETASSPARMS) && (result == 0)) { + result = reply->data.setassparms.return_code; + if ((reply->data.setassparms.assist_no==IPA_INBOUND_CHECKSUM) && + (reply->data.setassparms.command_code == IPA_CMD_ASS_START)) + card->csum_enable_mask = + reply->data.setassparms.data.flags_32bit; + } + if ((ipa_cmd == IPA_CMD_SETADAPTERPARMS) && (result == 0)) { + result = reply->data.setadapterparms.return_code; } + return result; } @@ -5599,7 +5620,7 @@ } result=qeth_send_setassparms_simple_with_data (card,IPA_INBOUND_CHECKSUM, - IPA_CMD_ASS_ENABLE, IPA_CHECKSUM_ENABLE_MASK); + IPA_CMD_ASS_ENABLE, card->csum_enable_mask); if (result) { PRINT_WARN("Could not enable inbound " \ "checksumming on %s: 0x%x, " \ @@ -6881,6 +6902,14 @@ return level; /* hmmm... don't know what to do with that level. */ } +/* returns last four digits of bus_id */ +static inline __u16 +__raw_devno_from_bus_id(char *id) +{ + id += (strlen(id) - 4); + return (__u16) simple_strtoul(id, &id, 16); +} + static int qeth_idx_activate_read(struct qeth_card *card) { @@ -6905,7 +6934,7 @@ memcpy(QETH_IDX_ACT_FUNC_LEVEL(card->dma_stuff->sendbuf), &card->func_level, 2); - temp = _ccw_device_get_device_number(card->ddev); + temp = __raw_devno_from_bus_id(card->ddev->dev.bus_id); memcpy(QETH_IDX_ACT_QDIO_DEV_CUA(card->dma_stuff->sendbuf), &temp, 2); temp = (card->cula << 8) + card->unit_addr2; memcpy(QETH_IDX_ACT_QDIO_DEV_REALADDR(card->dma_stuff->sendbuf), @@ -7501,10 +7530,8 @@ for (; tmp && (!result); tmp = tmp->next) { if (atomic_read(&tmp->shutdown_phase)) continue; - if (dev == tmp->dev) { - result = QETH_VERIFY_IS_REAL_DEV; - } - result = __qeth_verify_dev_vlan(dev, tmp); + result = (dev == tmp->dev)? + QETH_VERIFY_IS_REAL_DEV:__qeth_verify_dev_vlan(dev, tmp); } read_unlock(&list_lock); return result; @@ -8547,6 +8574,8 @@ card->ip_mc_new_state.ipm6_ifa = NULL; #endif /* QETH_IPV6 */ + card->csum_enable_mask = IPA_CHECKSUM_DEFAULT_ENABLE_MASK; + /* setup net_device stuff */ card->dev->priv = card; @@ -9087,21 +9116,19 @@ /* FIXME: this is really a mess... */ #ifdef QETH_IPV6 - if (atomic_read(&card->rt4fld) && atomic_read(&card->rt6fld)) - strcpy(router_str, "no"); - else if (atomic_read(&card->rt4fld) - || atomic_read(&card->rt6fld)) - strcpy(router_str, "mix"); + if (atomic_read(&card->rt4fld) || atomic_read(&card->rt6fld)) + strcpy(router_str, "FLD"); #else/* QETH_IPV6 */ if (atomic_read(&card->rt4fld)) - strcpy(router_str, "no"); + strcpy(router_str, "FLD"); #endif /* QETH_IPV6 */ else if (((card->options.routing_type4 & ROUTER_MASK) == PRIMARY_ROUTER) #ifdef QETH_IPV6 && - ((card->options.routing_type6 & ROUTER_MASK) == - PRIMARY_ROUTER) + (((card->options.routing_type6 & ROUTER_MASK) == + PRIMARY_ROUTER) || + (!qeth_is_supported(IPA_IPv6))) #endif /* QETH_IPV6 */ ) { strcpy(router_str, "pri"); @@ -9110,8 +9137,9 @@ SECONDARY_ROUTER) #ifdef QETH_IPV6 && - ((card->options.routing_type6 & ROUTER_MASK) == - SECONDARY_ROUTER) + (((card->options.routing_type6 & ROUTER_MASK) == + SECONDARY_ROUTER) || + (!qeth_is_supported(IPA_IPv6))) #endif /* QETH_IPV6 */ ) { strcpy(router_str, "sec"); @@ -9120,8 +9148,9 @@ MULTICAST_ROUTER) #ifdef QETH_IPV6 && - ((card->options.routing_type6 & ROUTER_MASK) == - MULTICAST_ROUTER) + (((card->options.routing_type6 & ROUTER_MASK) == + MULTICAST_ROUTER) || + (!qeth_is_supported(IPA_IPv6))) #endif /* QETH_IPV6 */ ) { strcpy(router_str, "mc"); @@ -9130,8 +9159,9 @@ PRIMARY_CONNECTOR) #ifdef QETH_IPV6 && - ((card->options.routing_type6 & ROUTER_MASK) == - PRIMARY_CONNECTOR) + (((card->options.routing_type6 & ROUTER_MASK) == + PRIMARY_CONNECTOR) || + (!qeth_is_supported(IPA_IPv6))) #endif /* QETH_IPV6 */ ) { strcpy(router_str, "p.c"); @@ -9140,8 +9170,9 @@ SECONDARY_CONNECTOR) #ifdef QETH_IPV6 && - ((card->options.routing_type6 & ROUTER_MASK) == - SECONDARY_CONNECTOR) + (((card->options.routing_type6 & ROUTER_MASK) == + SECONDARY_CONNECTOR) || + (!qeth_is_supported(IPA_IPv6))) #endif /* QETH_IPV6 */ ) { strcpy(router_str, "s.c"); @@ -9150,8 +9181,9 @@ NO_ROUTER) #ifdef QETH_IPV6 && - ((card->options.routing_type6 & ROUTER_MASK) == - NO_ROUTER) + (((card->options.routing_type6 & ROUTER_MASK) == + NO_ROUTER) || + (!qeth_is_supported(IPA_IPv6))) #endif /* QETH_IPV6 */ ) { strcpy(router_str, "no"); @@ -10115,7 +10147,7 @@ return -EINVAL; if (atomic_read(&card->rt4fld)) - return sprintf(buf, "%s\n", "no"); + return sprintf(buf, "%s\n", "FLD"); switch (card->options.routing_type4 & ROUTER_MASK) { case PRIMARY_ROUTER: @@ -10202,7 +10234,10 @@ return -EINVAL; if (atomic_read(&card->rt6fld)) - return sprintf(buf, "%s\n", "no"); + return sprintf(buf, "%s\n", "FLD"); + + if (!qeth_is_supported(IPA_IPv6)) + return sprintf(buf, "%s\n", "n/a"); switch (card->options.routing_type6 & ROUTER_MASK) { case PRIMARY_ROUTER: @@ -11060,6 +11095,10 @@ qeth_remove_card_from_list(card); QETH_DBF_TEXT4(0, trace, "freecard"); + + memset(card->dev, 0, sizeof (struct net_device)); + card->dev->priv = card; + strncpy(card->dev->name, card->dev_name, IFNAMSIZ); ccw_device_set_offline(card->ddev); ccw_device_set_offline(card->wdev); diff -Nru a/drivers/s390/net/qeth.h b/drivers/s390/net/qeth.h --- a/drivers/s390/net/qeth.h Sun Jul 27 10:13:40 2003 +++ b/drivers/s390/net/qeth.h Sun Jul 27 10:13:40 2003 @@ -14,7 +14,7 @@ #define QETH_NAME " qeth" -#define VERSION_QETH_H "$Revision: 1.47 $" +#define VERSION_QETH_H "$Revision: 1.49 $" /******************** CONFIG STUFF ***********************/ //#define QETH_DBF_LIKE_HELL @@ -938,6 +938,8 @@ __u32 ipa6_enabled; __u32 adp_supported; + __u32 csum_enable_mask; + atomic_t startlan_attempts; atomic_t enable_routing_attempts4; atomic_t rt4fld; @@ -1021,7 +1023,7 @@ case QETH_MPC_LINK_TYPE_LANE_TR: /* fallthrough */ case QETH_MPC_LINK_TYPE_HSTR: - return ARPHRD_IEEE802; + return ARPHRD_IEEE802_TR; default: return ARPHRD_ETHER; } diff -Nru a/drivers/s390/net/qeth_mpc.h b/drivers/s390/net/qeth_mpc.h --- a/drivers/s390/net/qeth_mpc.h Sun Jul 27 10:13:45 2003 +++ b/drivers/s390/net/qeth_mpc.h Sun Jul 27 10:13:45 2003 @@ -10,7 +10,7 @@ #ifndef __QETH_MPC_H__ #define __QETH_MPC_H__ -#define VERSION_QETH_MPC_H "$Revision: 1.15 $" +#define VERSION_QETH_MPC_H "$Revision: 1.16 $" #define QETH_IPA_TIMEOUT (card->ipa_timeout) #define QETH_MPC_TIMEOUT 2000 @@ -188,7 +188,7 @@ #define IPA_CMD_ASS_ARP_QUERY_INFO 0x0104 #define IPA_CMD_ASS_ARP_QUERY_STATS 0x0204 -#define IPA_CHECKSUM_ENABLE_MASK 0x001a +#define IPA_CHECKSUM_DEFAULT_ENABLE_MASK 0x001a #define IPA_CMD_ASS_FILTER_SET_TYPES 0x0003 diff -Nru a/drivers/sbus/char/envctrl.c b/drivers/sbus/char/envctrl.c --- a/drivers/sbus/char/envctrl.c Sun Jul 27 10:13:41 2003 +++ b/drivers/sbus/char/envctrl.c Sun Jul 27 10:13:41 2003 @@ -14,6 +14,9 @@ * * EB - Added support for CP1500 Global Address and PS/Voltage monitoring. * Eric Brower + * + * DB - Audit every copy_to_user in envctrl_read. + * Daniele Bellucci */ #include @@ -571,7 +574,8 @@ data[0] = (unsigned char)(warning_temperature); ret = 1; - copy_to_user((unsigned char *)buf, data, ret); + if (copy_to_user((unsigned char *)buf, data, ret)) + ret = -EFAULT; break; case ENVCTRL_RD_SHUTDOWN_TEMPERATURE: @@ -580,14 +584,16 @@ data[0] = (unsigned char)(shutdown_temperature); ret = 1; - copy_to_user((unsigned char *)buf, data, ret); + if (copy_to_user((unsigned char *)buf, data, ret)) + ret = -EFAULT; break; case ENVCTRL_RD_MTHRBD_TEMPERATURE: if (!(pchild = envctrl_get_i2c_child(ENVCTRL_MTHRBDTEMP_MON))) return 0; ret = envctrl_read_noncpu_info(pchild, ENVCTRL_MTHRBDTEMP_MON, data); - copy_to_user((unsigned char *)buf, data, ret); + if (copy_to_user((unsigned char *)buf, data, ret)) + ret = -EFAULT; break; case ENVCTRL_RD_CPU_TEMPERATURE: @@ -596,7 +602,8 @@ ret = envctrl_read_cpu_info(read_cpu, pchild, ENVCTRL_CPUTEMP_MON, data); /* Reset cpu to the default cpu0. */ - copy_to_user((unsigned char *)buf, data, ret); + if (copy_to_user((unsigned char *)buf, data, ret)) + ret = -EFAULT; break; case ENVCTRL_RD_CPU_VOLTAGE: @@ -605,21 +612,24 @@ ret = envctrl_read_cpu_info(read_cpu, pchild, ENVCTRL_CPUVOLTAGE_MON, data); /* Reset cpu to the default cpu0. */ - copy_to_user((unsigned char *)buf, data, ret); + if (copy_to_user((unsigned char *)buf, data, ret)) + ret = -EFAULT; break; case ENVCTRL_RD_SCSI_TEMPERATURE: if (!(pchild = envctrl_get_i2c_child(ENVCTRL_SCSITEMP_MON))) return 0; ret = envctrl_read_noncpu_info(pchild, ENVCTRL_SCSITEMP_MON, data); - copy_to_user((unsigned char *)buf, data, ret); + if (copy_to_user((unsigned char *)buf, data, ret)) + ret = -EFAULT; break; case ENVCTRL_RD_ETHERNET_TEMPERATURE: if (!(pchild = envctrl_get_i2c_child(ENVCTRL_ETHERTEMP_MON))) return 0; ret = envctrl_read_noncpu_info(pchild, ENVCTRL_ETHERTEMP_MON, data); - copy_to_user((unsigned char *)buf, data, ret); + if (copy_to_user((unsigned char *)buf, data, ret)) + ret = -EFAULT; break; case ENVCTRL_RD_FAN_STATUS: @@ -627,7 +637,8 @@ return 0; data[0] = envctrl_i2c_read_8574(pchild->addr); ret = envctrl_i2c_fan_status(pchild,data[0], data); - copy_to_user((unsigned char *)buf, data, ret); + if (copy_to_user((unsigned char *)buf, data, ret)) + ret = -EFAULT; break; case ENVCTRL_RD_GLOBALADDRESS: @@ -635,7 +646,8 @@ return 0; data[0] = envctrl_i2c_read_8574(pchild->addr); ret = envctrl_i2c_globaladdr(pchild, data[0], data); - copy_to_user((unsigned char *)buf, data, ret); + if (copy_to_user((unsigned char *)buf, data, ret)) + ret = -EFAULT; break; case ENVCTRL_RD_VOLTAGE_STATUS: @@ -645,7 +657,8 @@ return 0; data[0] = envctrl_i2c_read_8574(pchild->addr); ret = envctrl_i2c_voltage_status(pchild, data[0], data); - copy_to_user((unsigned char *)buf, data, ret); + if (copy_to_user((unsigned char *)buf, data, ret)) + ret = -EFAULT; break; default: diff -Nru a/drivers/sbus/char/flash.c b/drivers/sbus/char/flash.c --- a/drivers/sbus/char/flash.c Sun Jul 27 10:13:46 2003 +++ b/drivers/sbus/char/flash.c Sun Jul 27 10:13:46 2003 @@ -162,10 +162,13 @@ { struct sbus_bus *sbus; struct sbus_dev *sdev = 0; +#ifdef CONFIG_PCI struct linux_ebus *ebus; struct linux_ebus_device *edev = 0; struct linux_prom_registers regs[2]; - int len, err, nregs; + int len, nregs; +#endif + int err; for_all_sbusdev(sdev, sbus) { if (!strcmp(sdev->prom_name, "flashprom")) { diff -Nru a/drivers/sbus/char/jsflash.c b/drivers/sbus/char/jsflash.c --- a/drivers/sbus/char/jsflash.c Sun Jul 27 10:13:45 2003 +++ b/drivers/sbus/char/jsflash.c Sun Jul 27 10:13:45 2003 @@ -38,12 +38,8 @@ #include #include -/* - * is controlled from the outside with these definitions. - */ #define MAJOR_NR JSFD_MAJOR -#include #include #include #include diff -Nru a/drivers/sbus/sbus.c b/drivers/sbus/sbus.c --- a/drivers/sbus/sbus.c Sun Jul 27 10:13:44 2003 +++ b/drivers/sbus/sbus.c Sun Jul 27 10:13:44 2003 @@ -334,7 +334,7 @@ nd = prom_searchsiblings(topnd, "sbus"); if(nd == 0) { #ifdef CONFIG_PCI - if (pci_find_device(PCI_ANY_ID, PCI_ANY_ID, NULL) == NULL) { + if (!pcic_present()) { prom_printf("Neither SBUS nor PCI found.\n"); prom_halt(); } else { diff -Nru a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c --- a/drivers/scsi/3w-xxxx.c Sun Jul 27 10:13:51 2003 +++ b/drivers/scsi/3w-xxxx.c Sun Jul 27 10:13:51 2003 @@ -187,7 +187,7 @@ #include #include #include -#include +#include #include #include #include diff -Nru a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c --- a/drivers/scsi/53c700.c Sun Jul 27 10:13:41 2003 +++ b/drivers/scsi/53c700.c Sun Jul 27 10:13:41 2003 @@ -131,7 +131,7 @@ #include #include #include -#include +#include #include #include @@ -172,7 +172,7 @@ STATIC int NCR_700_slave_configure(Scsi_Device *SDpnt); STATIC void NCR_700_slave_destroy(Scsi_Device *SDpnt); -static struct device_attribute **NCR_700_dev_attrs = NULL; +STATIC struct device_attribute *NCR_700_dev_attrs[]; static char *NCR_700_phase[] = { "", @@ -2027,25 +2027,12 @@ .show = NCR_700_show_active_tags, }; -STATIC int __init -NCR_700_init(void) -{ - scsi_sysfs_modify_sdev_attribute(&NCR_700_dev_attrs, - &NCR_700_queue_depth_attr); - scsi_sysfs_modify_sdev_attribute(&NCR_700_dev_attrs, - &NCR_700_active_tags_attr); - return 0; -} - -/* NULL exit routine to keep modutils happy */ -STATIC void __exit -NCR_700_exit(void) -{ -} +STATIC struct device_attribute *NCR_700_dev_attrs[] = { + &NCR_700_queue_depth_attr, + &NCR_700_active_tags_attr, + NULL, +}; EXPORT_SYMBOL(NCR_700_detect); EXPORT_SYMBOL(NCR_700_release); EXPORT_SYMBOL(NCR_700_intr); - -module_init(NCR_700_init); -module_exit(NCR_700_exit); diff -Nru a/drivers/scsi/53c7xx.c b/drivers/scsi/53c7xx.c --- a/drivers/scsi/53c7xx.c Sun Jul 27 10:13:52 2003 +++ b/drivers/scsi/53c7xx.c Sun Jul 27 10:13:52 2003 @@ -249,7 +249,7 @@ #include #include #include -#include +#include #include #include #include diff -Nru a/drivers/scsi/AM53C974.c b/drivers/scsi/AM53C974.c --- a/drivers/scsi/AM53C974.c Sun Jul 27 10:13:45 2003 +++ b/drivers/scsi/AM53C974.c Sun Jul 27 10:13:45 2003 @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include diff -Nru a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c --- a/drivers/scsi/BusLogic.c Sun Jul 27 10:13:52 2003 +++ b/drivers/scsi/BusLogic.c Sun Jul 27 10:13:52 2003 @@ -36,7 +36,6 @@ #include #include #include -#include #include #include #include diff -Nru a/drivers/scsi/NCR53C9x.c b/drivers/scsi/NCR53C9x.c --- a/drivers/scsi/NCR53C9x.c Sun Jul 27 10:13:42 2003 +++ b/drivers/scsi/NCR53C9x.c Sun Jul 27 10:13:42 2003 @@ -29,7 +29,7 @@ #include #include #include -#include +#include #include #include #include @@ -911,7 +911,7 @@ if (esp->dma_mmu_get_scsi_one) esp->dma_mmu_get_scsi_one(esp, sp); else - sp->SCp.have_data_in = (int) sp->SCp.ptr = + sp->SCp.ptr = (char *) virt_to_phys(sp->request_buffer); } else { sp->SCp.buffer = (struct scatterlist *) sp->buffer; diff -Nru a/drivers/scsi/NCR53c406a.c b/drivers/scsi/NCR53c406a.c --- a/drivers/scsi/NCR53c406a.c Sun Jul 27 10:13:45 2003 +++ b/drivers/scsi/NCR53c406a.c Sun Jul 27 10:13:45 2003 @@ -51,7 +51,7 @@ #include #include -#include +#include #include #include "scsi.h" #include "hosts.h" diff -Nru a/drivers/scsi/NCR_D700.c b/drivers/scsi/NCR_D700.c --- a/drivers/scsi/NCR_D700.c Sun Jul 27 10:13:41 2003 +++ b/drivers/scsi/NCR_D700.c Sun Jul 27 10:13:41 2003 @@ -218,7 +218,8 @@ goto irq_failed; } - scsi_add_host(host, p->dev); + scsi_add_host(host, p->dev); /* XXX handle failure */ + scsi_scan_host(host); p->hosts[siop] = host; hostdata->dev = p->dev; @@ -387,7 +388,6 @@ static void __exit NCR_D700_exit(void) { mca_unregister_driver(&NCR_D700_driver); - scsi_sysfs_release_attributes(&NCR_D700_driver_template); } module_init(NCR_D700_init); diff -Nru a/drivers/scsi/NCR_Q720.c b/drivers/scsi/NCR_Q720.c --- a/drivers/scsi/NCR_Q720.c Sun Jul 27 10:13:41 2003 +++ b/drivers/scsi/NCR_Q720.c Sun Jul 27 10:13:41 2003 @@ -85,6 +85,7 @@ __u8 scsr1 = readb(vaddr + NCR_Q720_SCSR_OFFSET + 1); __u8 differential = readb(vaddr + NCR_Q720_SCSR_OFFSET) & 0x20; __u8 version; + int error; scsi_id = scsr1 >> 4; /* enable burst length 16 (FIXME: should allow this) */ @@ -120,9 +121,12 @@ scsr1 &= ~0x01; writeb(scsr1, vaddr + NCR_Q720_SCSR_OFFSET + 1); - scsi_add_host(p->hosts[siop], p->dev); - - return 0; + error = scsi_add_host(p->hosts[siop], p->dev); + if (error) + ncr53c8xx_release(p->hosts[siop]); + else + scsi_scan_host(p->hosts[siop]); + return error; fail: return -ENODEV; @@ -347,7 +351,6 @@ NCR_Q720_exit(void) { mca_unregister_driver(&NCR_Q720_driver); - //scsi_sysfs_release_attributes(&NCR_Q720_driver_template); } module_init(NCR_Q720_init); diff -Nru a/drivers/scsi/a2091.c b/drivers/scsi/a2091.c --- a/drivers/scsi/a2091.c Sun Jul 27 10:13:46 2003 +++ b/drivers/scsi/a2091.c Sun Jul 27 10:13:46 2003 @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include #include @@ -43,9 +43,9 @@ continue; if (status & ISTR_INTS) { - spin_lock_irqsave(&instance->host_lock, flags); + spin_lock_irqsave(instance->host_lock, flags); wd33c93_intr (instance); - spin_unlock_irqrestore(&instance->host_lock, flags); + spin_unlock_irqrestore(instance->host_lock, flags); handled = 1; } } diff -Nru a/drivers/scsi/a3000.c b/drivers/scsi/a3000.c --- a/drivers/scsi/a3000.c Sun Jul 27 10:13:49 2003 +++ b/drivers/scsi/a3000.c Sun Jul 27 10:13:49 2003 @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include #include @@ -36,9 +36,9 @@ return IRQ_NONE; if (status & ISTR_INTS) { - spin_lock_irqsave(&a3000_host->host_lock, flags); + spin_lock_irqsave(a3000_host->host_lock, flags); wd33c93_intr (a3000_host); - spin_unlock_irqrestore(&a3000_host->host_lock, flags); + spin_unlock_irqrestore(a3000_host->host_lock, flags); return IRQ_HANDLED; } printk("Non-serviced A3000 SCSI-interrupt? ISTR = %02x\n", status); diff -Nru a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c --- a/drivers/scsi/aacraid/aachba.c Sun Jul 27 10:13:44 2003 +++ b/drivers/scsi/aacraid/aachba.c Sun Jul 27 10:13:44 2003 @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include "scsi.h" #include "hosts.h" diff -Nru a/drivers/scsi/aacraid/commctrl.c b/drivers/scsi/aacraid/commctrl.c --- a/drivers/scsi/aacraid/commctrl.c Sun Jul 27 10:13:44 2003 +++ b/drivers/scsi/aacraid/commctrl.c Sun Jul 27 10:13:44 2003 @@ -37,7 +37,7 @@ #include #include #include -#include +#include #include #include #include "scsi.h" diff -Nru a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c --- a/drivers/scsi/aacraid/comminit.c Sun Jul 27 10:13:40 2003 +++ b/drivers/scsi/aacraid/comminit.c Sun Jul 27 10:13:40 2003 @@ -37,7 +37,7 @@ #include #include #include -#include +#include #include #include #include diff -Nru a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c --- a/drivers/scsi/aacraid/commsup.c Sun Jul 27 10:13:49 2003 +++ b/drivers/scsi/aacraid/commsup.c Sun Jul 27 10:13:49 2003 @@ -41,7 +41,7 @@ #include #include #include -#include +#include #include "scsi.h" #include "hosts.h" diff -Nru a/drivers/scsi/aacraid/dpcsup.c b/drivers/scsi/aacraid/dpcsup.c --- a/drivers/scsi/aacraid/dpcsup.c Sun Jul 27 10:13:45 2003 +++ b/drivers/scsi/aacraid/dpcsup.c Sun Jul 27 10:13:45 2003 @@ -38,7 +38,7 @@ #include #include #include -#include +#include #include #include "scsi.h" #include "hosts.h" diff -Nru a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c --- a/drivers/scsi/aacraid/linit.c Sun Jul 27 10:13:44 2003 +++ b/drivers/scsi/aacraid/linit.c Sun Jul 27 10:13:44 2003 @@ -50,7 +50,7 @@ #include #include #include -#include +#include #include "scsi.h" #include "hosts.h" #include diff -Nru a/drivers/scsi/aacraid/rx.c b/drivers/scsi/aacraid/rx.c --- a/drivers/scsi/aacraid/rx.c Sun Jul 27 10:13:52 2003 +++ b/drivers/scsi/aacraid/rx.c Sun Jul 27 10:13:52 2003 @@ -36,7 +36,7 @@ #include #include #include -#include +#include #include #include #include diff -Nru a/drivers/scsi/aacraid/sa.c b/drivers/scsi/aacraid/sa.c --- a/drivers/scsi/aacraid/sa.c Sun Jul 27 10:13:47 2003 +++ b/drivers/scsi/aacraid/sa.c Sun Jul 27 10:13:47 2003 @@ -36,7 +36,7 @@ #include #include #include -#include +#include #include #include #include diff -Nru a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c --- a/drivers/scsi/advansys.c Sun Jul 27 10:13:43 2003 +++ b/drivers/scsi/advansys.c Sun Jul 27 10:13:43 2003 @@ -798,7 +798,7 @@ #include #include #include -#include +#include #include #include diff -Nru a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c --- a/drivers/scsi/aha152x.c Sun Jul 27 10:13:40 2003 +++ b/drivers/scsi/aha152x.c Sun Jul 27 10:13:40 2003 @@ -225,7 +225,7 @@ #include #include #include -#include +#include #include "scsi.h" #include "hosts.h" #include @@ -241,9 +241,7 @@ #include #include #include -#include #include -#include #include #include "scsi.h" @@ -941,7 +939,8 @@ struct Scsi_Host *shpnt = lookup_irq(irqno); if (!shpnt) { - printk(KERN_ERR "aha152x%d: catched software interrupt %d for unknown controller.\n", HOSTNO, irqno); + /* no point using HOSTNO here! */ + printk(KERN_ERR "aha152x: catched software interrupt %d for unknown controller.\n", irqno); return IRQ_NONE; } @@ -1049,6 +1048,10 @@ printk(KERN_INFO "aha152x%d: trying software interrupt, ", shost->host_no); + + /* need to have host registered before triggering any interrupt */ + aha152x_host[registered_count] = shost; + mb(); SETPORT(DMACNTRL0, SWINT|INTEN); mdelay(1000); free_irq(shost->irq, shost); @@ -1064,7 +1067,7 @@ printk(KERN_ERR "aha152x%d: IRQ %d possibly wrong. " "Please verify.\n", shost->host_no, shost->irq); - goto out_release_region; + goto out_unregister_host; } printk("ok.\n"); @@ -1077,12 +1080,12 @@ "aha152x", shost) < 0) { printk(KERN_ERR "aha152x%d: failed to reassign interrupt.\n", shost->host_no); - goto out_release_region; + goto out_unregister_host; } - - aha152x_host[registered_count] = shost; return shost; /* the pcmcia stub needs the return value; */ +out_unregister_host: + aha152x_host[registered_count] = NULL; out_release_region: release_region(shost->io_port, IO_RANGE); out_unregister: diff -Nru a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c --- a/drivers/scsi/aha1542.c Sun Jul 27 10:13:46 2003 +++ b/drivers/scsi/aha1542.c Sun Jul 27 10:13:46 2003 @@ -38,7 +38,7 @@ #include #include #include -#include +#include #include #include diff -Nru a/drivers/scsi/aha1542.h b/drivers/scsi/aha1542.h --- a/drivers/scsi/aha1542.h Sun Jul 27 10:13:49 2003 +++ b/drivers/scsi/aha1542.h Sun Jul 27 10:13:49 2003 @@ -130,7 +130,6 @@ }; static int aha1542_detect(Scsi_Host_Template *); -static int aha1542_command(Scsi_Cmnd *); static int aha1542_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); static int aha1542_abort(Scsi_Cmnd * SCpnt); static int aha1542_bus_reset(Scsi_Cmnd * SCpnt); diff -Nru a/drivers/scsi/aha1740.c b/drivers/scsi/aha1740.c --- a/drivers/scsi/aha1740.c Sun Jul 27 10:13:42 2003 +++ b/drivers/scsi/aha1740.c Sun Jul 27 10:13:42 2003 @@ -34,7 +34,7 @@ * are deemed to be part of the source code. */ -#include +#include #include #include #include @@ -375,7 +375,7 @@ #endif /* locate an available ecb */ - spin_lock_irqsave(&SCpnt->device->host->host_lock, flags); + spin_lock_irqsave(SCpnt->device->host->host_lock, flags); ecbno = host->last_ecb_used + 1; /* An optimization */ if (ecbno >= AHA1740_ECBS) ecbno = 0; @@ -394,7 +394,7 @@ doubles as reserved flag */ host->last_ecb_used = ecbno; - spin_unlock_irqrestore(&SCpnt->device->host->host_lock, flags); + spin_unlock_irqrestore(SCpnt->device->host->host_lock, flags); #ifdef DEBUG printk("Sending command (%d %x)...", ecbno, done); @@ -491,7 +491,7 @@ unsigned int base = SCpnt->device->host->io_port; DEB(printk("aha1740[%d] critical section\n",ecbno)); - spin_lock_irqsave(&SCpnt->device->host->host_lock, flags); + spin_lock_irqsave(SCpnt->device->host->host_lock, flags); for (loopcnt = 0; ; loopcnt++) { if (inb(G2STAT(base)) & G2STAT_MBXOUT) break; if (loopcnt == LOOPCNT_WARN) { @@ -511,7 +511,7 @@ panic("aha1740.c: attn wait failed!\n"); } outb(ATTN_START | (target & 7), ATTN(base)); /* Start it up */ - spin_unlock_irqrestore(&SCpnt->device->host->host_lock, flags); + spin_unlock_irqrestore(SCpnt->device->host->host_lock, flags); DEB(printk("aha1740[%d] request queued.\n",ecbno)); } else printk(KERN_ALERT "aha1740_queuecommand: done can't be NULL\n"); @@ -594,7 +594,7 @@ if (!request_region(slotbase, SLOTSIZE, "aha1740")) /* See if in use */ return -EBUSY; if (!aha1740_test_port(slotbase)) - goto err_release; + goto err_release_region; aha1740_getconfig(slotbase,&irq_level,&translation); if ((inb(G2STAT(slotbase)) & (G2STAT_MBXOUT|G2STAT_BUSY)) != G2STAT_MBXOUT) { @@ -609,7 +609,7 @@ shpnt = scsi_host_alloc(&aha1740_template, sizeof(struct aha1740_hostdata)); if(shpnt == NULL) - goto err_release; + goto err_release_region; shpnt->base = 0; shpnt->io_port = slotbase; @@ -625,21 +625,27 @@ if (!host->ecb_dma_addr) { printk (KERN_ERR "aha1740_probe: Couldn't map ECB, giving up\n"); scsi_unregister (shpnt); - goto err_release; + goto err_host_put; } DEB(printk("aha1740_probe: enable interrupt channel %d\n",irq_level)); if (request_irq(irq_level,aha1740_intr_handle,0,"aha1740",shpnt)) { printk(KERN_ERR "aha1740_probe: Unable to allocate IRQ %d.\n", irq_level); - goto err_release; + goto err_unmap; } eisa_set_drvdata (edev, shpnt); - scsi_add_host (shpnt, dev); + scsi_add_host (shpnt, dev); /* XXX handle failure */ + scsi_scan_host (shpnt); return 0; - err_release: + err_unmap: + dma_unmap_single (&edev->dev, host->ecb_dma_addr, + sizeof (host->ecb), DMA_BIDIRECTIONAL); + err_host_put: + scsi_host_put (shpnt); + err_release_region: release_region(slotbase, SLOTSIZE); return -ENODEV; diff -Nru a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c --- a/drivers/scsi/aic7xxx/aic79xx_osm.c Sun Jul 27 10:13:46 2003 +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c Sun Jul 27 10:13:46 2003 @@ -2173,7 +2173,8 @@ ahd_unlock(ahd, &s); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) - scsi_add_host(host, &ahd->dev_softc->dev); + scsi_add_host(host, &ahd->dev_softc->dev); /* XXX handle failure */ + scsi_scan_host(host); #endif return (0); } diff -Nru a/drivers/scsi/aic7xxx/aic79xx_osm.h b/drivers/scsi/aic7xxx/aic79xx_osm.h --- a/drivers/scsi/aic7xxx/aic79xx_osm.h Sun Jul 27 10:13:47 2003 +++ b/drivers/scsi/aic7xxx/aic79xx_osm.h Sun Jul 27 10:13:47 2003 @@ -43,7 +43,6 @@ #define _AIC79XX_LINUX_H_ #include -#include #include #include #include diff -Nru a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c --- a/drivers/scsi/aic7xxx/aic7xxx_osm.c Sun Jul 27 10:13:41 2003 +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c Sun Jul 27 10:13:41 2003 @@ -139,7 +139,7 @@ #endif #include /* For fetching system memory size */ -#include /* For block_size() */ +#include /* For block_size() */ /* * Lock protecting manipulation of the ahc softc list. @@ -1811,7 +1811,8 @@ ahc_unlock(ahc, &s); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) - scsi_add_host(host, (ahc->dev_softc ? &ahc->dev_softc->dev : NULL)); + scsi_add_host(host, (ahc->dev_softc ? &ahc->dev_softc->dev : NULL)); /* XXX handle failure */ + scsi_scan_host(host); #endif return (0); } diff -Nru a/drivers/scsi/aic7xxx/aic7xxx_osm.h b/drivers/scsi/aic7xxx/aic7xxx_osm.h --- a/drivers/scsi/aic7xxx/aic7xxx_osm.h Sun Jul 27 10:13:44 2003 +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.h Sun Jul 27 10:13:44 2003 @@ -60,7 +60,6 @@ #define _AIC7XXX_LINUX_H_ #include -#include #include #include #include diff -Nru a/drivers/scsi/aic7xxx/aiclib.c b/drivers/scsi/aic7xxx/aiclib.c --- a/drivers/scsi/aic7xxx/aiclib.c Sun Jul 27 10:13:46 2003 +++ b/drivers/scsi/aic7xxx/aiclib.c Sun Jul 27 10:13:46 2003 @@ -30,7 +30,6 @@ * $Id$ */ -#include #include #include #include diff -Nru a/drivers/scsi/aic7xxx_old.c b/drivers/scsi/aic7xxx_old.c --- a/drivers/scsi/aic7xxx_old.c Sun Jul 27 10:13:44 2003 +++ b/drivers/scsi/aic7xxx_old.c Sun Jul 27 10:13:44 2003 @@ -233,11 +233,10 @@ #include #include #include -#include +#include #include #include #include -#include #include #include "scsi.h" #include "hosts.h" diff -Nru a/drivers/scsi/amiga7xx.c b/drivers/scsi/amiga7xx.c --- a/drivers/scsi/amiga7xx.c Sun Jul 27 10:13:44 2003 +++ b/drivers/scsi/amiga7xx.c Sun Jul 27 10:13:44 2003 @@ -9,7 +9,7 @@ */ #include #include -#include +#include #include #include #include diff -Nru a/drivers/scsi/arm/acornscsi.c b/drivers/scsi/arm/acornscsi.c --- a/drivers/scsi/arm/acornscsi.c Sun Jul 27 10:13:46 2003 +++ b/drivers/scsi/arm/acornscsi.c Sun Jul 27 10:13:46 2003 @@ -138,7 +138,7 @@ #include #include #include -#include +#include #include #include #include @@ -3043,9 +3043,13 @@ acornscsi_resetcard(ashost); ret = scsi_add_host(host, &ec->dev); - if (ret == 0) - goto out; + if (ret) + goto err_7; + + scsi_scan_host(host); + goto out; + err_7: free_irq(host->irq, ashost); err_6: release_region(host->io_port, 2048); diff -Nru a/drivers/scsi/arm/arxescsi.c b/drivers/scsi/arm/arxescsi.c --- a/drivers/scsi/arm/arxescsi.c Sun Jul 27 10:13:46 2003 +++ b/drivers/scsi/arm/arxescsi.c Sun Jul 27 10:13:46 2003 @@ -19,7 +19,7 @@ * 22-10-2000 SH Updated for new registering scheme. */ #include -#include +#include #include #include #include diff -Nru a/drivers/scsi/arm/cumana_1.c b/drivers/scsi/arm/cumana_1.c --- a/drivers/scsi/arm/cumana_1.c Sun Jul 27 10:13:41 2003 +++ b/drivers/scsi/arm/cumana_1.c Sun Jul 27 10:13:41 2003 @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include @@ -297,9 +297,13 @@ printk("\n"); ret = scsi_add_host(host, &ec->dev); - if (ret == 0) - goto out; + if (ret) + goto out_free_irq; + + scsi_scan_host(host); + goto out; + out_free_irq: free_irq(host->irq, host); out_release: release_region(host->io_port, host->n_io_port); diff -Nru a/drivers/scsi/arm/cumana_2.c b/drivers/scsi/arm/cumana_2.c --- a/drivers/scsi/arm/cumana_2.c Sun Jul 27 10:13:49 2003 +++ b/drivers/scsi/arm/cumana_2.c Sun Jul 27 10:13:49 2003 @@ -17,7 +17,7 @@ * 02-04-2000 RMK 0.0.4 Updated for new error handling code. */ #include -#include +#include #include #include #include diff -Nru a/drivers/scsi/arm/ecoscsi.c b/drivers/scsi/arm/ecoscsi.c --- a/drivers/scsi/arm/ecoscsi.c Sun Jul 27 10:13:52 2003 +++ b/drivers/scsi/arm/ecoscsi.c Sun Jul 27 10:13:52 2003 @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include @@ -205,7 +205,8 @@ NCR5380_print_options(host); printk("\n"); - scsi_add_host(host, NULL); + scsi_add_host(host, NULL); /* XXX handle failure */ + scsi_scan_host(host); return 0; release_reg: diff -Nru a/drivers/scsi/arm/eesox.c b/drivers/scsi/arm/eesox.c --- a/drivers/scsi/arm/eesox.c Sun Jul 27 10:13:52 2003 +++ b/drivers/scsi/arm/eesox.c Sun Jul 27 10:13:52 2003 @@ -23,7 +23,7 @@ * error handling code. */ #include -#include +#include #include #include #include diff -Nru a/drivers/scsi/arm/fas216.c b/drivers/scsi/arm/fas216.c --- a/drivers/scsi/arm/fas216.c Sun Jul 27 10:13:44 2003 +++ b/drivers/scsi/arm/fas216.c Sun Jul 27 10:13:44 2003 @@ -35,7 +35,7 @@ * condition status from targets. */ #include -#include +#include #include #include #include @@ -2861,6 +2861,8 @@ ret = scsi_add_host(host, dev); if (ret) fas216_writeb(info, REG_CMD, CMD_RESETCHIP); + else + scsi_scan_host(host); return ret; } diff -Nru a/drivers/scsi/arm/oak.c b/drivers/scsi/arm/oak.c --- a/drivers/scsi/arm/oak.c Sun Jul 27 10:13:39 2003 +++ b/drivers/scsi/arm/oak.c Sun Jul 27 10:13:39 2003 @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include @@ -158,9 +158,13 @@ printk("\n"); ret = scsi_add_host(host, &ec->dev); - if (ret == 0) - goto out; + if (ret) + goto out_release; + + scsi_scan_host(host); + goto out; + out_release: release_region(host->io_port, host->n_io_port); unreg: scsi_host_put(host); diff -Nru a/drivers/scsi/arm/powertec.c b/drivers/scsi/arm/powertec.c --- a/drivers/scsi/arm/powertec.c Sun Jul 27 10:13:48 2003 +++ b/drivers/scsi/arm/powertec.c Sun Jul 27 10:13:48 2003 @@ -8,7 +8,7 @@ * published by the Free Software Foundation. */ #include -#include +#include #include #include #include diff -Nru a/drivers/scsi/arm/queue.c b/drivers/scsi/arm/queue.c --- a/drivers/scsi/arm/queue.c Sun Jul 27 10:13:41 2003 +++ b/drivers/scsi/arm/queue.c Sun Jul 27 10:13:41 2003 @@ -15,7 +15,7 @@ * 30-Aug-2000 RMK Use Linux list handling and spinlocks */ #include -#include +#include #include #include #include diff -Nru a/drivers/scsi/atari_scsi.c b/drivers/scsi/atari_scsi.c --- a/drivers/scsi/atari_scsi.c Sun Jul 27 10:13:52 2003 +++ b/drivers/scsi/atari_scsi.c Sun Jul 27 10:13:52 2003 @@ -86,7 +86,7 @@ #include #include #include -#include +#include #include #include #include diff -Nru a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c --- a/drivers/scsi/atp870u.c Sun Jul 27 10:13:44 2003 +++ b/drivers/scsi/atp870u.c Sun Jul 27 10:13:44 2003 @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include diff -Nru a/drivers/scsi/blz1230.c b/drivers/scsi/blz1230.c --- a/drivers/scsi/blz1230.c Sun Jul 27 10:13:48 2003 +++ b/drivers/scsi/blz1230.c Sun Jul 27 10:13:48 2003 @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include #include diff -Nru a/drivers/scsi/blz2060.c b/drivers/scsi/blz2060.c --- a/drivers/scsi/blz2060.c Sun Jul 27 10:13:45 2003 +++ b/drivers/scsi/blz2060.c Sun Jul 27 10:13:45 2003 @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include #include diff -Nru a/drivers/scsi/bvme6000.c b/drivers/scsi/bvme6000.c --- a/drivers/scsi/bvme6000.c Sun Jul 27 10:13:41 2003 +++ b/drivers/scsi/bvme6000.c Sun Jul 27 10:13:41 2003 @@ -5,7 +5,7 @@ */ #include #include -#include +#include #include #include #include diff -Nru a/drivers/scsi/constants.c b/drivers/scsi/constants.c --- a/drivers/scsi/constants.c Sun Jul 27 10:13:49 2003 +++ b/drivers/scsi/constants.c Sun Jul 27 10:13:49 2003 @@ -9,7 +9,7 @@ #include #include -#include +#include #include #include "scsi.h" #include "hosts.h" diff -Nru a/drivers/scsi/cpqfcTScontrol.c b/drivers/scsi/cpqfcTScontrol.c --- a/drivers/scsi/cpqfcTScontrol.c Sun Jul 27 10:13:41 2003 +++ b/drivers/scsi/cpqfcTScontrol.c Sun Jul 27 10:13:41 2003 @@ -30,7 +30,7 @@ #define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s)) -#include +#include #include #include #include // request_region() prototype diff -Nru a/drivers/scsi/cpqfcTSinit.c b/drivers/scsi/cpqfcTSinit.c --- a/drivers/scsi/cpqfcTSinit.c Sun Jul 27 10:13:40 2003 +++ b/drivers/scsi/cpqfcTSinit.c Sun Jul 27 10:13:40 2003 @@ -35,7 +35,7 @@ #include #include #include -#include +#include #include #include #include diff -Nru a/drivers/scsi/cpqfcTSworker.c b/drivers/scsi/cpqfcTSworker.c --- a/drivers/scsi/cpqfcTSworker.c Sun Jul 27 10:13:50 2003 +++ b/drivers/scsi/cpqfcTSworker.c Sun Jul 27 10:13:50 2003 @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include #include diff -Nru a/drivers/scsi/cyberstorm.c b/drivers/scsi/cyberstorm.c --- a/drivers/scsi/cyberstorm.c Sun Jul 27 10:13:50 2003 +++ b/drivers/scsi/cyberstorm.c Sun Jul 27 10:13:50 2003 @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include #include diff -Nru a/drivers/scsi/cyberstormII.c b/drivers/scsi/cyberstormII.c --- a/drivers/scsi/cyberstormII.c Sun Jul 27 10:13:50 2003 +++ b/drivers/scsi/cyberstormII.c Sun Jul 27 10:13:50 2003 @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include #include diff -Nru a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c --- a/drivers/scsi/dc395x.c Sun Jul 27 10:13:41 2003 +++ b/drivers/scsi/dc395x.c Sun Jul 27 10:13:41 2003 @@ -50,7 +50,7 @@ #include #include #include -#include +#include #include #include "scsi.h" #include "hosts.h" @@ -6214,7 +6214,8 @@ pci_set_drvdata(pdev, scsi_host); /* get the scsi mid level to scan for new devices on the bus */ - scsi_add_host(scsi_host, &pdev->dev); + scsi_add_host(scsi_host, &pdev->dev); /* XXX handle failure */ + scsi_scan_host(scsi_host); return 0; } diff -Nru a/drivers/scsi/dec_esp.c b/drivers/scsi/dec_esp.c --- a/drivers/scsi/dec_esp.c Sun Jul 27 10:13:49 2003 +++ b/drivers/scsi/dec_esp.c Sun Jul 27 10:13:49 2003 @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include @@ -348,7 +348,7 @@ static void dma_drain(struct NCR_ESP *esp) { unsigned long nw = *scsi_scr; - unsigned short *p = KSEG1ADDR((unsigned short *) ((*scsi_dma_ptr) >> 3)); + unsigned short *p = (unsigned short *)KSEG1ADDR((*scsi_dma_ptr) >> 3); /* * Is there something in the dma buffers left? @@ -478,8 +478,7 @@ */ static void dma_mmu_get_scsi_one(struct NCR_ESP *esp, Scsi_Cmnd * sp) { - sp->SCp.have_data_in = PHYSADDR(sp->SCp.buffer); - sp->SCp.ptr = (char *) ((unsigned long) sp->SCp.have_data_in); + sp->SCp.ptr = (char *)PHYSADDR(sp->SCp.buffer); } static void dma_mmu_get_scsi_sgl(struct NCR_ESP *esp, Scsi_Cmnd * sp) @@ -523,8 +522,8 @@ { volatile int *dmareg = (volatile int *) ( esp->slot + DEC_SCSI_DMAREG ); - memcpy((void *) (esp->slot + DEC_SCSI_SRAM + ESP_TGT_DMA_SIZE), - KSEG0ADDR((void *) vaddress), length); + memcpy((void *)(esp->slot + DEC_SCSI_SRAM + ESP_TGT_DMA_SIZE), + (void *)KSEG0ADDR(vaddress), length); *dmareg = TC_ESP_DMAR_WRITE | TC_ESP_DMA_ADDR(esp->slot + DEC_SCSI_SRAM + ESP_TGT_DMA_SIZE); @@ -554,7 +553,5 @@ static void pmaz_dma_mmu_get_scsi_one(struct NCR_ESP *esp, Scsi_Cmnd * sp) { - sp->SCp.have_data_in = (int) sp->SCp.ptr = - (char *) KSEG0ADDR((sp->request_buffer)); + sp->SCp.ptr = (char *)KSEG0ADDR((sp->request_buffer)); } - diff -Nru a/drivers/scsi/dmx3191d.c b/drivers/scsi/dmx3191d.c --- a/drivers/scsi/dmx3191d.c Sun Jul 27 10:13:47 2003 +++ b/drivers/scsi/dmx3191d.c Sun Jul 27 10:13:47 2003 @@ -22,7 +22,7 @@ #include #include -#include +#include #include #include #include diff -Nru a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c --- a/drivers/scsi/dpt_i2o.c Sun Jul 27 10:13:50 2003 +++ b/drivers/scsi/dpt_i2o.c Sun Jul 27 10:13:50 2003 @@ -47,7 +47,7 @@ #include /* for CONFIG_PCI */ #include /* for PCI support */ #include -#include +#include #include /* for udelay */ #include #include /* for printk */ diff -Nru a/drivers/scsi/dtc.c b/drivers/scsi/dtc.c --- a/drivers/scsi/dtc.c Sun Jul 27 10:13:49 2003 +++ b/drivers/scsi/dtc.c Sun Jul 27 10:13:49 2003 @@ -76,7 +76,7 @@ #include #include #include -#include +#include #include #include #include diff -Nru a/drivers/scsi/eata.c b/drivers/scsi/eata.c --- a/drivers/scsi/eata.c Sun Jul 27 10:13:50 2003 +++ b/drivers/scsi/eata.c Sun Jul 27 10:13:50 2003 @@ -486,7 +486,7 @@ #include #include #include -#include +#include #include #include #include diff -Nru a/drivers/scsi/eata_pio.c b/drivers/scsi/eata_pio.c --- a/drivers/scsi/eata_pio.c Sun Jul 27 10:13:48 2003 +++ b/drivers/scsi/eata_pio.c Sun Jul 27 10:13:48 2003 @@ -58,7 +58,7 @@ #include #include #include -#include +#include #include #include diff -Nru a/drivers/scsi/esp.c b/drivers/scsi/esp.c --- a/drivers/scsi/esp.c Sun Jul 27 10:13:52 2003 +++ b/drivers/scsi/esp.c Sun Jul 27 10:13:52 2003 @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include #include diff -Nru a/drivers/scsi/fastlane.c b/drivers/scsi/fastlane.c --- a/drivers/scsi/fastlane.c Sun Jul 27 10:13:44 2003 +++ b/drivers/scsi/fastlane.c Sun Jul 27 10:13:44 2003 @@ -30,7 +30,7 @@ #include #include #include -#include +#include #include #include #include diff -Nru a/drivers/scsi/fcal.c b/drivers/scsi/fcal.c --- a/drivers/scsi/fcal.c Sun Jul 27 10:13:40 2003 +++ b/drivers/scsi/fcal.c Sun Jul 27 10:13:40 2003 @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include #include diff -Nru a/drivers/scsi/fd_mcs.c b/drivers/scsi/fd_mcs.c --- a/drivers/scsi/fd_mcs.c Sun Jul 27 10:13:44 2003 +++ b/drivers/scsi/fd_mcs.c Sun Jul 27 10:13:44 2003 @@ -79,7 +79,7 @@ #include #include -#include +#include #include #include #include diff -Nru a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c --- a/drivers/scsi/fdomain.c Sun Jul 27 10:13:49 2003 +++ b/drivers/scsi/fdomain.c Sun Jul 27 10:13:49 2003 @@ -270,7 +270,7 @@ #include #include #include -#include +#include #include #include #include diff -Nru a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c --- a/drivers/scsi/g_NCR5380.c Sun Jul 27 10:13:42 2003 +++ b/drivers/scsi/g_NCR5380.c Sun Jul 27 10:13:42 2003 @@ -105,7 +105,7 @@ #include #include #include -#include +#include #include "scsi.h" #include "hosts.h" #include "g_NCR5380.h" diff -Nru a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c --- a/drivers/scsi/gdth.c Sun Jul 27 10:13:47 2003 +++ b/drivers/scsi/gdth.c Sun Jul 27 10:13:47 2003 @@ -357,11 +357,8 @@ #include #endif -#if LINUX_VERSION_CODE >= 0x010300 -#include -#else -#include "../block/blk.h" -#endif +#include + #include "scsi.h" #include "hosts.h" #if LINUX_VERSION_CODE < 0x020503 diff -Nru a/drivers/scsi/gvp11.c b/drivers/scsi/gvp11.c --- a/drivers/scsi/gvp11.c Sun Jul 27 10:13:51 2003 +++ b/drivers/scsi/gvp11.c Sun Jul 27 10:13:51 2003 @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include #include @@ -42,9 +42,9 @@ if (!(status & GVP11_DMAC_INT_PENDING)) continue; - spin_lock_irqsave(&instance->host_lock, flags); + spin_lock_irqsave(instance->host_lock, flags); wd33c93_intr (instance); - spin_unlock_irqrestore(&instance->host_lock, flags); + spin_unlock_irqrestore(instance->host_lock, flags); handled = 1; } return IRQ_RETVAL(handled); diff -Nru a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c --- a/drivers/scsi/hosts.c Sun Jul 27 10:13:40 2003 +++ b/drivers/scsi/hosts.c Sun Jul 27 10:13:40 2003 @@ -81,19 +81,15 @@ printk(KERN_INFO "scsi%d : %s\n", shost->host_no, sht->info ? sht->info(shost) : sht->name); - error = scsi_sysfs_add_host(shost, dev); - if (!shost->can_queue) { printk(KERN_ERR "%s: can_queue = 0 no longer supported\n", sht->name); error = -EINVAL; } - if (!error) { + error = scsi_sysfs_add_host(shost, dev); + if (!error) scsi_proc_host_add(shost); - scsi_scan_host(shost); - } - return error; } @@ -151,12 +147,6 @@ dump_stack(); } - /* if its not set in the template, use the default */ - if (!sht->shost_attrs) - sht->shost_attrs = scsi_sysfs_shost_attrs; - if (!sht->sdev_attrs) - sht->sdev_attrs = scsi_sysfs_sdev_attrs; - shost = kmalloc(sizeof(struct Scsi_Host) + privsize, gfp_mask); if (!shost) return NULL; @@ -283,8 +273,8 @@ **/ void scsi_host_get(struct Scsi_Host *shost) { - get_device(&shost->host_gendev); - class_device_get(&shost->class_dev); + get_device(&shost->shost_gendev); + class_device_get(&shost->shost_classdev); } /** @@ -293,6 +283,6 @@ **/ void scsi_host_put(struct Scsi_Host *shost) { - class_device_put(&shost->class_dev); - put_device(&shost->host_gendev); + class_device_put(&shost->shost_classdev); + put_device(&shost->shost_gendev); } diff -Nru a/drivers/scsi/i91uscsi.c b/drivers/scsi/i91uscsi.c --- a/drivers/scsi/i91uscsi.c Sun Jul 27 10:13:42 2003 +++ b/drivers/scsi/i91uscsi.c Sun Jul 27 10:13:42 2003 @@ -81,7 +81,7 @@ #include #include -#include +#include #include #include "i91uscsi.h" diff -Nru a/drivers/scsi/ibmmca.c b/drivers/scsi/ibmmca.c --- a/drivers/scsi/ibmmca.c Sun Jul 27 10:13:41 2003 +++ b/drivers/scsi/ibmmca.c Sun Jul 27 10:13:41 2003 @@ -32,7 +32,7 @@ #include #include #include -#include +#include #include #include #include diff -Nru a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c --- a/drivers/scsi/ide-scsi.c Sun Jul 27 10:13:48 2003 +++ b/drivers/scsi/ide-scsi.c Sun Jul 27 10:13:48 2003 @@ -978,8 +978,10 @@ idescsi_setup (drive, idescsi); drive->disk->fops = &idescsi_ops; err = scsi_add_host(host, &idescsi_primary); - if (!err) + if (!err) { + scsi_scan_host(host); return 0; + } /* fall through on error */ ide_unregister_subdriver(drive); } diff -Nru a/drivers/scsi/imm.c b/drivers/scsi/imm.c --- a/drivers/scsi/imm.c Sun Jul 27 10:13:52 2003 +++ b/drivers/scsi/imm.c Sun Jul 27 10:13:52 2003 @@ -24,7 +24,7 @@ void imm_reset_pulse(unsigned int base); static int device_check(int host_no); -#include +#include #include #include #include diff -Nru a/drivers/scsi/imm.h b/drivers/scsi/imm.h --- a/drivers/scsi/imm.h Sun Jul 27 10:13:39 2003 +++ b/drivers/scsi/imm.h Sun Jul 27 10:13:39 2003 @@ -75,7 +75,7 @@ #include #include #include -#include +#include #include #include diff -Nru a/drivers/scsi/in2000.c b/drivers/scsi/in2000.c --- a/drivers/scsi/in2000.c Sun Jul 27 10:13:49 2003 +++ b/drivers/scsi/in2000.c Sun Jul 27 10:13:49 2003 @@ -114,7 +114,6 @@ */ #include -#include #include #include #include diff -Nru a/drivers/scsi/ini9100u.c b/drivers/scsi/ini9100u.c --- a/drivers/scsi/ini9100u.c Sun Jul 27 10:13:43 2003 +++ b/drivers/scsi/ini9100u.c Sun Jul 27 10:13:43 2003 @@ -119,7 +119,7 @@ #include #include #include -#include +#include #include #include #include diff -Nru a/drivers/scsi/inia100.c b/drivers/scsi/inia100.c --- a/drivers/scsi/inia100.c Sun Jul 27 10:13:43 2003 +++ b/drivers/scsi/inia100.c Sun Jul 27 10:13:43 2003 @@ -74,7 +74,7 @@ #include #include #include -#include +#include #include #include #include diff -Nru a/drivers/scsi/ips.c b/drivers/scsi/ips.c --- a/drivers/scsi/ips.c Sun Jul 27 10:13:40 2003 +++ b/drivers/scsi/ips.c Sun Jul 27 10:13:40 2003 @@ -167,7 +167,7 @@ #include #include -#include +#include #include #include diff -Nru a/drivers/scsi/ips.h b/drivers/scsi/ips.h --- a/drivers/scsi/ips.h Sun Jul 27 10:13:42 2003 +++ b/drivers/scsi/ips.h Sun Jul 27 10:13:42 2003 @@ -111,7 +111,7 @@ #else #define IPS_REGISTER_HOSTS(SHT) (!ips_detect(SHT)) #define IPS_UNREGISTER_HOSTS(SHT) - #define IPS_ADD_HOST(shost,device) scsi_add_host(shost,device) + #define IPS_ADD_HOST(shost,device) do { scsi_add_host(shost,device); scsi_scan_host(shost); } while (0) #define IPS_REMOVE_HOST(shost) scsi_remove_host(shost) #define IPS_SCSI_SET_DEVICE(sh,ha) scsi_set_device(sh, &(ha)->pcidev->dev) #define IPS_PRINTK(level, pcidev, format, arg...) \ diff -Nru a/drivers/scsi/jazz_esp.c b/drivers/scsi/jazz_esp.c --- a/drivers/scsi/jazz_esp.c Sun Jul 27 10:13:41 2003 +++ b/drivers/scsi/jazz_esp.c Sun Jul 27 10:13:41 2003 @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include diff -Nru a/drivers/scsi/lasi700.c b/drivers/scsi/lasi700.c --- a/drivers/scsi/lasi700.c Sun Jul 27 10:13:41 2003 +++ b/drivers/scsi/lasi700.c Sun Jul 27 10:13:41 2003 @@ -128,7 +128,8 @@ } dev_set_drvdata(&dev->dev, host); - scsi_add_host(host, &dev->dev); + scsi_add_host(host, &dev->dev); /* XXX handle failure */ + scsi_scan_host(host); return 0; @@ -165,7 +166,6 @@ lasi700_exit(void) { unregister_parisc_driver(&lasi700_driver); - scsi_sysfs_release_attributes(&lasi700_template); } module_init(lasi700_init); diff -Nru a/drivers/scsi/mac53c94.c b/drivers/scsi/mac53c94.c --- a/drivers/scsi/mac53c94.c Sun Jul 27 10:13:40 2003 +++ b/drivers/scsi/mac53c94.c Sun Jul 27 10:13:40 2003 @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include #include diff -Nru a/drivers/scsi/mac_esp.c b/drivers/scsi/mac_esp.c --- a/drivers/scsi/mac_esp.c Sun Jul 27 10:13:45 2003 +++ b/drivers/scsi/mac_esp.c Sun Jul 27 10:13:45 2003 @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include #include diff -Nru a/drivers/scsi/mac_scsi.c b/drivers/scsi/mac_scsi.c --- a/drivers/scsi/mac_scsi.c Sun Jul 27 10:13:41 2003 +++ b/drivers/scsi/mac_scsi.c Sun Jul 27 10:13:41 2003 @@ -39,7 +39,7 @@ #include #include #include -#include +#include #include #include diff -Nru a/drivers/scsi/mca_53c9x.c b/drivers/scsi/mca_53c9x.c --- a/drivers/scsi/mca_53c9x.c Sun Jul 27 10:13:43 2003 +++ b/drivers/scsi/mca_53c9x.c Sun Jul 27 10:13:43 2003 @@ -37,7 +37,7 @@ #include #include #include -#include +#include #include #include #include diff -Nru a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c --- a/drivers/scsi/megaraid.c Sun Jul 27 10:13:39 2003 +++ b/drivers/scsi/megaraid.c Sun Jul 27 10:13:39 2003 @@ -32,7 +32,7 @@ #include #include -#include +#include #include #include #include diff -Nru a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c --- a/drivers/scsi/mesh.c Sun Jul 27 10:13:48 2003 +++ b/drivers/scsi/mesh.c Sun Jul 27 10:13:48 2003 @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include #include diff -Nru a/drivers/scsi/mvme147.c b/drivers/scsi/mvme147.c --- a/drivers/scsi/mvme147.c Sun Jul 27 10:13:43 2003 +++ b/drivers/scsi/mvme147.c Sun Jul 27 10:13:43 2003 @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include #include diff -Nru a/drivers/scsi/mvme16x.c b/drivers/scsi/mvme16x.c --- a/drivers/scsi/mvme16x.c Sun Jul 27 10:13:50 2003 +++ b/drivers/scsi/mvme16x.c Sun Jul 27 10:13:50 2003 @@ -5,7 +5,7 @@ */ #include #include -#include +#include #include #include diff -Nru a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c --- a/drivers/scsi/ncr53c8xx.c Sun Jul 27 10:13:43 2003 +++ b/drivers/scsi/ncr53c8xx.c Sun Jul 27 10:13:43 2003 @@ -140,7 +140,7 @@ #include #include -#include +#include #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,35) #include diff -Nru a/drivers/scsi/nsp32.c b/drivers/scsi/nsp32.c --- a/drivers/scsi/nsp32.c Sun Jul 27 10:13:44 2003 +++ b/drivers/scsi/nsp32.c Sun Jul 27 10:13:44 2003 @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include #include @@ -1820,7 +1820,8 @@ goto free_irq; } - scsi_add_host(host, &pdev->dev); + scsi_add_host(host, &pdev->dev); /* XXX handle failure */ + scsi_scan_host(host); pci_set_drvdata(pdev, host); return 0; diff -Nru a/drivers/scsi/oktagon_esp.c b/drivers/scsi/oktagon_esp.c --- a/drivers/scsi/oktagon_esp.c Sun Jul 27 10:13:40 2003 +++ b/drivers/scsi/oktagon_esp.c Sun Jul 27 10:13:40 2003 @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include #include @@ -550,7 +550,7 @@ void dma_mmu_get_scsi_one(struct NCR_ESP *esp, Scsi_Cmnd *sp) { - sp->SCp.have_data_in = (int) sp->SCp.ptr = + sp->SCp.ptr = sp->request_buffer; } diff -Nru a/drivers/scsi/osst.c b/drivers/scsi/osst.c --- a/drivers/scsi/osst.c Sun Jul 27 10:13:45 2003 +++ b/drivers/scsi/osst.c Sun Jul 27 10:13:45 2003 @@ -46,7 +46,7 @@ #include #include #include -#include +#include #include #include #include diff -Nru a/drivers/scsi/pas16.c b/drivers/scsi/pas16.c --- a/drivers/scsi/pas16.c Sun Jul 27 10:13:40 2003 +++ b/drivers/scsi/pas16.c Sun Jul 27 10:13:40 2003 @@ -117,7 +117,8 @@ #include #include #include -#include +#include +#include #include #include #include diff -Nru a/drivers/scsi/pc980155.c b/drivers/scsi/pc980155.c --- a/drivers/scsi/pc980155.c Sun Jul 27 10:13:40 2003 +++ b/drivers/scsi/pc980155.c Sun Jul 27 10:13:40 2003 @@ -11,7 +11,7 @@ */ #include -#include +#include #include #include #include diff -Nru a/drivers/scsi/pci2000.c b/drivers/scsi/pci2000.c --- a/drivers/scsi/pci2000.c Sun Jul 27 10:13:48 2003 +++ b/drivers/scsi/pci2000.c Sun Jul 27 10:13:48 2003 @@ -35,7 +35,7 @@ ****************************************************************************/ #define PCI2000_VERSION "1.20" -#include +#include #include #include #include diff -Nru a/drivers/scsi/pci2220i.c b/drivers/scsi/pci2220i.c --- a/drivers/scsi/pci2220i.c Sun Jul 27 10:13:40 2003 +++ b/drivers/scsi/pci2220i.c Sun Jul 27 10:13:40 2003 @@ -50,7 +50,7 @@ #include #include #include -#include +#include #include #include diff -Nru a/drivers/scsi/pcmcia/aha152x_stub.c b/drivers/scsi/pcmcia/aha152x_stub.c --- a/drivers/scsi/pcmcia/aha152x_stub.c Sun Jul 27 10:13:51 2003 +++ b/drivers/scsi/pcmcia/aha152x_stub.c Sun Jul 27 10:13:51 2003 @@ -44,7 +44,7 @@ #include #include #include -#include +#include #include #include "scsi.h" @@ -278,7 +278,8 @@ goto cs_failed; } - scsi_add_host(host, NULL); + scsi_add_host(host, NULL); /* XXX handle failure */ + scsi_scan_host(host); sprintf(info->node.dev_name, "scsi%d", host->host_no); link->dev = &info->node; diff -Nru a/drivers/scsi/pcmcia/fdomain_stub.c b/drivers/scsi/pcmcia/fdomain_stub.c --- a/drivers/scsi/pcmcia/fdomain_stub.c Sun Jul 27 10:13:47 2003 +++ b/drivers/scsi/pcmcia/fdomain_stub.c Sun Jul 27 10:13:47 2003 @@ -41,7 +41,7 @@ #include #include #include -#include +#include #include #include "scsi.h" @@ -254,7 +254,8 @@ goto cs_failed; } - scsi_add_host(host, NULL); + scsi_add_host(host, NULL); /* XXX handle failure */ + scsi_scan_host(host); sprintf(info->node.dev_name, "scsi%d", host->host_no); link->dev = &info->node; diff -Nru a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c --- a/drivers/scsi/pcmcia/nsp_cs.c Sun Jul 27 10:13:52 2003 +++ b/drivers/scsi/pcmcia/nsp_cs.c Sun Jul 27 10:13:52 2003 @@ -44,7 +44,7 @@ #include #include #include -#include +#include #include #include @@ -1773,7 +1773,8 @@ req.Base+req.Size-1); printk("\n"); - scsi_add_host(host, NULL); + scsi_add_host(host, NULL); /* XXX handle failure */ + scsi_scan_host(host); link->state &= ~DEV_CONFIG_PENDING; return; diff -Nru a/drivers/scsi/pcmcia/qlogic_stub.c b/drivers/scsi/pcmcia/qlogic_stub.c --- a/drivers/scsi/pcmcia/qlogic_stub.c Sun Jul 27 10:13:46 2003 +++ b/drivers/scsi/pcmcia/qlogic_stub.c Sun Jul 27 10:13:46 2003 @@ -42,7 +42,7 @@ #include #include #include -#include +#include #include #include "scsi.h" @@ -270,7 +270,8 @@ link->dev = &info->node; info->host = host; - scsi_add_host(host, NULL); + scsi_add_host(host, NULL); /* XXX handle failure */ + scsi_scan_host(host); out: link->state &= ~DEV_CONFIG_PENDING; diff -Nru a/drivers/scsi/pluto.c b/drivers/scsi/pluto.c --- a/drivers/scsi/pluto.c Sun Jul 27 10:13:43 2003 +++ b/drivers/scsi/pluto.c Sun Jul 27 10:13:43 2003 @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include #include diff -Nru a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c --- a/drivers/scsi/ppa.c Sun Jul 27 10:13:47 2003 +++ b/drivers/scsi/ppa.c Sun Jul 27 10:13:47 2003 @@ -15,7 +15,7 @@ /* The following #define is to avoid a clash with hosts.c */ #define PPA_CODE 1 -#include +#include #include #include #include diff -Nru a/drivers/scsi/ppa.h b/drivers/scsi/ppa.h --- a/drivers/scsi/ppa.h Sun Jul 27 10:13:50 2003 +++ b/drivers/scsi/ppa.h Sun Jul 27 10:13:50 2003 @@ -82,7 +82,7 @@ #include #include #include -#include +#include #include #include diff -Nru a/drivers/scsi/psi240i.c b/drivers/scsi/psi240i.c --- a/drivers/scsi/psi240i.c Sun Jul 27 10:13:48 2003 +++ b/drivers/scsi/psi240i.c Sun Jul 27 10:13:48 2003 @@ -26,7 +26,7 @@ #include -#include +#include #include #include #include diff -Nru a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c --- a/drivers/scsi/qla1280.c Sun Jul 27 10:13:52 2003 +++ b/drivers/scsi/qla1280.c Sun Jul 27 10:13:52 2003 @@ -252,7 +252,7 @@ #include #include #include -#include +#include #include #include #include @@ -327,7 +327,7 @@ /* 3.16 */ #ifdef QLA_64BIT_PTR #define pci_dma_lo32(a) (a & 0xffffffff) -#define pci_dma_hi32(a) (a >> 32) +#define pci_dma_hi32(a) ((a >> 16)>>16) #else #define pci_dma_lo32(a) (a & 0xffffffff) #define pci_dma_hi32(a) 0 diff -Nru a/drivers/scsi/qlogicfas.c b/drivers/scsi/qlogicfas.c --- a/drivers/scsi/qlogicfas.c Sun Jul 27 10:13:52 2003 +++ b/drivers/scsi/qlogicfas.c Sun Jul 27 10:13:52 2003 @@ -127,7 +127,7 @@ #endif #include -#include /* to get disk capacity */ +#include /* to get disk capacity */ #include #include #include @@ -140,6 +140,7 @@ #include #include +#include #include "scsi.h" #include "hosts.h" diff -Nru a/drivers/scsi/qlogicfc.c b/drivers/scsi/qlogicfc.c --- a/drivers/scsi/qlogicfc.c Sun Jul 27 10:13:49 2003 +++ b/drivers/scsi/qlogicfc.c Sun Jul 27 10:13:49 2003 @@ -50,7 +50,7 @@ * */ -#include +#include #include #include #include diff -Nru a/drivers/scsi/qlogicisp.c b/drivers/scsi/qlogicisp.c --- a/drivers/scsi/qlogicisp.c Sun Jul 27 10:13:52 2003 +++ b/drivers/scsi/qlogicisp.c Sun Jul 27 10:13:52 2003 @@ -20,7 +20,7 @@ * General Public License for more details. */ -#include +#include #include #include #include diff -Nru a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c --- a/drivers/scsi/qlogicpti.c Sun Jul 27 10:13:48 2003 +++ b/drivers/scsi/qlogicpti.c Sun Jul 27 10:13:48 2003 @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include diff -Nru a/drivers/scsi/scsi.h b/drivers/scsi/scsi.h --- a/drivers/scsi/scsi.h Sun Jul 27 10:13:42 2003 +++ b/drivers/scsi/scsi.h Sun Jul 27 10:13:42 2003 @@ -174,11 +174,6 @@ #define SCSI_MLQUEUE_DEVICE_BUSY 0x1056 #define SCSI_MLQUEUE_EH_RETRY 0x1057 -extern int scsi_sysfs_modify_sdev_attribute(struct device_attribute ***dev_attrs, - struct device_attribute *attr); -extern int scsi_sysfs_modify_shost_attribute(struct class_device_attribute ***class_attrs, - struct class_device_attribute *attr); - /* * Legacy dma direction interfaces. * diff -Nru a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c --- a/drivers/scsi/scsi_debug.c Sun Jul 27 10:13:47 2003 +++ b/drivers/scsi/scsi_debug.c Sun Jul 27 10:13:47 2003 @@ -41,7 +41,7 @@ #include #include -#include +#include #include "scsi.h" #include "hosts.h" #include @@ -687,7 +687,7 @@ pcontrol = (cmd[2] & 0xc0) >> 6; pcode = cmd[2] & 0x3f; msense_6 = (MODE_SENSE == cmd[0]); - alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[6]); + alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]); /* printk(KERN_INFO "msense: dbd=%d pcontrol=%d pcode=%d " "msense_6=%d alloc_len=%d\n", dbd, pcontrol, pcode, " "msense_6, alloc_len); */ @@ -1701,7 +1701,8 @@ printk(KERN_ERR "%s: scsi_add_host failed\n", __FUNCTION__); error = -ENODEV; scsi_host_put(hpnt); - } + } else + scsi_scan_host(hpnt); return error; diff -Nru a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c --- a/drivers/scsi/scsi_ioctl.c Sun Jul 27 10:13:52 2003 +++ b/drivers/scsi/scsi_ioctl.c Sun Jul 27 10:13:52 2003 @@ -18,7 +18,7 @@ #include #include -#include +#include #include "scsi.h" #include "hosts.h" #include diff -Nru a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c --- a/drivers/scsi/scsi_lib.c Sun Jul 27 10:13:45 2003 +++ b/drivers/scsi/scsi_lib.c Sun Jul 27 10:13:45 2003 @@ -8,7 +8,7 @@ */ #include -#include +#include #include #include #include @@ -69,7 +69,7 @@ */ sreq->sr_request->flags &= ~REQ_DONTPREP; blk_insert_request(sreq->sr_device->request_queue, sreq->sr_request, - at_head, sreq); + at_head, sreq, 0); return 0; } @@ -147,7 +147,7 @@ * function. The SCSI request function detects the blocked condition * and plugs the queue appropriately. */ - blk_insert_request(device->request_queue, cmd->request, 1, cmd); + blk_insert_request(device->request_queue, cmd->request, 1, cmd, 1); return 0; } @@ -444,22 +444,8 @@ */ static void scsi_requeue_command(struct request_queue *q, struct scsi_cmnd *cmd) { - unsigned long flags; - - spin_lock_irqsave(q->queue_lock, flags); - cmd->request->special = cmd; - if (blk_rq_tagged(cmd->request)) - blk_queue_end_tag(q, cmd->request); - - /* - * set REQ_SPECIAL - we have a command - * clear REQ_DONTPREP - we assume the sg table has been - * nuked so we need to set it up again. - */ - cmd->request->flags |= REQ_SPECIAL; cmd->request->flags &= ~REQ_DONTPREP; - __elv_add_request(q, cmd->request, 0, 0); - spin_unlock_irqrestore(q->queue_lock, flags); + blk_insert_request(q, cmd->request, 1, cmd, 1); scsi_run_queue(q); } @@ -1213,9 +1199,7 @@ * later time. */ spin_lock_irq(q->queue_lock); - if (blk_rq_tagged(req)) - blk_queue_end_tag(q, req); - __elv_add_request(q, req, 0, 0); + blk_requeue_request(q, req); sdev->device_busy--; if(sdev->device_busy == 0) blk_plug_device(q); @@ -1426,17 +1410,17 @@ if(scsi_status_is_good(sreq->sr_result)) { data->header_length = header_length; if(use_10_for_ms) { - data->length = buffer[0]*256 + buffer[1]; + data->length = buffer[0]*256 + buffer[1] + 2; data->medium_type = buffer[2]; data->device_specific = buffer[3]; data->longlba = buffer[4] & 0x01; data->block_descriptor_length = buffer[6]*256 + buffer[7]; } else { - data->length = buffer[0]; + data->length = buffer[0] + 1; data->medium_type = buffer[1]; - data->device_specific = buffer[3]; - data->block_descriptor_length = buffer[4]; + data->device_specific = buffer[2]; + data->block_descriptor_length = buffer[3]; } } diff -Nru a/drivers/scsi/scsi_module.c b/drivers/scsi/scsi_module.c --- a/drivers/scsi/scsi_module.c Sun Jul 27 10:13:43 2003 +++ b/drivers/scsi/scsi_module.c Sun Jul 27 10:13:43 2003 @@ -40,6 +40,7 @@ error = scsi_add_host(shost, NULL); if (error) goto fail; + scsi_scan_host(shost); } return 0; fail: diff -Nru a/drivers/scsi/scsi_pc98.c b/drivers/scsi/scsi_pc98.c --- a/drivers/scsi/scsi_pc98.c Sun Jul 27 10:13:40 2003 +++ b/drivers/scsi/scsi_pc98.c Sun Jul 27 10:13:40 2003 @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include "scsi.h" diff -Nru a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h --- a/drivers/scsi/scsi_priv.h Sun Jul 27 10:13:49 2003 +++ b/drivers/scsi/scsi_priv.h Sun Jul 27 10:13:49 2003 @@ -102,7 +102,6 @@ #endif /* CONFIG_PROC_FS */ /* scsi_scan.c */ -extern void scsi_scan_host(struct Scsi_Host *); extern void scsi_forget_host(struct Scsi_Host *); extern void scsi_free_sdev(struct scsi_device *); extern void scsi_free_shost(struct Scsi_Host *); @@ -116,11 +115,6 @@ extern void scsi_sysfs_remove_host(struct Scsi_Host *); extern int scsi_sysfs_register(void); extern void scsi_sysfs_unregister(void); - -/* definitions for the linker default sections covering the host - * class and device attributes */ -extern struct class_device_attribute *scsi_sysfs_shost_attrs[]; -extern struct device_attribute *scsi_sysfs_sdev_attrs[]; extern struct class shost_class; extern struct bus_type scsi_bus_type; diff -Nru a/drivers/scsi/scsi_proc.c b/drivers/scsi/scsi_proc.c --- a/drivers/scsi/scsi_proc.c Sun Jul 27 10:13:40 2003 +++ b/drivers/scsi/scsi_proc.c Sun Jul 27 10:13:40 2003 @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include diff -Nru a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c --- a/drivers/scsi/scsi_scan.c Sun Jul 27 10:13:50 2003 +++ b/drivers/scsi/scsi_scan.c Sun Jul 27 10:13:50 2003 @@ -29,7 +29,7 @@ #include #include #include -#include +#include #include "scsi.h" #include "hosts.h" @@ -464,8 +464,7 @@ while (i >= 0 && type[i] == ' ') type[i--] = '\0'; - snprintf(sdev->sdev_driverfs_dev.name, DEVICE_NAME_SIZE, "SCSI %s", - type); + snprintf(sdev->sdev_gendev.name, DEVICE_NAME_SIZE, "SCSI %s", type); } /** diff -Nru a/drivers/scsi/scsi_syms.c b/drivers/scsi/scsi_syms.c --- a/drivers/scsi/scsi_syms.c Sun Jul 27 10:13:45 2003 +++ b/drivers/scsi/scsi_syms.c Sun Jul 27 10:13:45 2003 @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include @@ -34,6 +34,7 @@ EXPORT_SYMBOL(scsi_register_interface); EXPORT_SYMBOL(scsi_host_alloc); EXPORT_SYMBOL(scsi_add_host); +EXPORT_SYMBOL(scsi_scan_host); EXPORT_SYMBOL(scsi_remove_host); EXPORT_SYMBOL(scsi_host_get); EXPORT_SYMBOL(scsi_host_put); diff -Nru a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c --- a/drivers/scsi/scsi_sysfs.c Sun Jul 27 10:13:42 2003 +++ b/drivers/scsi/scsi_sysfs.c Sun Jul 27 10:13:42 2003 @@ -45,7 +45,7 @@ shost_rd_attr(sg_tablesize, "%hu\n"); shost_rd_attr(unchecked_isa_dma, "%d\n"); -struct class_device_attribute *scsi_sysfs_shost_attrs[] = { +static struct class_device_attribute *scsi_sysfs_shost_attrs[] = { &class_device_attr_unique_id, &class_device_attr_host_busy, &class_device_attr_cmd_per_lun, @@ -204,7 +204,7 @@ static DEVICE_ATTR(rescan, S_IWUSR, NULL, store_rescan_field) /* Default template for device attributes. May NOT be modified */ -struct device_attribute *scsi_sysfs_sdev_attrs[] = { +static struct device_attribute *scsi_sysfs_sdev_attrs[] = { &dev_attr_device_blocked, &dev_attr_queue_depth, &dev_attr_type, @@ -228,6 +228,42 @@ scsi_free_sdev(sdev); } +static struct device_attribute *attr_overridden( + struct device_attribute **attrs, + struct device_attribute *attr) +{ + int i; + + if (!attrs) + return NULL; + for (i = 0; attrs[i]; i++) + if (!strcmp(attrs[i]->attr.name, attr->attr.name)) + return attrs[i]; + return NULL; +} + +static int attr_add(struct device *dev, struct device_attribute *attr) +{ + struct device_attribute *base_attr; + + /* + * Spare the caller from having to copy things it's not interested in. + */ + base_attr = attr_overridden(scsi_sysfs_sdev_attrs, attr); + if (base_attr) { + /* extend permissions */ + attr->attr.mode |= base_attr->attr.mode; + + /* override null show/store with default */ + if (!attr->show) + attr->show = base_attr->show; + if (!attr->store) + attr->store = base_attr->store; + } + + return device_create_file(dev, attr); +} + /** * scsi_device_register - register a scsi device with the scsi bus * @sdev: scsi_device to register @@ -239,20 +275,20 @@ { int error = 0, i; - device_initialize(&sdev->sdev_driverfs_dev); - sprintf(sdev->sdev_driverfs_dev.bus_id,"%d:%d:%d:%d", + device_initialize(&sdev->sdev_gendev); + sprintf(sdev->sdev_gendev.bus_id,"%d:%d:%d:%d", sdev->host->host_no, sdev->channel, sdev->id, sdev->lun); - sdev->sdev_driverfs_dev.parent = &sdev->host->host_gendev; - sdev->sdev_driverfs_dev.bus = &scsi_bus_type; - sdev->sdev_driverfs_dev.release = scsi_device_release; + sdev->sdev_gendev.parent = &sdev->host->shost_gendev; + sdev->sdev_gendev.bus = &scsi_bus_type; + sdev->sdev_gendev.release = scsi_device_release; class_device_initialize(&sdev->sdev_classdev); - sdev->sdev_classdev.dev = &sdev->sdev_driverfs_dev; + sdev->sdev_classdev.dev = &sdev->sdev_gendev; sdev->sdev_classdev.class = &sdev_class; snprintf(sdev->sdev_classdev.class_id, BUS_ID_SIZE, "%d:%d:%d:%d", sdev->host->host_no, sdev->channel, sdev->id, sdev->lun); - error = device_add(&sdev->sdev_driverfs_dev); + error = device_add(&sdev->sdev_gendev); if (error) { printk(KERN_INFO "error 1\n"); return error; @@ -260,16 +296,28 @@ error = class_device_add(&sdev->sdev_classdev); if (error) { printk(KERN_INFO "error 2\n"); - device_unregister(&sdev->sdev_driverfs_dev); + device_unregister(&sdev->sdev_gendev); return error; } - for (i = 0; !error && sdev->host->hostt->sdev_attrs[i] != NULL; i++) - error = device_create_file(&sdev->sdev_driverfs_dev, - sdev->host->hostt->sdev_attrs[i]); - - if (error) - scsi_device_unregister(sdev); + if (sdev->host->hostt->sdev_attrs) { + for (i = 0; sdev->host->hostt->sdev_attrs[i]; i++) { + error = attr_add(&sdev->sdev_gendev, + sdev->host->hostt->sdev_attrs[i]); + if (error) + scsi_device_unregister(sdev); + } + } + + for (i = 0; scsi_sysfs_sdev_attrs[i]; i++) { + if (!attr_overridden(sdev->host->hostt->sdev_attrs, + scsi_sysfs_sdev_attrs[i])) { + error = device_create_file(&sdev->sdev_gendev, + scsi_sysfs_sdev_attrs[i]); + if (error) + scsi_device_unregister(sdev); + } + } return error; } @@ -280,12 +328,8 @@ **/ void scsi_device_unregister(struct scsi_device *sdev) { - int i; - - for (i = 0; sdev->host->hostt->sdev_attrs[i] != NULL; i++) - device_remove_file(&sdev->sdev_driverfs_dev, sdev->host->hostt->sdev_attrs[i]); class_device_unregister(&sdev->sdev_classdev); - device_unregister(&sdev->sdev_driverfs_dev); + device_unregister(&sdev->sdev_gendev); } int scsi_register_driver(struct device_driver *drv) @@ -315,20 +359,57 @@ void scsi_sysfs_init_host(struct Scsi_Host *shost) { - device_initialize(&shost->host_gendev); - snprintf(shost->host_gendev.bus_id, BUS_ID_SIZE, "host%d", + device_initialize(&shost->shost_gendev); + snprintf(shost->shost_gendev.bus_id, BUS_ID_SIZE, "host%d", shost->host_no); - snprintf(shost->host_gendev.name, DEVICE_NAME_SIZE, "%s", + snprintf(shost->shost_gendev.name, DEVICE_NAME_SIZE, "%s", shost->hostt->proc_name); - shost->host_gendev.release = scsi_host_release; + shost->shost_gendev.release = scsi_host_release; - class_device_initialize(&shost->class_dev); - shost->class_dev.dev = &shost->host_gendev; - shost->class_dev.class = &shost_class; - snprintf(shost->class_dev.class_id, BUS_ID_SIZE, "host%d", + class_device_initialize(&shost->shost_classdev); + shost->shost_classdev.dev = &shost->shost_gendev; + shost->shost_classdev.class = &shost_class; + snprintf(shost->shost_classdev.class_id, BUS_ID_SIZE, "host%d", shost->host_no); } +static struct class_device_attribute *class_attr_overridden( + struct class_device_attribute **attrs, + struct class_device_attribute *attr) +{ + int i; + + if (!attrs) + return NULL; + for (i = 0; attrs[i]; i++) + if (!strcmp(attrs[i]->attr.name, attr->attr.name)) + return attrs[i]; + return NULL; +} + +static int class_attr_add(struct class_device *classdev, + struct class_device_attribute *attr) +{ + struct class_device_attribute *base_attr; + + /* + * Spare the caller from having to copy things it's not interested in. + */ + base_attr = class_attr_overridden(scsi_sysfs_shost_attrs, attr); + if (base_attr) { + /* extend permissions */ + attr->attr.mode |= base_attr->attr.mode; + + /* override null show/store with default */ + if (!attr->show) + attr->show = base_attr->show; + if (!attr->store) + attr->store = base_attr->store; + } + + return class_device_create_file(classdev, attr); +} + /** * scsi_sysfs_add_host - add scsi host to subsystem * @shost: scsi host struct to add to subsystem @@ -336,31 +417,44 @@ **/ int scsi_sysfs_add_host(struct Scsi_Host *shost, struct device *dev) { - int i, error; + int error, i; - if (!shost->host_gendev.parent) - shost->host_gendev.parent = dev ? dev : &legacy_bus; + if (!shost->shost_gendev.parent) + shost->shost_gendev.parent = dev ? dev : &legacy_bus; - error = device_add(&shost->host_gendev); + error = device_add(&shost->shost_gendev); if (error) return error; - error = class_device_add(&shost->class_dev); + error = class_device_add(&shost->shost_classdev); if (error) goto clean_device; - for (i = 0; !error && shost->hostt->shost_attrs[i] != NULL; i++) - error = class_device_create_file(&shost->class_dev, - shost->hostt->shost_attrs[i]); - if (error) - goto clean_class; + if (shost->hostt->shost_attrs) { + for (i = 0; shost->hostt->shost_attrs[i]; i++) { + error = class_attr_add(&shost->shost_classdev, + shost->hostt->shost_attrs[i]); + if (error) + goto clean_class; + } + } + + for (i = 0; scsi_sysfs_shost_attrs[i]; i++) { + if (!class_attr_overridden(shost->hostt->shost_attrs, + scsi_sysfs_shost_attrs[i])) { + error = class_device_create_file(&shost->shost_classdev, + scsi_sysfs_shost_attrs[i]); + if (error) + goto clean_class; + } + } return error; clean_class: - class_device_del(&shost->class_dev); + class_device_del(&shost->shost_classdev); clean_device: - device_del(&shost->host_gendev); + device_del(&shost->shost_gendev); return error; } @@ -371,133 +465,6 @@ **/ void scsi_sysfs_remove_host(struct Scsi_Host *shost) { - class_device_del(&shost->class_dev); - device_del(&shost->host_gendev); -} - -/** scsi_sysfs_modify_shost_attribute - modify or add a host class attribute - * - * @class_attrs:host class attribute list to be added to or modified - * @attr: individual attribute to change or added - * - * returns zero if successful or error if not - **/ -int scsi_sysfs_modify_shost_attribute( - struct class_device_attribute ***class_attrs, - struct class_device_attribute *attr) -{ - int modify = -1; - int num_attrs; - - if(*class_attrs == NULL) - *class_attrs = scsi_sysfs_shost_attrs; - - for(num_attrs=0; (*class_attrs)[num_attrs] != NULL; num_attrs++) - if(strcmp((*class_attrs)[num_attrs]->attr.name, - attr->attr.name) == 0) - modify = num_attrs; - - if(*class_attrs == scsi_sysfs_shost_attrs || modify < 0) { - /* note: need space for null at the end as well */ - struct class_device_attribute **tmp_attrs = - kmalloc(sizeof(*tmp_attrs) * - (num_attrs + (modify >= 0 ? 1 : 2)), - GFP_KERNEL); - if(tmp_attrs == NULL) - return -ENOMEM; - memcpy(tmp_attrs, *class_attrs, sizeof(*tmp_attrs) * - (num_attrs + 1)); - if(*class_attrs != scsi_sysfs_shost_attrs) - kfree(*class_attrs); - *class_attrs = tmp_attrs; - } - if(modify >= 0) { - /* spare the caller from having to copy things it's - * not interested in */ - struct class_device_attribute *old_attr = - (*class_attrs)[modify]; - /* extend permissions */ - attr->attr.mode |= old_attr->attr.mode; - - /* override null show/store with default */ - if(attr->show == NULL) - attr->show = old_attr->show; - if(attr->store == NULL) - attr->store = old_attr->store; - (*class_attrs)[modify] = attr; - } else { - (*class_attrs)[num_attrs++] = attr; - (*class_attrs)[num_attrs] = NULL; - } - - return 0; -} -EXPORT_SYMBOL(scsi_sysfs_modify_shost_attribute); - -/** scsi_sysfs_modify_sdev_attribute - modify or add a host device attribute - * - * @dev_attrs: pointer to the attribute list to be added to or modified - * @attr: individual attribute to change or added - * - * returns zero if successful or error if not - **/ -int scsi_sysfs_modify_sdev_attribute(struct device_attribute ***dev_attrs, - struct device_attribute *attr) -{ - int modify = -1; - int num_attrs; - - if(*dev_attrs == NULL) - *dev_attrs = scsi_sysfs_sdev_attrs; - - for(num_attrs=0; (*dev_attrs)[num_attrs] != NULL; num_attrs++) - if(strcmp((*dev_attrs)[num_attrs]->attr.name, - attr->attr.name) == 0) - modify = num_attrs; - - if(*dev_attrs == scsi_sysfs_sdev_attrs || modify < 0) { - /* note: need space for null at the end as well */ - struct device_attribute **tmp_attrs = - kmalloc(sizeof(*tmp_attrs) * - (num_attrs + (modify >= 0 ? 1 : 2)), - GFP_KERNEL); - if(tmp_attrs == NULL) - return -ENOMEM; - memcpy(tmp_attrs, *dev_attrs, sizeof(*tmp_attrs) * - (num_attrs + 1)); - if(*dev_attrs != scsi_sysfs_sdev_attrs) - kfree(*dev_attrs); - *dev_attrs = tmp_attrs; - } - if(modify >= 0) { - /* spare the caller from having to copy things it's - * not interested in */ - struct device_attribute *old_attr = - (*dev_attrs)[modify]; - /* extend permissions */ - attr->attr.mode |= old_attr->attr.mode; - - /* override null show/store with default */ - if(attr->show == NULL) - attr->show = old_attr->show; - if(attr->store == NULL) - attr->store = old_attr->store; - (*dev_attrs)[modify] = attr; - } else { - (*dev_attrs)[num_attrs++] = attr; - (*dev_attrs)[num_attrs] = NULL; - } - - return 0; -} -EXPORT_SYMBOL(scsi_sysfs_modify_sdev_attribute); - -void scsi_sysfs_release_attributes(struct scsi_host_template *hostt) -{ - if(hostt->sdev_attrs != scsi_sysfs_sdev_attrs) - kfree(hostt->sdev_attrs); - - if(hostt->shost_attrs != scsi_sysfs_shost_attrs) - kfree(hostt->shost_attrs); + class_device_del(&shost->shost_classdev); + device_del(&shost->shost_gendev); } -EXPORT_SYMBOL(scsi_sysfs_release_attributes); diff -Nru a/drivers/scsi/scsicam.c b/drivers/scsi/scsicam.c --- a/drivers/scsi/scsicam.c Sun Jul 27 10:13:47 2003 +++ b/drivers/scsi/scsicam.c Sun Jul 27 10:13:47 2003 @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include #include "scsi.h" diff -Nru a/drivers/scsi/sd.c b/drivers/scsi/sd.c --- a/drivers/scsi/sd.c Sun Jul 27 10:13:49 2003 +++ b/drivers/scsi/sd.c Sun Jul 27 10:13:49 2003 @@ -43,7 +43,7 @@ #include #include #include -#include +#include #include #include @@ -606,35 +606,8 @@ static void sd_rescan(struct device *dev) { - struct scsi_device *sdp = to_scsi_device(dev); struct scsi_disk *sdkp = dev_get_drvdata(dev); - struct gendisk *gd; - struct scsi_request *SRpnt; - unsigned char *buffer; - - if (!sdkp || sdp->online == FALSE || !sdkp->media_present) - return; - - gd = sdkp->disk; - - SCSI_LOG_HLQUEUE(3, printk("sd_rescan: disk=%s\n", gd->disk_name)); - - SRpnt = scsi_allocate_request(sdp); - if (!SRpnt) { - printk(KERN_WARNING "(sd_rescan:) Request allocation " - "failure.\n"); - return; - } - - if (sdkp->device->host->unchecked_isa_dma) - buffer = kmalloc(512, GFP_DMA); - else - buffer = kmalloc(512, GFP_KERNEL); - - sd_read_capacity(sdkp, gd->disk_name, SRpnt, buffer); - set_capacity(gd, sdkp->capacity); - scsi_release_request(SRpnt); - kfree(buffer); + sd_revalidate_disk(sdkp->disk); } static struct block_device_operations sd_fops = { @@ -1318,7 +1291,7 @@ sd_revalidate_disk(gd); - gd->driverfs_dev = &sdp->sdev_driverfs_dev; + gd->driverfs_dev = &sdp->sdev_gendev; gd->flags = GENHD_FL_DRIVERFS; if (sdp->removable) gd->flags |= GENHD_FL_REMOVABLE; diff -Nru a/drivers/scsi/seagate.c b/drivers/scsi/seagate.c --- a/drivers/scsi/seagate.c Sun Jul 27 10:13:44 2003 +++ b/drivers/scsi/seagate.c Sun Jul 27 10:13:44 2003 @@ -95,7 +95,7 @@ #include #include #include -#include +#include #include #include diff -Nru a/drivers/scsi/sg.c b/drivers/scsi/sg.c --- a/drivers/scsi/sg.c Sun Jul 27 10:13:45 2003 +++ b/drivers/scsi/sg.c Sun Jul 27 10:13:45 2003 @@ -61,7 +61,7 @@ #include #include -#include +#include #include "scsi.h" #include "hosts.h" #include diff -Nru a/drivers/scsi/sgiwd93.c b/drivers/scsi/sgiwd93.c --- a/drivers/scsi/sgiwd93.c Sun Jul 27 10:13:52 2003 +++ b/drivers/scsi/sgiwd93.c Sun Jul 27 10:13:52 2003 @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include #include diff -Nru a/drivers/scsi/sim710.c b/drivers/scsi/sim710.c --- a/drivers/scsi/sim710.c Sun Jul 27 10:13:50 2003 +++ b/drivers/scsi/sim710.c Sun Jul 27 10:13:50 2003 @@ -29,7 +29,7 @@ #include #include -#include +#include #include #include #include @@ -138,7 +138,8 @@ goto out_unregister; } - scsi_add_host(host, dev); + scsi_add_host(host, dev); /* XXX handle failure */ + scsi_scan_host(host); hostdata->dev = dev; return 0; diff -Nru a/drivers/scsi/sr.c b/drivers/scsi/sr.c --- a/drivers/scsi/sr.c Sun Jul 27 10:13:42 2003 +++ b/drivers/scsi/sr.c Sun Jul 27 10:13:42 2003 @@ -43,7 +43,7 @@ #include #include #include -#include +#include #include #include "scsi.h" @@ -533,7 +533,7 @@ snprintf(disk->devfs_name, sizeof(disk->devfs_name), "%s/cd", sdev->devfs_name); - disk->driverfs_dev = &sdev->sdev_driverfs_dev; + disk->driverfs_dev = &sdev->sdev_gendev; register_cdrom(&cd->cdi); set_capacity(disk, cd->capacity); disk->private_data = &cd->driver; diff -Nru a/drivers/scsi/sr_ioctl.c b/drivers/scsi/sr_ioctl.c --- a/drivers/scsi/sr_ioctl.c Sun Jul 27 10:13:48 2003 +++ b/drivers/scsi/sr_ioctl.c Sun Jul 27 10:13:48 2003 @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include #include #include diff -Nru a/drivers/scsi/sr_vendor.c b/drivers/scsi/sr_vendor.c --- a/drivers/scsi/sr_vendor.c Sun Jul 27 10:13:45 2003 +++ b/drivers/scsi/sr_vendor.c Sun Jul 27 10:13:45 2003 @@ -39,7 +39,7 @@ #include #include -#include +#include #include "scsi.h" #include "hosts.h" #include diff -Nru a/drivers/scsi/st.c b/drivers/scsi/st.c --- a/drivers/scsi/st.c Sun Jul 27 10:13:48 2003 +++ b/drivers/scsi/st.c Sun Jul 27 10:13:48 2003 @@ -32,7 +32,7 @@ #include #include #include -#include +#include #include #include #include diff -Nru a/drivers/scsi/sun3_NCR5380.c b/drivers/scsi/sun3_NCR5380.c --- a/drivers/scsi/sun3_NCR5380.c Sun Jul 27 10:13:41 2003 +++ b/drivers/scsi/sun3_NCR5380.c Sun Jul 27 10:13:41 2003 @@ -754,8 +754,8 @@ static char *lprint_Scsi_Cmnd (Scsi_Cmnd *cmd, char *pos, char *buffer, int length); -static int NCR5380_proc_info (struct Scsi_Host *instance, char *buffer, char **start, off_t offset, - int length, int inout) +int NCR5380_proc_info (struct Scsi_Host *instance, char *buffer, char **start, + off_t offset, int length, int inout) { char *pos = buffer; struct NCR5380_hostdata *hostdata; diff -Nru a/drivers/scsi/sun3_scsi.c b/drivers/scsi/sun3_scsi.c --- a/drivers/scsi/sun3_scsi.c Sun Jul 27 10:13:41 2003 +++ b/drivers/scsi/sun3_scsi.c Sun Jul 27 10:13:41 2003 @@ -61,7 +61,7 @@ #include #include #include -#include +#include #include #include diff -Nru a/drivers/scsi/sun3_scsi_vme.c b/drivers/scsi/sun3_scsi_vme.c --- a/drivers/scsi/sun3_scsi_vme.c Sun Jul 27 10:13:52 2003 +++ b/drivers/scsi/sun3_scsi_vme.c Sun Jul 27 10:13:52 2003 @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include diff -Nru a/drivers/scsi/sun3x_esp.c b/drivers/scsi/sun3x_esp.c --- a/drivers/scsi/sun3x_esp.c Sun Jul 27 10:13:49 2003 +++ b/drivers/scsi/sun3x_esp.c Sun Jul 27 10:13:49 2003 @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include #include diff -Nru a/drivers/scsi/sym53c416.c b/drivers/scsi/sym53c416.c --- a/drivers/scsi/sym53c416.c Sun Jul 27 10:13:41 2003 +++ b/drivers/scsi/sym53c416.c Sun Jul 27 10:13:41 2003 @@ -40,7 +40,7 @@ #include #include #include -#include +#include #include #include #include "scsi.h" diff -Nru a/drivers/scsi/sym53c8xx.c b/drivers/scsi/sym53c8xx.c --- a/drivers/scsi/sym53c8xx.c Sun Jul 27 10:13:48 2003 +++ b/drivers/scsi/sym53c8xx.c Sun Jul 27 10:13:48 2003 @@ -123,7 +123,7 @@ #include #include -#include +#include #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,35) #include @@ -1327,7 +1327,7 @@ #define SetScsiAbortResult(cmd) SetScsiResult(cmd, DID_ABORT, 0xff) #endif -static void sym53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs); +static irqreturn_t sym53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs); static void sym53c8xx_timeout(unsigned long np); #define initverbose (driver_setup.verbose) @@ -7374,7 +7374,7 @@ } if (cp->xerr_status & XE_BAD_PHASE) { PRINT_ADDR(cmd); - printk ("illegal scsi phase (4/5).\n"); + printk ("invalid scsi phase (4/5).\n"); } if (cp->xerr_status & XE_SODL_UNRUN) { PRINT_ADDR(cmd); @@ -13660,7 +13660,7 @@ ** routine for each host that uses this IRQ. */ -static void sym53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs) +static irqreturn_t sym53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs) { unsigned long flags; ncb_p np = (ncb_p) dev_id; @@ -13685,6 +13685,7 @@ ncr_flush_done_cmds(done_list); NCR_UNLOCK_SCSI_DONE(done_list->device->host, flags); } + return IRQ_HANDLED; } /* diff -Nru a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c --- a/drivers/scsi/sym53c8xx_2/sym_glue.c Sun Jul 27 10:13:52 2003 +++ b/drivers/scsi/sym53c8xx_2/sym_glue.c Sun Jul 27 10:13:52 2003 @@ -1110,6 +1110,7 @@ int sts = -1; struct sym_eh_wait eh, *ep = &eh; char devname[20]; + unsigned long flags; sprintf(devname, "%s:%d:%d", sym_name(np), cmd->device->id, cmd->device->lun); @@ -1201,7 +1202,11 @@ ep->timer.data = (u_long)cmd; ep->timed_out = 1; /* Be pessimistic for once :) */ add_timer(&ep->timer); + local_save_flags(flags); + spin_unlock_irq(cmd->device->host->host_lock); down(&ep->sem); + local_irq_restore(flags); + spin_lock(cmd->device->host->host_lock); if (ep->timed_out) sts = -2; } diff -Nru a/drivers/scsi/sym53c8xx_2/sym_glue.h b/drivers/scsi/sym53c8xx_2/sym_glue.h --- a/drivers/scsi/sym53c8xx_2/sym_glue.h Sun Jul 27 10:13:52 2003 +++ b/drivers/scsi/sym53c8xx_2/sym_glue.h Sun Jul 27 10:13:52 2003 @@ -84,7 +84,7 @@ #include #include -#include +#include #ifdef __sparc__ # include diff -Nru a/drivers/scsi/t128.c b/drivers/scsi/t128.c --- a/drivers/scsi/t128.c Sun Jul 27 10:13:51 2003 +++ b/drivers/scsi/t128.c Sun Jul 27 10:13:51 2003 @@ -110,7 +110,7 @@ #include #include #include -#include +#include #include #include #include diff -Nru a/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c --- a/drivers/scsi/tmscsim.c Sun Jul 27 10:13:52 2003 +++ b/drivers/scsi/tmscsim.c Sun Jul 27 10:13:52 2003 @@ -224,7 +224,7 @@ #include #include #include -#include +#include #include #include "scsi.h" diff -Nru a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c --- a/drivers/scsi/u14-34f.c Sun Jul 27 10:13:43 2003 +++ b/drivers/scsi/u14-34f.c Sun Jul 27 10:13:43 2003 @@ -414,7 +414,7 @@ #include #include #include -#include +#include #include #include #include diff -Nru a/drivers/scsi/ultrastor.c b/drivers/scsi/ultrastor.c --- a/drivers/scsi/ultrastor.c Sun Jul 27 10:13:46 2003 +++ b/drivers/scsi/ultrastor.c Sun Jul 27 10:13:46 2003 @@ -128,7 +128,7 @@ */ #include -#include +#include #include #include #include diff -Nru a/drivers/scsi/wd33c93.c b/drivers/scsi/wd33c93.c --- a/drivers/scsi/wd33c93.c Sun Jul 27 10:13:48 2003 +++ b/drivers/scsi/wd33c93.c Sun Jul 27 10:13:48 2003 @@ -79,7 +79,7 @@ #include #include #include -#include +#include #include #include "scsi.h" @@ -1920,7 +1920,7 @@ char *bp; char tbuf[128]; - struct Scsi_Host *instance; + struct WD33C93_hostdata *hd; Scsi_Cmnd *cmd; int x, i; static int stop = 0; diff -Nru a/drivers/scsi/wd7000.c b/drivers/scsi/wd7000.c --- a/drivers/scsi/wd7000.c Sun Jul 27 10:13:52 2003 +++ b/drivers/scsi/wd7000.c Sun Jul 27 10:13:52 2003 @@ -174,7 +174,7 @@ #include #include #include -#include +#include #include #include diff -Nru a/drivers/scsi/zalon.c b/drivers/scsi/zalon.c --- a/drivers/scsi/zalon.c Sun Jul 27 10:13:48 2003 +++ b/drivers/scsi/zalon.c Sun Jul 27 10:13:48 2003 @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include #include @@ -85,7 +85,7 @@ { struct gsc_irq gsc_irq; u32 zalon_vers; - int irq; + int irq, error = -ENODEV; unsigned long zalon = dev->hpa; unsigned long io_port = zalon + GSC_SCSI_ZALON_OFFSET; static int unit = 0; @@ -147,11 +147,18 @@ dev_set_drvdata(&dev->dev, host); - scsi_add_host(host, &dev->dev); + error = scsi_add_host(host, &dev->dev); + if (error) + goto fail_free_irq; + scsi_scan_host(host); return 0; + + fail_free_irq: + free_irq(irq, host); fail: - return -ENODEV; + ncr53c8xx_release(host); + return error; } static struct parisc_device_id zalon_tbl[] = { diff -Nru a/drivers/serial/Kconfig b/drivers/serial/Kconfig --- a/drivers/serial/Kconfig Sun Jul 27 10:13:51 2003 +++ b/drivers/serial/Kconfig Sun Jul 27 10:13:51 2003 @@ -404,14 +404,19 @@ on your Sparc system as the console, you can do so by answering Y to this option. -config V850E_NB85E_UART +config V850E_UART bool "NEC V850E on-chip UART support" - depends on V850E_NB85E || V850E2_ANNA || V850E_AS85EP1 + depends on V850E_MA1 || V850E_ME2 || V850E_TEG || V850E2_ANNA || V850E_AS85EP1 default y -config V850E_NB85E_UART_CONSOLE +config V850E_UARTB + bool + depends V850E_UART && V850E_ME2 + default y + +config V850E_UART_CONSOLE bool "Use NEC V850E on-chip UART for console" - depends on V850E_NB85E_UART + depends on V850E_UART config SERIAL98 tristate "PC-9800 8251-based primary serial port support" @@ -426,12 +431,12 @@ config SERIAL_CORE tristate - default m if SERIAL_AMBA!=y && SERIAL_CLPS711X!=y && SERIAL_21285!=y && !SERIAL_SA1100 && !SERIAL_ANAKIN && !SERIAL_UART00 && SERIAL_8250!=y && SERIAL_MUX!=y && !SERIAL_ROCKETPORT && !SERIAL_SUNCORE && !V850E_NB85E_UART && (SERIAL_AMBA=m || SERIAL_CLPS711X=m || SERIAL_21285=m || SERIAL_8250=m || SERIAL_MUX=m || SERIAL98=m) - default y if SERIAL_AMBA=y || SERIAL_CLPS711X=y || SERIAL_21285=y || SERIAL_SA1100 || SERIAL_ANAKIN || SERIAL_UART00 || SERIAL_8250=y || SERIAL_MUX=y || SERIAL_ROCKETPORT || SERIAL_SUNCORE || V850E_NB85E_UART || SERIAL98=y + default m if SERIAL_AMBA!=y && SERIAL_CLPS711X!=y && SERIAL_21285!=y && !SERIAL_SA1100 && !SERIAL_ANAKIN && !SERIAL_UART00 && SERIAL_8250!=y && SERIAL_MUX!=y && !SERIAL_ROCKETPORT && !SERIAL_SUNCORE && !V850E_UART && (SERIAL_AMBA=m || SERIAL_CLPS711X=m || SERIAL_21285=m || SERIAL_8250=m || SERIAL_MUX=m || SERIAL98=m) + default y if SERIAL_AMBA=y || SERIAL_CLPS711X=y || SERIAL_21285=y || SERIAL_SA1100 || SERIAL_ANAKIN || SERIAL_UART00 || SERIAL_8250=y || SERIAL_MUX=y || SERIAL_ROCKETPORT || SERIAL_SUNCORE || V850E_UART || SERIAL98=y config SERIAL_CORE_CONSOLE bool - depends on SERIAL_AMBA_CONSOLE || SERIAL_CLPS711X_CONSOLE || SERIAL_21285_CONSOLE || SERIAL_SA1100_CONSOLE || SERIAL_ANAKIN_CONSOLE || SERIAL_UART00_CONSOLE || SERIAL_8250_CONSOLE || SERIAL_MUX_CONSOLE || SERIAL_SUNZILOG_CONSOLE || SERIAL_SUNSU_CONSOLE || SERIAL_SUNSAB_CONSOLE || V850E_NB85E_UART_CONSOLE || SERIAL98_CONSOLE + depends on SERIAL_AMBA_CONSOLE || SERIAL_CLPS711X_CONSOLE || SERIAL_21285_CONSOLE || SERIAL_SA1100_CONSOLE || SERIAL_ANAKIN_CONSOLE || SERIAL_UART00_CONSOLE || SERIAL_8250_CONSOLE || SERIAL_MUX_CONSOLE || SERIAL_SUNZILOG_CONSOLE || SERIAL_SUNSU_CONSOLE || SERIAL_SUNSAB_CONSOLE || V850E_UART_CONSOLE || SERIAL98_CONSOLE default y config SERIAL_68328 diff -Nru a/drivers/serial/Makefile b/drivers/serial/Makefile --- a/drivers/serial/Makefile Sun Jul 27 10:13:45 2003 +++ b/drivers/serial/Makefile Sun Jul 27 10:13:45 2003 @@ -29,5 +29,5 @@ obj-$(CONFIG_SERIAL_68328) += 68328serial.o obj-$(CONFIG_SERIAL_68360) += 68360serial.o obj-$(CONFIG_SERIAL_COLDFIRE) += mcfserial.o -obj-$(CONFIG_V850E_NB85E_UART) += nb85e_uart.o +obj-$(CONFIG_V850E_UART) += v850e_uart.o obj-$(CONFIG_SERIAL98) += serial98.o diff -Nru a/drivers/serial/core.c b/drivers/serial/core.c --- a/drivers/serial/core.c Sun Jul 27 10:13:42 2003 +++ b/drivers/serial/core.c Sun Jul 27 10:13:42 2003 @@ -1667,23 +1667,25 @@ return ret + 1; } - status = port->ops->get_mctrl(port); - - ret += sprintf(buf + ret, " tx:%d rx:%d", - port->icount.tx, port->icount.rx); - if (port->icount.frame) - ret += sprintf(buf + ret, " fe:%d", - port->icount.frame); - if (port->icount.parity) - ret += sprintf(buf + ret, " pe:%d", - port->icount.parity); - if (port->icount.brk) - ret += sprintf(buf + ret, " brk:%d", - port->icount.brk); - if (port->icount.overrun) - ret += sprintf(buf + ret, " oe:%d", - port->icount.overrun); + if(capable(CAP_SYS_ADMIN)) + { + status = port->ops->get_mctrl(port); + ret += sprintf(buf + ret, " tx:%d rx:%d", + port->icount.tx, port->icount.rx); + if (port->icount.frame) + ret += sprintf(buf + ret, " fe:%d", + port->icount.frame); + if (port->icount.parity) + ret += sprintf(buf + ret, " pe:%d", + port->icount.parity); + if (port->icount.brk) + ret += sprintf(buf + ret, " brk:%d", + port->icount.brk); + if (port->icount.overrun) + ret += sprintf(buf + ret, " oe:%d", + port->icount.overrun); + #define INFOBIT(bit,str) \ if (port->mctrl & (bit)) \ strncat(stat_buf, (str), sizeof(stat_buf) - \ @@ -1693,19 +1695,22 @@ strncat(stat_buf, (str), sizeof(stat_buf) - \ strlen(stat_buf) - 2) - stat_buf[0] = '\0'; - stat_buf[1] = '\0'; - INFOBIT(TIOCM_RTS, "|RTS"); - STATBIT(TIOCM_CTS, "|CTS"); - INFOBIT(TIOCM_DTR, "|DTR"); - STATBIT(TIOCM_DSR, "|DSR"); - STATBIT(TIOCM_CAR, "|CD"); - STATBIT(TIOCM_RNG, "|RI"); - if (stat_buf[0]) - stat_buf[0] = ' '; - strcat(stat_buf, "\n"); - - ret += sprintf(buf + ret, stat_buf); + stat_buf[0] = '\0'; + stat_buf[1] = '\0'; + INFOBIT(TIOCM_RTS, "|RTS"); + STATBIT(TIOCM_CTS, "|CTS"); + INFOBIT(TIOCM_DTR, "|DTR"); + STATBIT(TIOCM_DSR, "|DSR"); + STATBIT(TIOCM_CAR, "|CD"); + STATBIT(TIOCM_RNG, "|RI"); + if (stat_buf[0]) + stat_buf[0] = ' '; + strcat(stat_buf, "\n"); + + ret += sprintf(buf + ret, stat_buf); + } +#undef STATBIT +#undef INFOBIT return ret; } diff -Nru a/drivers/serial/nb85e_uart.c b/drivers/serial/nb85e_uart.c --- a/drivers/serial/nb85e_uart.c Sun Jul 27 10:13:50 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,610 +0,0 @@ -/* - * drivers/serial/nb85e_uart.c -- Serial I/O using V850E/NB85E on-chip UART - * - * Copyright (C) 2001,02,03 NEC Corporation - * Copyright (C) 2001,02,03 Miles Bader - * - * This file is subject to the terms and conditions of the GNU General - * Public License. See the file COPYING in the main directory of this - * archive for more details. - * - * Written by Miles Bader - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -/* Initial UART state. This may be overridden by machine-dependent headers. */ -#ifndef NB85E_UART_INIT_BAUD -#define NB85E_UART_INIT_BAUD 115200 -#endif -#ifndef NB85E_UART_INIT_CFLAGS -#define NB85E_UART_INIT_CFLAGS (B115200 | CS8 | CREAD) -#endif - -/* XXX This should be in a header file. */ -#define NB85E_UART_BRGC_MIN 8 - -/* A string used for prefixing printed descriptions; since the same UART - macro is actually used on other chips than the V850E/NB85E. This must - be a constant string. */ -#ifndef NB85E_UART_CHIP_NAME -#define NB85E_UART_CHIP_NAME "V850E/NB85E" -#endif - - -/* Helper functions for doing baud-rate/frequency calculations. */ - -/* Calculate the minimum value for CKSR on this processor. */ -static inline unsigned cksr_min (void) -{ - int min = 0; - unsigned freq = NB85E_UART_BASE_FREQ; - while (freq > NB85E_UART_CKSR_MAX_FREQ) { - freq >>= 1; - min++; - } - return min; -} - -/* Minimum baud rate possible. */ -#define min_baud() \ - ((NB85E_UART_BASE_FREQ >> NB85E_UART_CKSR_MAX) / (2 * 255) + 1) - -/* Maximum baud rate possible. The error is quite high at max, though. */ -#define max_baud() \ - ((NB85E_UART_BASE_FREQ >> cksr_min()) / (2 * NB85E_UART_BRGC_MIN)) - - -/* Low-level UART functions. */ - -/* These masks define which control bits affect TX/RX modes, respectively. */ -#define RX_BITS \ - (NB85E_UART_ASIM_PS_MASK | NB85E_UART_ASIM_CL_8 | NB85E_UART_ASIM_ISRM) -#define TX_BITS \ - (NB85E_UART_ASIM_PS_MASK | NB85E_UART_ASIM_CL_8 | NB85E_UART_ASIM_SL_2) - -/* The UART require various delays after writing control registers. */ -static inline void nb85e_uart_delay (unsigned cycles) -{ - /* The loop takes 2 insns, so loop CYCLES / 2 times. */ - register unsigned count = cycles >> 1; - while (--count != 0) - /* nothing */; -} - -/* Configure and turn on uart channel CHAN, using the termios `control - modes' bits in CFLAGS, and a baud-rate of BAUD. */ -void nb85e_uart_configure (unsigned chan, unsigned cflags, unsigned baud) -{ - int flags; - unsigned new_config = 0; /* What we'll write to the control reg. */ - unsigned new_clk_divlog2; /* New baud-rate generate clock divider. */ - unsigned new_brgen_count; /* New counter max for baud-rate generator.*/ - /* These are the current values corresponding to the above. */ - unsigned old_config, old_clk_divlog2, old_brgen_count; - - /* Calculate new baud-rate generator config values. */ - - /* Calculate the log2 clock divider and baud-rate counter values - (note that the UART divides the resulting clock by 2, so - multiply BAUD by 2 here to compensate). */ - calc_counter_params (NB85E_UART_BASE_FREQ, baud * 2, - cksr_min(), NB85E_UART_CKSR_MAX, 8/*bits*/, - &new_clk_divlog2, &new_brgen_count); - - /* Figure out new configuration of control register. */ - if (cflags & CSTOPB) - /* Number of stop bits, 1 or 2. */ - new_config |= NB85E_UART_ASIM_SL_2; - if ((cflags & CSIZE) == CS8) - /* Number of data bits, 7 or 8. */ - new_config |= NB85E_UART_ASIM_CL_8; - if (! (cflags & PARENB)) - /* No parity check/generation. */ - new_config |= NB85E_UART_ASIM_PS_NONE; - else if (cflags & PARODD) - /* Odd parity check/generation. */ - new_config |= NB85E_UART_ASIM_PS_ODD; - else - /* Even parity check/generation. */ - new_config |= NB85E_UART_ASIM_PS_EVEN; - if (cflags & CREAD) - /* Reading enabled. */ - new_config |= NB85E_UART_ASIM_RXE; - - new_config |= NB85E_UART_ASIM_TXE; /* Writing is always enabled. */ - new_config |= NB85E_UART_ASIM_CAE; - new_config |= NB85E_UART_ASIM_ISRM; /* Errors generate a read-irq. */ - - /* Disable interrupts while we're twiddling the hardware. */ - local_irq_save (flags); - -#ifdef NB85E_UART_PRE_CONFIGURE - NB85E_UART_PRE_CONFIGURE (chan, cflags, baud); -#endif - - old_config = NB85E_UART_ASIM (chan); - old_clk_divlog2 = NB85E_UART_CKSR (chan); - old_brgen_count = NB85E_UART_BRGC (chan); - - if (new_clk_divlog2 != old_clk_divlog2 - || new_brgen_count != old_brgen_count) - { - /* The baud rate has changed. First, disable the UART. */ - NB85E_UART_ASIM (chan) = 0; - old_config = 0; - /* Reprogram the baud-rate generator. */ - NB85E_UART_CKSR (chan) = new_clk_divlog2; - NB85E_UART_BRGC (chan) = new_brgen_count; - } - - if (! (old_config & NB85E_UART_ASIM_CAE)) { - /* If we are enabling the uart for the first time, start - by turning on the enable bit, which must be done - before turning on any other bits. */ - NB85E_UART_ASIM (chan) = NB85E_UART_ASIM_CAE; - /* Enabling the uart also resets it. */ - old_config = NB85E_UART_ASIM_CAE; - } - - if (new_config != old_config) { - /* Which of the TXE/RXE bits we'll temporarily turn off - before changing other control bits. */ - unsigned temp_disable = 0; - /* Which of the TXE/RXE bits will be enabled. */ - unsigned enable = 0; - unsigned changed_bits = new_config ^ old_config; - - /* Which of RX/TX will be enabled in the new configuration. */ - if (new_config & RX_BITS) - enable |= (new_config & NB85E_UART_ASIM_RXE); - if (new_config & TX_BITS) - enable |= (new_config & NB85E_UART_ASIM_TXE); - - /* Figure out which of RX/TX needs to be disabled; note - that this will only happen if they're not already - disabled. */ - if (changed_bits & RX_BITS) - temp_disable |= (old_config & NB85E_UART_ASIM_RXE); - if (changed_bits & TX_BITS) - temp_disable |= (old_config & NB85E_UART_ASIM_TXE); - - /* We have to turn off RX and/or TX mode before changing - any associated control bits. */ - if (temp_disable) - NB85E_UART_ASIM (chan) = old_config & ~temp_disable; - - /* Write the new control bits, while RX/TX are disabled. */ - if (changed_bits & ~enable) - NB85E_UART_ASIM (chan) = new_config & ~enable; - - /* The UART may not be reset properly unless we - wait at least 2 `basic-clocks' until turning - on the TXE/RXE bits again. A `basic clock' - is the clock used by the baud-rate generator, i.e., - the cpu clock divided by the 2^new_clk_divlog2. */ - nb85e_uart_delay (1 << (new_clk_divlog2 + 1)); - - /* Write the final version, with enable bits turned on. */ - NB85E_UART_ASIM (chan) = new_config; - } - - local_irq_restore (flags); -} - - -/* Low-level console. */ - -#ifdef CONFIG_V850E_NB85E_UART_CONSOLE - -static void nb85e_uart_cons_write (struct console *co, - const char *s, unsigned count) -{ - if (count > 0) { - unsigned chan = co->index; - unsigned irq = IRQ_INTST (chan); - int irq_was_enabled, irq_was_pending, flags; - - /* We don't want to get `transmission completed' (INTST) - interrupts, since we're busy-waiting, so we disable - them while sending (we don't disable interrupts - entirely because sending over a serial line is really - slow). We save the status of INTST and restore it - when we're done so that using printk doesn't - interfere with normal serial transmission (other than - interleaving the output, of course!). This should - work correctly even if this function is interrupted - and the interrupt printks something. */ - - /* Disable interrupts while fiddling with INTST. */ - local_irq_save (flags); - /* Get current INTST status. */ - irq_was_enabled = nb85e_intc_irq_enabled (irq); - irq_was_pending = nb85e_intc_irq_pending (irq); - /* Disable INTST if necessary. */ - if (irq_was_enabled) - nb85e_intc_disable_irq (irq); - /* Turn interrupts back on. */ - local_irq_restore (flags); - - /* Send characters. */ - while (count > 0) { - int ch = *s++; - - if (ch == '\n') { - /* We don't have the benefit of a tty - driver, so translate NL into CR LF. */ - nb85e_uart_wait_for_xmit_ok (chan); - nb85e_uart_putc (chan, '\r'); - } - - nb85e_uart_wait_for_xmit_ok (chan); - nb85e_uart_putc (chan, ch); - - count--; - } - - /* Restore saved INTST status. */ - if (irq_was_enabled) { - /* Wait for the last character we sent to be - completely transmitted (as we'll get an INTST - interrupt at that point). */ - nb85e_uart_wait_for_xmit_done (chan); - /* Clear pending interrupts received due - to our transmission, unless there was already - one pending, in which case we want the - handler to be called. */ - if (! irq_was_pending) - nb85e_intc_clear_pending_irq (irq); - /* ... and then turn back on handling. */ - nb85e_intc_enable_irq (irq); - } - } -} - -extern struct uart_driver nb85e_uart_driver; -static struct console nb85e_uart_cons = -{ - .name = "ttyS", - .write = nb85e_uart_cons_write, - .device = uart_console_device, - .flags = CON_PRINTBUFFER, - .cflag = NB85E_UART_INIT_CFLAGS, - .index = -1, - .data = &nb85e_uart_driver, -}; - -void nb85e_uart_cons_init (unsigned chan) -{ - nb85e_uart_configure (chan, NB85E_UART_INIT_CFLAGS, - NB85E_UART_INIT_BAUD); - nb85e_uart_cons.index = chan; - register_console (&nb85e_uart_cons); - printk ("Console: %s on-chip UART channel %d\n", - NB85E_UART_CHIP_NAME, chan); -} - -#define NB85E_UART_CONSOLE &nb85e_uart_cons - -#else /* !CONFIG_V850E_NB85E_UART_CONSOLE */ -#define NB85E_UART_CONSOLE 0 -#endif /* CONFIG_V850E_NB85E_UART_CONSOLE */ - -/* TX/RX interrupt handlers. */ - -static void nb85e_uart_stop_tx (struct uart_port *port, unsigned tty_stop); - -void nb85e_uart_tx (struct uart_port *port) -{ - struct circ_buf *xmit = &port->info->xmit; - int stopped = uart_tx_stopped (port); - - if (nb85e_uart_xmit_ok (port->line)) { - int tx_ch; - - if (port->x_char) { - tx_ch = port->x_char; - port->x_char = 0; - } else if (!uart_circ_empty (xmit) && !stopped) { - tx_ch = xmit->buf[xmit->tail]; - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - } else - goto no_xmit; - - nb85e_uart_putc (port->line, tx_ch); - port->icount.tx++; - - if (uart_circ_chars_pending (xmit) < WAKEUP_CHARS) - uart_write_wakeup (port); - } - - no_xmit: - if (uart_circ_empty (xmit) || stopped) - nb85e_uart_stop_tx (port, stopped); -} - -static void nb85e_uart_tx_irq (int irq, void *data, struct pt_regs *regs) -{ - struct uart_port *port = data; - nb85e_uart_tx (port); -} - -static void nb85e_uart_rx_irq (int irq, void *data, struct pt_regs *regs) -{ - struct uart_port *port = data; - unsigned ch_stat = TTY_NORMAL; - unsigned ch = NB85E_UART_RXB (port->line); - unsigned err = NB85E_UART_ASIS (port->line); - - if (err) { - if (err & NB85E_UART_ASIS_OVE) { - ch_stat = TTY_OVERRUN; - port->icount.overrun++; - } else if (err & NB85E_UART_ASIS_FE) { - ch_stat = TTY_FRAME; - port->icount.frame++; - } else if (err & NB85E_UART_ASIS_PE) { - ch_stat = TTY_PARITY; - port->icount.parity++; - } - } - - port->icount.rx++; - - tty_insert_flip_char (port->info->tty, ch, ch_stat); - tty_schedule_flip (port->info->tty); -} - -/* Control functions for the serial framework. */ - -static void nb85e_uart_nop (struct uart_port *port) { } -static int nb85e_uart_success (struct uart_port *port) { return 0; } - -static unsigned nb85e_uart_tx_empty (struct uart_port *port) -{ - return TIOCSER_TEMT; /* Can't detect. */ -} - -static void nb85e_uart_set_mctrl (struct uart_port *port, unsigned mctrl) -{ -#ifdef NB85E_UART_SET_RTS - NB85E_UART_SET_RTS (port->line, (mctrl & TIOCM_RTS)); -#endif -} - -static unsigned nb85e_uart_get_mctrl (struct uart_port *port) -{ - /* We don't support DCD or DSR, so consider them permanently active. */ - int mctrl = TIOCM_CAR | TIOCM_DSR; - - /* We may support CTS. */ -#ifdef NB85E_UART_CTS - mctrl |= NB85E_UART_CTS(port->line) ? TIOCM_CTS : 0; -#else - mctrl |= TIOCM_CTS; -#endif - - return mctrl; -} - -static void nb85e_uart_start_tx (struct uart_port *port, unsigned tty_start) -{ - nb85e_intc_disable_irq (IRQ_INTST (port->line)); - nb85e_uart_tx (port); - nb85e_intc_enable_irq (IRQ_INTST (port->line)); -} - -static void nb85e_uart_stop_tx (struct uart_port *port, unsigned tty_stop) -{ - nb85e_intc_disable_irq (IRQ_INTST (port->line)); -} - -static void nb85e_uart_start_rx (struct uart_port *port) -{ - nb85e_intc_enable_irq (IRQ_INTSR (port->line)); -} - -static void nb85e_uart_stop_rx (struct uart_port *port) -{ - nb85e_intc_disable_irq (IRQ_INTSR (port->line)); -} - -static void nb85e_uart_break_ctl (struct uart_port *port, int break_ctl) -{ - /* Umm, do this later. */ -} - -static int nb85e_uart_startup (struct uart_port *port) -{ - int err; - - /* Alloc RX irq. */ - err = request_irq (IRQ_INTSR (port->line), nb85e_uart_rx_irq, - SA_INTERRUPT, "nb85e_uart", port); - if (err) - return err; - - /* Alloc TX irq. */ - err = request_irq (IRQ_INTST (port->line), nb85e_uart_tx_irq, - SA_INTERRUPT, "nb85e_uart", port); - if (err) { - free_irq (IRQ_INTSR (port->line), port); - return err; - } - - nb85e_uart_start_rx (port); - - return 0; -} - -static void nb85e_uart_shutdown (struct uart_port *port) -{ - /* Disable port interrupts. */ - free_irq (IRQ_INTST (port->line), port); - free_irq (IRQ_INTSR (port->line), port); - - /* Turn off xmit/recv enable bits. */ - NB85E_UART_ASIM (port->line) - &= ~(NB85E_UART_ASIM_TXE | NB85E_UART_ASIM_RXE); - /* Then reset the channel. */ - NB85E_UART_ASIM (port->line) = 0; -} - -static void -nb85e_uart_set_termios (struct uart_port *port, struct termios *termios, - struct termios *old) -{ - unsigned cflags = termios->c_cflag; - - /* Restrict flags to legal values. */ - if ((cflags & CSIZE) != CS7 && (cflags & CSIZE) != CS8) - /* The new value of CSIZE is invalid, use the old value. */ - cflags = (cflags & ~CSIZE) - | (old ? (old->c_cflag & CSIZE) : CS8); - - termios->c_cflag = cflags; - - nb85e_uart_configure (port->line, cflags, - uart_get_baud_rate (port, termios, old, - min_baud(), max_baud())); -} - -static const char *nb85e_uart_type (struct uart_port *port) -{ - return port->type == PORT_NB85E_UART ? "nb85e_uart" : 0; -} - -static void nb85e_uart_config_port (struct uart_port *port, int flags) -{ - if (flags & UART_CONFIG_TYPE) - port->type = PORT_NB85E_UART; -} - -static int -nb85e_uart_verify_port (struct uart_port *port, struct serial_struct *ser) -{ - if (ser->type != PORT_UNKNOWN && ser->type != PORT_NB85E_UART) - return -EINVAL; - if (ser->irq != IRQ_INTST (port->line)) - return -EINVAL; - return 0; -} - -static struct uart_ops nb85e_uart_ops = { - .tx_empty = nb85e_uart_tx_empty, - .get_mctrl = nb85e_uart_get_mctrl, - .set_mctrl = nb85e_uart_set_mctrl, - .start_tx = nb85e_uart_start_tx, - .stop_tx = nb85e_uart_stop_tx, - .stop_rx = nb85e_uart_stop_rx, - .enable_ms = nb85e_uart_nop, - .break_ctl = nb85e_uart_break_ctl, - .startup = nb85e_uart_startup, - .shutdown = nb85e_uart_shutdown, - .set_termios = nb85e_uart_set_termios, - .type = nb85e_uart_type, - .release_port = nb85e_uart_nop, - .request_port = nb85e_uart_success, - .config_port = nb85e_uart_config_port, - .verify_port = nb85e_uart_verify_port, -}; - -/* Initialization and cleanup. */ - -static struct uart_driver nb85e_uart_driver = { - .owner = THIS_MODULE, - .driver_name = "nb85e_uart", - .devfs_name = "tts/", - .dev_name = "ttyS", - .major = TTY_MAJOR, - .minor = NB85E_UART_MINOR_BASE, - .nr = NB85E_UART_NUM_CHANNELS, - .cons = NB85E_UART_CONSOLE, -}; - - -static struct uart_port nb85e_uart_ports[NB85E_UART_NUM_CHANNELS]; - -static int __init nb85e_uart_init (void) -{ - int rval; - - printk (KERN_INFO "%s on-chip UART\n", NB85E_UART_CHIP_NAME); - - rval = uart_register_driver (&nb85e_uart_driver); - if (rval == 0) { - unsigned chan; - - for (chan = 0; chan < NB85E_UART_NUM_CHANNELS; chan++) { - struct uart_port *port = &nb85e_uart_ports[chan]; - - memset (port, 0, sizeof *port); - - port->ops = &nb85e_uart_ops; - port->line = chan; - port->iotype = SERIAL_IO_MEM; - port->flags = UPF_BOOT_AUTOCONF; - - /* We actually use multiple IRQs, but the serial - framework seems to mainly use this for - informational purposes anyway. Here we use the TX - irq. */ - port->irq = IRQ_INTST (chan); - - /* The serial framework doesn't really use these - membase/mapbase fields for anything useful, but - it requires that they be something non-zero to - consider the port `valid', and also uses them - for informational purposes. */ - port->membase = (void *)NB85E_UART_BASE_ADDR (chan); - port->mapbase = NB85E_UART_BASE_ADDR (chan); - - /* The framework insists on knowing the uart's master - clock freq, though it doesn't seem to do anything - useful for us with it. We must make it at least - higher than (the maximum baud rate * 16), otherwise - the framework will puke during its internal - calculations, and force the baud rate to be 9600. - To be accurate though, just repeat the calculation - we use when actually setting the speed. - - The `* 8' means `* 16 / 2': 16 to account for for - the serial framework's built-in bias, and 2 because - there's an additional / 2 in the hardware. */ - port->uartclk = - (NB85E_UART_BASE_FREQ >> cksr_min()) * 8; - - uart_add_one_port (&nb85e_uart_driver, port); - } - } - - return rval; -} - -static void __exit nb85e_uart_exit (void) -{ - unsigned chan; - - for (chan = 0; chan < NB85E_UART_NUM_CHANNELS; chan++) - uart_remove_one_port (&nb85e_uart_driver, - &nb85e_uart_ports[chan]); - - uart_unregister_driver (&nb85e_uart_driver); -} - -module_init (nb85e_uart_init); -module_exit (nb85e_uart_exit); - -MODULE_AUTHOR ("Miles Bader"); -MODULE_DESCRIPTION ("NEC " NB85E_UART_CHIP_NAME " on-chip UART"); -MODULE_LICENSE ("GPL"); diff -Nru a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c --- a/drivers/serial/sunsu.c Sun Jul 27 10:13:42 2003 +++ b/drivers/serial/sunsu.c Sun Jul 27 10:13:42 2003 @@ -86,7 +86,7 @@ struct uart_port port; unsigned char acr; unsigned char ier; - unsigned char rev; + unsigned short rev; unsigned char lcr; unsigned int lsr_break_flag; unsigned int cflag; @@ -102,6 +102,7 @@ int l1_down; #ifdef CONFIG_SERIO struct serio serio; + int serio_open; #endif }; @@ -1021,12 +1022,13 @@ static int sunsu_serio_open(struct serio *serio) { + struct uart_sunsu_port *up = serio->driver; unsigned long flags; int ret; spin_lock_irqsave(&sunsu_serio_lock, flags); - if (serio->private == NULL) { - serio->private = (void *) -1L; + if (!up->serio_open) { + up->serio_open = 1; ret = 0; } else ret = -EBUSY; @@ -1037,10 +1039,11 @@ static void sunsu_serio_close(struct serio *serio) { + struct uart_sunsu_port *up = serio->driver; unsigned long flags; spin_lock_irqsave(&sunsu_serio_lock, flags); - serio->private = NULL; + up->serio_open = 0; spin_unlock_irqrestore(&sunsu_serio_lock, flags); } diff -Nru a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c --- a/drivers/serial/sunzilog.c Sun Jul 27 10:13:52 2003 +++ b/drivers/serial/sunzilog.c Sun Jul 27 10:13:52 2003 @@ -112,6 +112,7 @@ #ifdef CONFIG_SERIO struct serio serio; + int serio_open; #endif }; @@ -1311,12 +1312,13 @@ static int sunzilog_serio_open(struct serio *serio) { + struct uart_sunzilog_port *up = serio->driver; unsigned long flags; int ret; spin_lock_irqsave(&sunzilog_serio_lock, flags); - if (serio->private == NULL) { - serio->private = (void *) -1L; + if (!up->serio_open) { + up->serio_open = 1; ret = 0; } else ret = -EBUSY; @@ -1327,10 +1329,11 @@ static void sunzilog_serio_close(struct serio *serio) { + struct uart_sunzilog_port *up = serio->driver; unsigned long flags; spin_lock_irqsave(&sunzilog_serio_lock, flags); - serio->private = NULL; + up->serio_open = 0; spin_unlock_irqrestore(&sunzilog_serio_lock, flags); } diff -Nru a/drivers/serial/v850e_uart.c b/drivers/serial/v850e_uart.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/serial/v850e_uart.c Sun Jul 27 10:13:50 2003 @@ -0,0 +1,549 @@ +/* + * drivers/serial/v850e_uart.c -- Serial I/O using V850E on-chip UART or UARTB + * + * Copyright (C) 2001,02,03 NEC Electronics Corporation + * Copyright (C) 2001,02,03 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +/* This driver supports both the original V850E UART interface (called + merely `UART' in the docs) and the newer `UARTB' interface, which is + roughly a superset of the first one. The selection is made at + configure time -- if CONFIG_V850E_UARTB is defined, then UARTB is + presumed, otherwise the old UART -- as these are on-CPU UARTS, a system + can never have both. + + The UARTB interface also has a 16-entry FIFO mode, which is not + yet supported by this driver. */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* Initial UART state. This may be overridden by machine-dependent headers. */ +#ifndef V850E_UART_INIT_BAUD +#define V850E_UART_INIT_BAUD 115200 +#endif +#ifndef V850E_UART_INIT_CFLAGS +#define V850E_UART_INIT_CFLAGS (B115200 | CS8 | CREAD) +#endif + +/* A string used for prefixing printed descriptions; since the same UART + macro is actually used on other chips than the V850E. This must be a + constant string. */ +#ifndef V850E_UART_CHIP_NAME +#define V850E_UART_CHIP_NAME "V850E" +#endif + +#define V850E_UART_MINOR_BASE 64 /* First tty minor number */ + + +/* Low-level UART functions. */ + +/* Configure and turn on uart channel CHAN, using the termios `control + modes' bits in CFLAGS, and a baud-rate of BAUD. */ +void v850e_uart_configure (unsigned chan, unsigned cflags, unsigned baud) +{ + int flags; + v850e_uart_speed_t old_speed; + v850e_uart_config_t old_config; + v850e_uart_speed_t new_speed = v850e_uart_calc_speed (baud); + v850e_uart_config_t new_config = v850e_uart_calc_config (cflags); + + /* Disable interrupts while we're twiddling the hardware. */ + local_irq_save (flags); + +#ifdef V850E_UART_PRE_CONFIGURE + V850E_UART_PRE_CONFIGURE (chan, cflags, baud); +#endif + + old_config = V850E_UART_CONFIG (chan); + old_speed = v850e_uart_speed (chan); + + if (! v850e_uart_speed_eq (old_speed, new_speed)) { + /* The baud rate has changed. First, disable the UART. */ + V850E_UART_CONFIG (chan) = V850E_UART_CONFIG_FINI; + old_config = 0; /* Force the uart to be re-initialized. */ + + /* Reprogram the baud-rate generator. */ + v850e_uart_set_speed (chan, new_speed); + } + + if (! (old_config & V850E_UART_CONFIG_ENABLED)) { + /* If we are using the uart for the first time, start by + enabling it, which must be done before turning on any + other bits. */ + V850E_UART_CONFIG (chan) = V850E_UART_CONFIG_INIT; + /* See the initial state. */ + old_config = V850E_UART_CONFIG (chan); + } + + if (new_config != old_config) { + /* Which of the TXE/RXE bits we'll temporarily turn off + before changing other control bits. */ + unsigned temp_disable = 0; + /* Which of the TXE/RXE bits will be enabled. */ + unsigned enable = 0; + unsigned changed_bits = new_config ^ old_config; + + /* Which of RX/TX will be enabled in the new configuration. */ + if (new_config & V850E_UART_CONFIG_RX_BITS) + enable |= (new_config & V850E_UART_CONFIG_RX_ENABLE); + if (new_config & V850E_UART_CONFIG_TX_BITS) + enable |= (new_config & V850E_UART_CONFIG_TX_ENABLE); + + /* Figure out which of RX/TX needs to be disabled; note + that this will only happen if they're not already + disabled. */ + if (changed_bits & V850E_UART_CONFIG_RX_BITS) + temp_disable + |= (old_config & V850E_UART_CONFIG_RX_ENABLE); + if (changed_bits & V850E_UART_CONFIG_TX_BITS) + temp_disable + |= (old_config & V850E_UART_CONFIG_TX_ENABLE); + + /* We have to turn off RX and/or TX mode before changing + any associated control bits. */ + if (temp_disable) + V850E_UART_CONFIG (chan) = old_config & ~temp_disable; + + /* Write the new control bits, while RX/TX are disabled. */ + if (changed_bits & ~enable) + V850E_UART_CONFIG (chan) = new_config & ~enable; + + v850e_uart_config_delay (new_config, new_speed); + + /* Write the final version, with enable bits turned on. */ + V850E_UART_CONFIG (chan) = new_config; + } + + local_irq_restore (flags); +} + + +/* Low-level console. */ + +#ifdef CONFIG_V850E_UART_CONSOLE + +static void v850e_uart_cons_write (struct console *co, + const char *s, unsigned count) +{ + if (count > 0) { + unsigned chan = co->index; + unsigned irq = V850E_UART_TX_IRQ (chan); + int irq_was_enabled, irq_was_pending, flags; + + /* We don't want to get `transmission completed' + interrupts, since we're busy-waiting, so we disable them + while sending (we don't disable interrupts entirely + because sending over a serial line is really slow). We + save the status of the tx interrupt and restore it when + we're done so that using printk doesn't interfere with + normal serial transmission (other than interleaving the + output, of course!). This should work correctly even if + this function is interrupted and the interrupt printks + something. */ + + /* Disable interrupts while fiddling with tx interrupt. */ + local_irq_save (flags); + /* Get current tx interrupt status. */ + irq_was_enabled = v850e_intc_irq_enabled (irq); + irq_was_pending = v850e_intc_irq_pending (irq); + /* Disable tx interrupt if necessary. */ + if (irq_was_enabled) + v850e_intc_disable_irq (irq); + /* Turn interrupts back on. */ + local_irq_restore (flags); + + /* Send characters. */ + while (count > 0) { + int ch = *s++; + + if (ch == '\n') { + /* We don't have the benefit of a tty + driver, so translate NL into CR LF. */ + v850e_uart_wait_for_xmit_ok (chan); + v850e_uart_putc (chan, '\r'); + } + + v850e_uart_wait_for_xmit_ok (chan); + v850e_uart_putc (chan, ch); + + count--; + } + + /* Restore saved tx interrupt status. */ + if (irq_was_enabled) { + /* Wait for the last character we sent to be + completely transmitted (as we'll get an + interrupt interrupt at that point). */ + v850e_uart_wait_for_xmit_done (chan); + /* Clear pending interrupts received due + to our transmission, unless there was already + one pending, in which case we want the + handler to be called. */ + if (! irq_was_pending) + v850e_intc_clear_pending_irq (irq); + /* ... and then turn back on handling. */ + v850e_intc_enable_irq (irq); + } + } +} + +extern struct uart_driver v850e_uart_driver; +static struct console v850e_uart_cons = +{ + .name = "ttyS", + .write = v850e_uart_cons_write, + .device = uart_console_device, + .flags = CON_PRINTBUFFER, + .cflag = V850E_UART_INIT_CFLAGS, + .index = -1, + .data = &v850e_uart_driver, +}; + +void v850e_uart_cons_init (unsigned chan) +{ + v850e_uart_configure (chan, V850E_UART_INIT_CFLAGS, + V850E_UART_INIT_BAUD); + v850e_uart_cons.index = chan; + register_console (&v850e_uart_cons); + printk ("Console: %s on-chip UART channel %d\n", + V850E_UART_CHIP_NAME, chan); +} + +/* This is what the init code actually calls. */ +static int v850e_uart_console_init (void) +{ + v850e_uart_cons_init (V850E_UART_CONSOLE_CHANNEL); + return 0; +} +console_initcall(v850e_uart_console_init); + +#define V850E_UART_CONSOLE &v850e_uart_cons + +#else /* !CONFIG_V850E_UART_CONSOLE */ +#define V850E_UART_CONSOLE 0 +#endif /* CONFIG_V850E_UART_CONSOLE */ + +/* TX/RX interrupt handlers. */ + +static void v850e_uart_stop_tx (struct uart_port *port, unsigned tty_stop); + +void v850e_uart_tx (struct uart_port *port) +{ + struct circ_buf *xmit = &port->info->xmit; + int stopped = uart_tx_stopped (port); + + if (v850e_uart_xmit_ok (port->line)) { + int tx_ch; + + if (port->x_char) { + tx_ch = port->x_char; + port->x_char = 0; + } else if (!uart_circ_empty (xmit) && !stopped) { + tx_ch = xmit->buf[xmit->tail]; + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + } else + goto no_xmit; + + v850e_uart_putc (port->line, tx_ch); + port->icount.tx++; + + if (uart_circ_chars_pending (xmit) < WAKEUP_CHARS) + uart_write_wakeup (port); + } + + no_xmit: + if (uart_circ_empty (xmit) || stopped) + v850e_uart_stop_tx (port, stopped); +} + +static irqreturn_t v850e_uart_tx_irq(int irq, void *data, struct pt_regs *regs) +{ + struct uart_port *port = data; + v850e_uart_tx (port); + return IRQ_HANDLED; +} + +static irqreturn_t v850e_uart_rx_irq(int irq, void *data, struct pt_regs *regs) +{ + struct uart_port *port = data; + unsigned ch_stat = TTY_NORMAL; + unsigned ch = v850e_uart_getc (port->line); + unsigned err = v850e_uart_err (port->line); + + if (err) { + if (err & V850E_UART_ERR_OVERRUN) { + ch_stat = TTY_OVERRUN; + port->icount.overrun++; + } else if (err & V850E_UART_ERR_FRAME) { + ch_stat = TTY_FRAME; + port->icount.frame++; + } else if (err & V850E_UART_ERR_PARITY) { + ch_stat = TTY_PARITY; + port->icount.parity++; + } + } + + port->icount.rx++; + + tty_insert_flip_char (port->info->tty, ch, ch_stat); + tty_schedule_flip (port->info->tty); + + return IRQ_HANDLED; +} + + +/* Control functions for the serial framework. */ + +static void v850e_uart_nop (struct uart_port *port) { } +static int v850e_uart_success (struct uart_port *port) { return 0; } + +static unsigned v850e_uart_tx_empty (struct uart_port *port) +{ + return TIOCSER_TEMT; /* Can't detect. */ +} + +static void v850e_uart_set_mctrl (struct uart_port *port, unsigned mctrl) +{ +#ifdef V850E_UART_SET_RTS + V850E_UART_SET_RTS (port->line, (mctrl & TIOCM_RTS)); +#endif +} + +static unsigned v850e_uart_get_mctrl (struct uart_port *port) +{ + /* We don't support DCD or DSR, so consider them permanently active. */ + int mctrl = TIOCM_CAR | TIOCM_DSR; + + /* We may support CTS. */ +#ifdef V850E_UART_CTS + mctrl |= V850E_UART_CTS(port->line) ? TIOCM_CTS : 0; +#else + mctrl |= TIOCM_CTS; +#endif + + return mctrl; +} + +static void v850e_uart_start_tx (struct uart_port *port, unsigned tty_start) +{ + v850e_intc_disable_irq (V850E_UART_TX_IRQ (port->line)); + v850e_uart_tx (port); + v850e_intc_enable_irq (V850E_UART_TX_IRQ (port->line)); +} + +static void v850e_uart_stop_tx (struct uart_port *port, unsigned tty_stop) +{ + v850e_intc_disable_irq (V850E_UART_TX_IRQ (port->line)); +} + +static void v850e_uart_start_rx (struct uart_port *port) +{ + v850e_intc_enable_irq (V850E_UART_RX_IRQ (port->line)); +} + +static void v850e_uart_stop_rx (struct uart_port *port) +{ + v850e_intc_disable_irq (V850E_UART_RX_IRQ (port->line)); +} + +static void v850e_uart_break_ctl (struct uart_port *port, int break_ctl) +{ + /* Umm, do this later. */ +} + +static int v850e_uart_startup (struct uart_port *port) +{ + int err; + + /* Alloc RX irq. */ + err = request_irq (V850E_UART_RX_IRQ (port->line), v850e_uart_rx_irq, + SA_INTERRUPT, "v850e_uart", port); + if (err) + return err; + + /* Alloc TX irq. */ + err = request_irq (V850E_UART_TX_IRQ (port->line), v850e_uart_tx_irq, + SA_INTERRUPT, "v850e_uart", port); + if (err) { + free_irq (V850E_UART_RX_IRQ (port->line), port); + return err; + } + + v850e_uart_start_rx (port); + + return 0; +} + +static void v850e_uart_shutdown (struct uart_port *port) +{ + /* Disable port interrupts. */ + free_irq (V850E_UART_TX_IRQ (port->line), port); + free_irq (V850E_UART_RX_IRQ (port->line), port); + + /* Turn off xmit/recv enable bits. */ + V850E_UART_CONFIG (port->line) + &= ~(V850E_UART_CONFIG_TX_ENABLE + | V850E_UART_CONFIG_RX_ENABLE); + /* Then reset the channel. */ + V850E_UART_CONFIG (port->line) = 0; +} + +static void +v850e_uart_set_termios (struct uart_port *port, struct termios *termios, + struct termios *old) +{ + unsigned cflags = termios->c_cflag; + + /* Restrict flags to legal values. */ + if ((cflags & CSIZE) != CS7 && (cflags & CSIZE) != CS8) + /* The new value of CSIZE is invalid, use the old value. */ + cflags = (cflags & ~CSIZE) + | (old ? (old->c_cflag & CSIZE) : CS8); + + termios->c_cflag = cflags; + + v850e_uart_configure (port->line, cflags, + uart_get_baud_rate (port, termios, old, + v850e_uart_min_baud(), + v850e_uart_max_baud())); +} + +static const char *v850e_uart_type (struct uart_port *port) +{ + return port->type == PORT_V850E_UART ? "v850e_uart" : 0; +} + +static void v850e_uart_config_port (struct uart_port *port, int flags) +{ + if (flags & UART_CONFIG_TYPE) + port->type = PORT_V850E_UART; +} + +static int +v850e_uart_verify_port (struct uart_port *port, struct serial_struct *ser) +{ + if (ser->type != PORT_UNKNOWN && ser->type != PORT_V850E_UART) + return -EINVAL; + if (ser->irq != V850E_UART_TX_IRQ (port->line)) + return -EINVAL; + return 0; +} + +static struct uart_ops v850e_uart_ops = { + .tx_empty = v850e_uart_tx_empty, + .get_mctrl = v850e_uart_get_mctrl, + .set_mctrl = v850e_uart_set_mctrl, + .start_tx = v850e_uart_start_tx, + .stop_tx = v850e_uart_stop_tx, + .stop_rx = v850e_uart_stop_rx, + .enable_ms = v850e_uart_nop, + .break_ctl = v850e_uart_break_ctl, + .startup = v850e_uart_startup, + .shutdown = v850e_uart_shutdown, + .set_termios = v850e_uart_set_termios, + .type = v850e_uart_type, + .release_port = v850e_uart_nop, + .request_port = v850e_uart_success, + .config_port = v850e_uart_config_port, + .verify_port = v850e_uart_verify_port, +}; + +/* Initialization and cleanup. */ + +static struct uart_driver v850e_uart_driver = { + .owner = THIS_MODULE, + .driver_name = "v850e_uart", + .devfs_name = "tts/", + .dev_name = "ttyS", + .major = TTY_MAJOR, + .minor = V850E_UART_MINOR_BASE, + .nr = V850E_UART_NUM_CHANNELS, + .cons = V850E_UART_CONSOLE, +}; + + +static struct uart_port v850e_uart_ports[V850E_UART_NUM_CHANNELS]; + +static int __init v850e_uart_init (void) +{ + int rval; + + printk (KERN_INFO "%s on-chip UART\n", V850E_UART_CHIP_NAME); + + rval = uart_register_driver (&v850e_uart_driver); + if (rval == 0) { + unsigned chan; + + for (chan = 0; chan < V850E_UART_NUM_CHANNELS; chan++) { + struct uart_port *port = &v850e_uart_ports[chan]; + + memset (port, 0, sizeof *port); + + port->ops = &v850e_uart_ops; + port->line = chan; + port->iotype = SERIAL_IO_MEM; + port->flags = UPF_BOOT_AUTOCONF; + + /* We actually use multiple IRQs, but the serial + framework seems to mainly use this for + informational purposes anyway. Here we use the TX + irq. */ + port->irq = V850E_UART_TX_IRQ (chan); + + /* The serial framework doesn't really use these + membase/mapbase fields for anything useful, but + it requires that they be something non-zero to + consider the port `valid', and also uses them + for informational purposes. */ + port->membase = (void *)V850E_UART_BASE_ADDR (chan); + port->mapbase = V850E_UART_BASE_ADDR (chan); + + /* The framework insists on knowing the uart's master + clock freq, though it doesn't seem to do anything + useful for us with it. We must make it at least + higher than (the maximum baud rate * 16), otherwise + the framework will puke during its internal + calculations, and force the baud rate to be 9600. + To be accurate though, just repeat the calculation + we use when actually setting the speed. */ + port->uartclk = v850e_uart_max_clock() * 16; + + uart_add_one_port (&v850e_uart_driver, port); + } + } + + return rval; +} + +static void __exit v850e_uart_exit (void) +{ + unsigned chan; + + for (chan = 0; chan < V850E_UART_NUM_CHANNELS; chan++) + uart_remove_one_port (&v850e_uart_driver, + &v850e_uart_ports[chan]); + + uart_unregister_driver (&v850e_uart_driver); +} + +module_init (v850e_uart_init); +module_exit (v850e_uart_exit); + +MODULE_AUTHOR ("Miles Bader"); +MODULE_DESCRIPTION ("NEC " V850E_UART_CHIP_NAME " on-chip UART"); +MODULE_LICENSE ("GPL"); diff -Nru a/drivers/telephony/Kconfig b/drivers/telephony/Kconfig --- a/drivers/telephony/Kconfig Sun Jul 27 10:13:42 2003 +++ b/drivers/telephony/Kconfig Sun Jul 27 10:13:42 2003 @@ -39,7 +39,7 @@ config PHONE_IXJ_PCMCIA tristate "QuickNet Internet LineJack/PhoneJack PCMCIA support" - depends on PHONE_IXJ + depends on PHONE_IXJ && PCMCIA help Say Y here to configure in PCMCIA service support for the Quicknet cards manufactured by Quicknet Technologies, Inc. This changes the diff -Nru a/drivers/telephony/ixj.c b/drivers/telephony/ixj.c --- a/drivers/telephony/ixj.c Sun Jul 27 10:13:40 2003 +++ b/drivers/telephony/ixj.c Sun Jul 27 10:13:40 2003 @@ -23,6 +23,7 @@ * Fixes: David Huggins-Daines, * Fabio Ferrari, * Artis Kugevics, + * Daniele Bellucci, * * More information about the hardware related to this driver can be found * at our website: http://www.quicknet.net @@ -45,6 +46,10 @@ /* * $Log: ixj.c,v $ + * + * Revision 4.8 2003/07/09 19:39:00 Daniele Bellucci + * Audit some copy_*_user and minor cleanup. + * * Revision 4.7 2001/08/13 06:19:33 craigs * Added additional changes from Alan Cox and John Anderson for * 2.2 to 2.4 cleanup and bounds checking @@ -363,12 +368,9 @@ static IXJ *ixj_alloc(void) { int cnt; - for(cnt=0; cntcid_send, (char *)arg, sizeof(PHONE_CID)); - } - else { + if (copy_from_user(&j->cid_send, (char *)arg, sizeof(PHONE_CID))) { + retval = -EFAULT; + break; + } + } else { memset(&j->cid_send, 0, sizeof(PHONE_CID)); } ixj_write_cidcw(j); @@ -6273,14 +6277,12 @@ /* Fall through */ case PHONE_RING_START: if(arg) { - if(copy_from_user(&j->cid_send, (char *)arg, sizeof(PHONE_CID))) - { + if (copy_from_user(&j->cid_send, (char *)arg, sizeof(PHONE_CID))) { retval = -EFAULT; break; } ixj_write_cid(j); - } - else { + } else { memset(&j->cid_send, 0, sizeof(PHONE_CID)); } ixj_ring_start(j); @@ -6696,7 +6698,8 @@ case IXJCTL_SET_FILTER_RAW: if (copy_from_user(&jfr, (char *) arg, sizeof(jfr))) retval = -EFAULT; - retval = ixj_init_filter_raw(j, &jfr); + else + retval = ixj_init_filter_raw(j, &jfr); break; case IXJCTL_GET_FILTER_HIST: if(arg<0||arg>3) @@ -6705,8 +6708,10 @@ retval = j->filter_hist[arg]; break; case IXJCTL_INIT_TONE: - copy_from_user(&ti, (char *) arg, sizeof(ti)); - retval = ixj_init_tone(j, &ti); + if (copy_from_user(&ti, (char *) arg, sizeof(ti))) + retval = -EFAULT; + else + retval = ixj_init_tone(j, &ti); break; case IXJCTL_TONE_CADENCE: retval = ixj_build_cadence(j, (IXJ_CADENCE *) arg); @@ -6715,8 +6720,10 @@ retval = ixj_build_filter_cadence(j, (IXJ_FILTER_CADENCE *) arg); break; case IXJCTL_SIGCTL: - if (copy_from_user(&j->sigdef, (char *)arg, sizeof(IXJ_SIGDEF))) + if (copy_from_user(&j->sigdef, (char *)arg, sizeof(IXJ_SIGDEF))) { retval = -EFAULT; + break; + } j->ixj_signals[j->sigdef.event] = j->sigdef.signal; if(j->sigdef.event < 33) { raise = 1; @@ -7693,7 +7700,7 @@ MODULE_AUTHOR("Ed Okerson "); MODULE_LICENSE("GPL"); -void ixj_exit(void) +static void __exit ixj_exit(void) { cleanup(); } @@ -7852,7 +7859,7 @@ return probe; } -int __init ixj_init(void) +static int __init ixj_init(void) { int cnt = 0; int probe = 0; diff -Nru a/drivers/usb/class/bluetty.c b/drivers/usb/class/bluetty.c --- a/drivers/usb/class/bluetty.c Sun Jul 27 10:13:49 2003 +++ b/drivers/usb/class/bluetty.c Sun Jul 27 10:13:49 2003 @@ -1320,7 +1320,8 @@ bluetooth_tty_driver->owner = THIS_MODULE; bluetooth_tty_driver->driver_name = "usb-bluetooth"; - bluetooth_tty_driver->name = "usb/ttub/"; + bluetooth_tty_driver->name = "ttyUB"; + bluetooth_tty_driver->devfs_name = "usb/ttub/"; bluetooth_tty_driver->major = BLUETOOTH_TTY_MAJOR; bluetooth_tty_driver->minor_start = 0; bluetooth_tty_driver->type = TTY_DRIVER_TYPE_SERIAL; diff -Nru a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c --- a/drivers/usb/class/cdc-acm.c Sun Jul 27 10:13:48 2003 +++ b/drivers/usb/class/cdc-acm.c Sun Jul 27 10:13:48 2003 @@ -765,7 +765,8 @@ return -ENOMEM; acm_tty_driver->owner = THIS_MODULE, acm_tty_driver->driver_name = "acm", - acm_tty_driver->name = "usb/acm/", + acm_tty_driver->name = "ttyACM", + acm_tty_driver->devfs_name = "usb/acm/", acm_tty_driver->major = ACM_TTY_MAJOR, acm_tty_driver->minor_start = 0, acm_tty_driver->type = TTY_DRIVER_TYPE_SERIAL, diff -Nru a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c --- a/drivers/usb/class/usblp.c Sun Jul 27 10:13:42 2003 +++ b/drivers/usb/class/usblp.c Sun Jul 27 10:13:42 2003 @@ -359,7 +359,6 @@ file->private_data = usblp; usblp->writeurb->transfer_buffer_length = 0; - usblp->writeurb->status = 0; usblp->wcomplete = 1; /* we begin writeable */ usblp->rcomplete = 0; @@ -833,22 +832,15 @@ init_waitqueue_head(&usblp->wait); usblp->ifnum = intf->altsetting->desc.bInterfaceNumber; - retval = usb_register_dev(intf, &usblp_class); - if (retval) { - err("Not able to get a minor for this device."); - goto abort; - } - usblp->minor = intf->minor; - usblp->writeurb = usb_alloc_urb(0, GFP_KERNEL); if (!usblp->writeurb) { err("out of memory"); - goto abort_minor; + goto abort; } usblp->readurb = usb_alloc_urb(0, GFP_KERNEL); if (!usblp->readurb) { err("out of memory"); - goto abort_minor; + goto abort; } /* Malloc device ID string buffer to the largest expected length, @@ -856,7 +848,7 @@ * could change in length. */ if (!(usblp->device_id_string = kmalloc(USBLP_DEVICE_ID_SIZE, GFP_KERNEL))) { err("out of memory for device_id_string"); - goto abort_minor; + goto abort; } usblp->writebuf = usblp->readbuf = NULL; @@ -868,19 +860,19 @@ if (!(usblp->writebuf = usb_buffer_alloc(dev, USBLP_BUF_SIZE, GFP_KERNEL, &usblp->writeurb->transfer_dma))) { err("out of memory for write buf"); - goto abort_minor; + goto abort; } if (!(usblp->readbuf = usb_buffer_alloc(dev, USBLP_BUF_SIZE, GFP_KERNEL, &usblp->readurb->transfer_dma))) { err("out of memory for read buf"); - goto abort_minor; + goto abort; } /* Allocate buffer for printer status */ usblp->statusbuf = kmalloc(STATUS_BUF_SIZE, GFP_KERNEL); if (!usblp->statusbuf) { err("out of memory for statusbuf"); - goto abort_minor; + goto abort; } /* Lookup quirks for this printer. */ @@ -894,12 +886,12 @@ dbg("incompatible printer-class device 0x%4.4X/0x%4.4X", dev->descriptor.idVendor, dev->descriptor.idProduct); - goto abort_minor; + goto abort; } /* Setup the selected alternate setting and endpoints. */ if (usblp_set_protocol(usblp, protocol) < 0) - goto abort_minor; + goto abort; /* Retrieve and store the device ID string. */ usblp_cache_device_id_string(usblp); @@ -920,10 +912,17 @@ usblp->present = 1; + retval = usb_register_dev(intf, &usblp_class); + if (retval) { + err("Not able to get a minor for this device."); + goto abort_intfdata; + } + usblp->minor = intf->minor; + return 0; -abort_minor: - usb_deregister_dev(intf, &usblp_class); +abort_intfdata: + usb_set_intfdata (intf, NULL); abort: if (usblp) { if (usblp->writebuf) diff -Nru a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c --- a/drivers/usb/core/hcd-pci.c Sun Jul 27 10:13:45 2003 +++ b/drivers/usb/core/hcd-pci.c Sun Jul 27 10:13:45 2003 @@ -81,7 +81,7 @@ if (!dev->irq) { err ("Found HC with no IRQ. Check BIOS/PCI %s setup!", - dev->slot_name); + pci_name(dev)); return -ENODEV; } @@ -99,7 +99,7 @@ retval = -EFAULT; clean_1: release_mem_region (resource, len); - err ("init %s fail, %d", dev->slot_name, retval); + err ("init %s fail, %d", pci_name(dev), retval); return retval; } @@ -136,7 +136,7 @@ goto clean_1; } else { release_region (resource, len); - err ("init %s fail, %d", dev->slot_name, retval); + err ("init %s fail, %d", pci_name(dev), retval); return retval; } } @@ -144,7 +144,7 @@ hcd->driver = driver; hcd->description = driver->description; hcd->pdev = dev; - hcd->self.bus_name = dev->slot_name; + hcd->self.bus_name = pci_name(dev); hcd->product_desc = dev->dev.name; hcd->self.controller = &dev->dev; hcd->controller = hcd->self.controller; @@ -279,6 +279,7 @@ /** * usb_hcd_pci_suspend - power management suspend of a PCI-based HCD * @dev: USB Host Controller being suspended + * @state: state that the controller is going into * * Store this function in the HCD's struct pci_driver as suspend(). */ diff -Nru a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c --- a/drivers/usb/core/hcd.c Sun Jul 27 10:13:47 2003 +++ b/drivers/usb/core/hcd.c Sun Jul 27 10:13:47 2003 @@ -1293,7 +1293,8 @@ } /* then kill any current requests */ - spin_lock_irqsave (&hcd_data_lock, flags); + local_irq_save (flags); + spin_lock (&hcd_data_lock); list_for_each_entry (urb, &dev->urb_list, urb_list) { int tmp = urb->pipe; @@ -1311,13 +1312,13 @@ if (urb->status != -EINPROGRESS) continue; usb_get_urb (urb); - spin_unlock_irqrestore (&hcd_data_lock, flags); + spin_unlock (&hcd_data_lock); - spin_lock_irqsave (&urb->lock, flags); + spin_lock (&urb->lock); tmp = urb->status; if (tmp == -EINPROGRESS) urb->status = -ESHUTDOWN; - spin_unlock_irqrestore (&urb->lock, flags); + spin_unlock (&urb->lock); /* kick hcd unless it's already returning this */ if (tmp == -EINPROGRESS) { @@ -1340,7 +1341,8 @@ /* list contents may have changed */ goto rescan; } - spin_unlock_irqrestore (&hcd_data_lock, flags); + spin_unlock (&hcd_data_lock); + local_irq_restore (flags); /* synchronize with the hardware, so old configuration state * clears out immediately (and will be freed). diff -Nru a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c --- a/drivers/usb/core/usb.c Sun Jul 27 10:13:45 2003 +++ b/drivers/usb/core/usb.c Sun Jul 27 10:13:45 2003 @@ -80,6 +80,23 @@ static int usb_generic_driver_data; +/* deallocate hcd/hardware state ... and nuke all pending urbs */ +static void nuke_urbs(struct usb_device *dev) +{ + void (*disable)(struct usb_device *, int); + int i; + + if (!dev || !dev->bus || !dev->bus->op || !dev->bus->op->disable) + return; + dbg("nuking urbs assigned to %s", dev->dev.bus_id); + + disable = dev->bus->op->disable; + for (i = 0; i < 15; i++) { + disable(dev, i); + disable(dev, USB_DIR_IN | i); + } +} + /* needs to be called with BKL held */ int usb_device_probe(struct device *dev) { @@ -116,6 +133,9 @@ down(&driver->serialize); + /* release all urbs for this device */ + nuke_urbs(interface_to_usbdev(intf)); + if (intf->driver && intf->driver->disconnect) intf->driver->disconnect(intf); @@ -896,6 +916,9 @@ usb_disconnect(child); } + /* deallocate hcd/hardware state ... and nuke all pending urbs */ + nuke_urbs(dev); + /* disconnect() drivers from interfaces (a key side effect) */ dev_dbg (&dev->dev, "unregistering interfaces\n"); if (dev->actconfig) { @@ -905,16 +928,6 @@ /* remove this interface */ interface = &dev->actconfig->interface[i]; device_unregister(&interface->dev); - } - } - - /* deallocate hcd/hardware state */ - if (ops->disable) { - void (*disable)(struct usb_device *, int) = ops->disable; - - for (i = 0; i < 15; i++) { - disable (dev, i); - disable (dev, USB_DIR_IN | i); } } diff -Nru a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c --- a/drivers/usb/gadget/ether.c Sun Jul 27 10:13:52 2003 +++ b/drivers/usb/gadget/ether.c Sun Jul 27 10:13:52 2003 @@ -1,5 +1,5 @@ /* - * ether.c -- CDC 1.1 Ethernet gadget driver + * ether.c -- Ethernet gadget driver, with CDC and non-CDC options * * Copyright (C) 2003 David Brownell * @@ -58,21 +58,23 @@ /*-------------------------------------------------------------------------*/ /* - * "Communications Device Class" (CDC) Ethernet class driver + * Ethernet gadget driver -- with CDC and non-CDC options * * CDC Ethernet is the standard USB solution for sending Ethernet frames * using USB. Real hardware tends to use the same framing protocol but look * different for control features. And Microsoft pushes their own approach * (RNDIS) instead of the standard. + * + * There's some hardware that can't talk CDC. We make that hardware + * implement a "minimalist" vendor-agnostic CDC core: same framing, but + * link-level setup only requires activating the configuration. */ -#define DRIVER_DESC "CDC Ethernet Gadget" -#define DRIVER_VERSION "29 April 2003" +#define DRIVER_DESC "Ethernet Gadget" +#define DRIVER_VERSION "Bastille Day 2003" static const char shortname [] = "ether"; static const char driver_desc [] = DRIVER_DESC; -static const char control_name [] = "Communications Control"; -static const char data_name [] = "CDC Ethernet Data"; #define MIN_PACKET sizeof(struct ethhdr) #define MAX_PACKET ETH_DATA_LEN /* biggest packet we'll rx/tx */ @@ -92,8 +94,7 @@ const struct usb_endpoint_descriptor *in, *out, *status; - struct semaphore mutex; - struct net_device net; + struct net_device *net; struct net_device_stats stats; atomic_t tx_qlen; @@ -112,7 +113,7 @@ static unsigned qmult = 4; -#define HS_FACTOR 15 +#define HS_FACTOR 5 #define qlen(gadget) \ (qmult*((gadget->speed == USB_SPEED_HIGH) ? HS_FACTOR : 1)) @@ -128,7 +129,7 @@ /* Thanks to NetChip Technologies for donating this product ID. * - * DO NOT REUSE THESE IDs with any other driver!! Ever!! + * DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!! * Instead: allocate your own, using normal USB-IF procedures. */ #define DRIVER_VENDOR_NUM 0x0525 /* NetChip */ @@ -158,6 +159,11 @@ * for some reason doesn't handle full speed bulk maxpacket of 64. */ +#define DEV_CONFIG_VALUE 3 /* some hardware cares */ + +/* #undef on hardware that can't implement CDC */ +#define DEV_CONFIG_CDC + /* * NetChip 2280, PCI based. * @@ -172,7 +178,7 @@ #define DRIVER_VERSION_NUM 0x0101 #define EP0_MAXPACKET 64 static const char EP_OUT_NAME [] = "ep-a"; -#define EP_OUT_NUM 2 +#define EP_OUT_NUM 1 static const char EP_IN_NAME [] = "ep-b"; #define EP_IN_NUM 2 static const char EP_STATUS_NAME [] = "ep-f"; @@ -194,22 +200,21 @@ #endif /* - * PXA-250 UDC: widely used in second gen Linux-capable PDAs. + * PXA-2xx UDC: widely used in second gen Linux-capable ARM PDAs + * and other products. * - * no limitations except from set_interface: docs say "no" to a third - * interface. and the interrupt-only endpoints don't toggle, so we'll - * just use a bulk-capable one instead. + * multiple interfaces (or altsettings) aren't usable. so this hardware + * can't implement CDC, which needs both capabilities. */ -#ifdef CONFIG_USB_ETH_PXA250 -#define CHIP "pxa250" +#ifdef CONFIG_USB_ETH_PXA2XX +#undef DEV_CONFIG_CDC +#define CHIP "pxa2xx" #define DRIVER_VERSION_NUM 0x0103 #define EP0_MAXPACKET 16 -static const char EP_OUT_NAME [] = "ep12out-bulk"; -#define EP_OUT_NUM 12 -static const char EP_IN_NAME [] = "ep11in-bulk"; -#define EP_IN_NUM 11 -static const char EP_STATUS_NAME [] = "ep6in-bulk"; -#define EP_STATUS_NUM 6 +static const char EP_OUT_NAME [] = "ep2out-bulk"; +#define EP_OUT_NUM 2 +static const char EP_IN_NAME [] = "ep1in-bulk"; +#define EP_IN_NUM 1 /* doesn't support bus-powered operation */ #define SELFPOWER USB_CONFIG_ATT_SELFPOWER /* supports remote wakeup, but this driver doesn't */ @@ -247,6 +252,29 @@ # error Configure some USB peripheral controller driver! #endif +/* We normally expect hardware that can talk CDC. That involves + * using multiple interfaces and altsettings, and maybe a status + * interrupt. Driver binding to be done according to USB-IF class, + * though you can use different VENDOR and PRODUCT numbers if you + * want (and they're officially assigned). + * + * For hardware that can't talk CDC, we use the same vendor ID that + * ARM Linux has used for ethernet-over-usb, both with sa1100 and + * with pxa250. We're protocol-compatible, if the host-side drivers + * use the endpoint descriptors. DRIVER_VERSION_NUM is nonzero, so + * drivers that need to hard-wire endpoint numbers have a hook. + */ +#ifdef DEV_CONFIG_CDC +#define DEV_CONFIG_CLASS USB_CLASS_COMM +#else +#define DEV_CONFIG_CLASS USB_CLASS_VENDOR_SPEC +#undef EP_STATUS_NUM +#undef DRIVER_VENDOR_NUM +#undef DRIVER_PRODUCT_NUM +#define DRIVER_VENDOR_NUM 0x049f +#define DRIVER_PRODUCT_NUM 0x505a +#endif /* CONFIG_CDC_ETHER */ + /* power usage is config specific. * hardware that supports remote wakeup defaults to disabling it. */ @@ -274,7 +302,8 @@ /*-------------------------------------------------------------------------*/ #define xprintk(d,level,fmt,args...) \ - dev_printk(level , &(d)->gadget->dev , fmt , ## args) + printk(level "%s %s: " fmt , shortname , (d)->gadget->dev.bus_id , \ + ## args) #ifdef DEBUG #undef DEBUG @@ -309,7 +338,7 @@ /* * DESCRIPTORS ... most are static, but strings and (full) configuration * descriptors are built on demand. Notice how most of the cdc descriptors - * add no value to simple (typical) configurations. + * aren't needed in the "minimalist" mode. */ #define STRING_MANUFACTURER 1 @@ -323,15 +352,14 @@ /* * This device advertises one configuration. */ -#define CONFIG_CDC_ETHER 3 - static const struct usb_device_descriptor device_desc = { .bLength = sizeof device_desc, .bDescriptorType = USB_DT_DEVICE, .bcdUSB = __constant_cpu_to_le16 (0x0200), - .bDeviceClass = USB_CLASS_COMM, + + .bDeviceClass = DEV_CONFIG_CLASS, .bDeviceSubClass = 0, .bDeviceProtocol = 0, .bMaxPacketSize0 = EP0_MAXPACKET, @@ -350,13 +378,26 @@ .bDescriptorType = USB_DT_CONFIG, /* compute wTotalLength on the fly */ +#ifdef DEV_CONFIG_CDC .bNumInterfaces = 2, - .bConfigurationValue = CONFIG_CDC_ETHER, +#else + .bNumInterfaces = 1, +#endif + .bConfigurationValue = DEV_CONFIG_VALUE, .iConfiguration = STRING_PRODUCT, .bmAttributes = USB_CONFIG_ATT_ONE | SELFPOWER | WAKEUP, .bMaxPower = (MAX_USB_POWER + 1) / 2, }; +#ifdef DEV_CONFIG_CDC + +/* + * Compared to the "minimalist" non-CDC model, the CDC model adds + * three class descriptors, two interface descrioptors, and a status + * endpoint. Both have a "data" interface and two bulk endpoints. + * There are also differences in how control requests are handled. + */ + /* master comm interface optionally has a status notification endpoint */ static const struct usb_interface_descriptor @@ -446,7 +487,7 @@ * some drivers (like current Linux cdc-ether!) "need" it to exist even * if they ignore the connect/disconnect notifications that real aether * can provide. more advanced cdc configurations might want to support - * encapsulated commands. + * encapsulated commands (vendor-specific, using control-OUT). */ #define LOG2_STATUS_INTERVAL_MSEC 6 @@ -494,6 +535,29 @@ .bInterfaceProtocol = 0, .iInterface = STRING_DATA, }; +#else + +/* + * "Minimalist" non-CDC option is a simple vendor-neutral model that most + * full speed controllers can handle: one interface, two bulk endpoints. + */ + +static const struct usb_interface_descriptor +data_intf = { + .bLength = sizeof data_intf, + .bDescriptorType = USB_DT_INTERFACE, + + .bInterfaceNumber = 0, + .bAlternateSetting = 0, + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_VENDOR_SPEC, + .bInterfaceSubClass = 0, + .bInterfaceProtocol = 0, + .iInterface = STRING_DATA, +}; + +#endif /* DEV_CONFIG_CDC */ + static const struct usb_endpoint_descriptor fs_source_desc = { @@ -563,12 +627,12 @@ .bDescriptorType = USB_DT_DEVICE_QUALIFIER, .bcdUSB = __constant_cpu_to_le16 (0x0200), - .bDeviceClass = USB_CLASS_VENDOR_SPEC, + .bDeviceClass = DEV_CONFIG_CLASS, /* assumes ep0 uses the same value for both speeds ... */ .bMaxPacketSize0 = EP0_MAXPACKET, - .bNumConfigurations = 2, + .bNumConfigurations = 1, }; /* maxpacket and other transfer characteristics vary by speed. */ @@ -581,16 +645,24 @@ #endif /* !HIGHSPEED */ +/*-------------------------------------------------------------------------*/ + +/* descriptors that are built on-demand */ + +#ifdef DEV_CONFIG_CDC /* address that the host will use ... usually assigned at random */ static char ethaddr [2 * ETH_ALEN + 1]; +#endif /* static strings, in iso 8859/1 */ static struct usb_string strings [] = { { STRING_MANUFACTURER, UTS_SYSNAME " " UTS_RELEASE "/" CHIP, }, { STRING_PRODUCT, driver_desc, }, +#ifdef DEV_CONFIG_CDC { STRING_ETHADDR, ethaddr, }, - { STRING_CONTROL, control_name, }, - { STRING_DATA, data_name, }, + { STRING_CONTROL, "CDC Communications Control", }, +#endif + { STRING_DATA, "Ethernet Data", }, { } /* end of list */ }; @@ -607,14 +679,18 @@ config_buf (enum usb_device_speed speed, u8 *buf, u8 type, unsigned index) { const unsigned config_len = USB_DT_CONFIG_SIZE - + 3 * USB_DT_INTERFACE_SIZE +#ifdef DEV_CONFIG_CDC + + 2 * USB_DT_INTERFACE_SIZE + sizeof header_desc + sizeof union_desc + sizeof ether_desc #ifdef EP_STATUS_NUM + USB_DT_ENDPOINT_SIZE #endif +#endif /* DEV_CONFIG_CDC */ + + USB_DT_INTERFACE_SIZE + 2 * USB_DT_ENDPOINT_SIZE; + #ifdef HIGHSPEED int hs; #endif @@ -636,6 +712,7 @@ hs = !hs; #endif +#ifdef DEV_CONFIG_CDC /* control interface, class descriptors, optional status endpoint */ memcpy (buf, &control_intf, USB_DT_INTERFACE_SIZE); buf += USB_DT_INTERFACE_SIZE; @@ -660,6 +737,7 @@ /* default data altsetting has no endpoints */ memcpy (buf, &data_nop_intf, USB_DT_INTERFACE_SIZE); buf += USB_DT_INTERFACE_SIZE; +#endif /* DEV_CONFIG_CDC */ /* the "real" data interface has two endpoints */ memcpy (buf, &data_intf, USB_DT_INTERFACE_SIZE); @@ -684,6 +762,8 @@ /*-------------------------------------------------------------------------*/ +static void eth_start (struct eth_dev *dev, int gfp_flags); + static int set_ether_config (struct eth_dev *dev, int gfp_flags) { @@ -694,7 +774,8 @@ gadget_for_each_ep (ep, gadget) { const struct usb_endpoint_descriptor *d; - /* NOTE: the host isn't allowed to use these two data +#ifdef DEV_CONFIG_CDC + /* With CDC, the host isn't allowed to use these two data * endpoints in the default altsetting for the interface. * so we don't activate them yet. */ @@ -714,10 +795,11 @@ dev->out_ep = ep; dev->out = d; continue; + } #ifdef EP_STATUS_NUM /* optional status/notification endpoint */ - } else if (strcmp (ep->name, EP_STATUS_NAME) == 0) { + else if (strcmp (ep->name, EP_STATUS_NAME) == 0) { d = ep_desc (gadget, &hs_status_desc, &fs_status_desc); result = usb_ep_enable (ep, d); if (result == 0) { @@ -726,16 +808,57 @@ dev->status = d; continue; } + } #endif +#else /* !CONFIG_CDC_ETHER */ + + /* non-CDC is simpler: if the device is there, + * it's live with rx and tx endpoints. + */ + /* one endpoint writes data back IN to the host */ + if (strcmp (ep->name, EP_IN_NAME) == 0) { + d = ep_desc (gadget, &hs_source_desc, &fs_source_desc); + result = usb_ep_enable (ep, d); + if (result == 0) { + ep->driver_data = dev; + dev->in_ep = ep; + dev->in = d; + continue; + } + + /* one endpoint just reads OUT packets */ + } else if (strcmp (ep->name, EP_OUT_NAME) == 0) { + d = ep_desc (gadget, &hs_sink_desc, &fs_sink_desc); + result = usb_ep_enable (ep, d); + if (result == 0) { + ep->driver_data = dev; + dev->out_ep = ep; + dev->out = d; + continue; + } + } + +#endif /* !CONFIG_CDC_ETHER */ + /* ignore any other endpoints */ - } else + else continue; /* stop on error */ ERROR (dev, "can't enable %s, result %d\n", ep->name, result); break; } + if (!result && (!dev->in_ep || !dev->out_ep)) + result = -ENODEV; + +#ifndef DEV_CONFIG_CDC + if (result == 0) { + netif_carrier_on (dev->net); + if (netif_running (dev->net)) + eth_start (dev, GFP_ATOMIC); + } +#endif /* !CONFIG_CDC_ETHER */ if (result == 0) DEBUG (dev, "qlen %d\n", qlen (gadget)); @@ -751,8 +874,8 @@ DEBUG (dev, "%s\n", __FUNCTION__); - netif_stop_queue (&dev->net); - netif_carrier_off (&dev->net); + netif_stop_queue (dev->net); + netif_carrier_off (dev->net); /* just disable endpoints, forcing completion of pending i/o. * all our completion handlers free their requests in this case. @@ -797,7 +920,7 @@ hw_optimize (gadget); switch (number) { - case CONFIG_CDC_ETHER: + case DEV_CONFIG_VALUE: result = set_ether_config (dev, gfp_flags); break; default: @@ -807,8 +930,6 @@ return result; } - if (!result && (!dev->in_ep || !dev->out_ep)) - result = -ENODEV; if (result) eth_reset_config (dev); else { @@ -896,6 +1017,7 @@ * FIXME ugly idiom, maybe we'd be better with just * a "cancel the whole queue" primitive since any * unlink-one primitive has way too many error modes. + * here, we "know" toggle is already clear... */ usb_ep_disable (dev->status_ep); usb_ep_enable (dev->status_ep, dev->status); @@ -953,8 +1075,6 @@ */ #define CDC_SET_ETHERNET_PACKET_FILTER 0x43 /* required */ -static void eth_start (struct eth_dev *dev, int gfp_flags); - /* * The setup() callback implements all the ep0 functionality that's not * handled lower down. CDC has a number of less-common features: @@ -1018,6 +1138,17 @@ value = eth_set_config (dev, ctrl->wValue, GFP_ATOMIC); spin_unlock (&dev->lock); break; +#ifdef CONFIG_USB_ETH_PXA2XX + /* PXA UDC prevents us from using SET_INTERFACE in normal ways. + * And it hides GET_CONFIGURATION and GET_INTERFACE too. + */ + case USB_REQ_SET_INTERFACE: + spin_lock (&dev->lock); + value = eth_set_config (dev, DEV_CONFIG_VALUE, GFP_ATOMIC); + spin_unlock (&dev->lock); + break; + +#else /* hardware that that stays out of our way */ case USB_REQ_GET_CONFIGURATION: if (ctrl->bRequestType != USB_DIR_IN) break; @@ -1056,15 +1187,15 @@ if (ctrl->wValue == 1) { usb_ep_enable (dev->in_ep, dev->in); usb_ep_enable (dev->out_ep, dev->out); - netif_carrier_on (&dev->net); + netif_carrier_on (dev->net); #ifdef EP_STATUS_NUM issue_start_status (dev); #endif - if (netif_running (&dev->net)) + if (netif_running (dev->net)) eth_start (dev, GFP_ATOMIC); } else { - netif_stop_queue (&dev->net); - netif_carrier_off (&dev->net); + netif_stop_queue (dev->net); + netif_carrier_off (dev->net); } value = 0; break; @@ -1079,12 +1210,14 @@ /* if carrier is on, data interface is active. */ *(u8 *)req->buf = - ((ctrl->wIndex == 1) && netif_carrier_ok (&dev->net)) + ((ctrl->wIndex == 1) && netif_carrier_ok (dev->net)) ? 1 : 0, value = min (ctrl->wLength, (u16) 1); break; +#endif +#ifdef DEV_CONFIG_CDC case CDC_SET_ETHERNET_PACKET_FILTER: /* see 6.2.30: no data, wIndex = interface, * wValue = packet filter bitmap @@ -1099,6 +1232,7 @@ */ value = 0; break; +#endif /* DEV_CONFIG_CDC */ default: VDEBUG (dev, @@ -1129,8 +1263,8 @@ unsigned long flags; spin_lock_irqsave (&dev->lock, flags); - netif_stop_queue (&dev->net); - netif_carrier_off (&dev->net); + netif_stop_queue (dev->net); + netif_carrier_off (dev->net); eth_reset_config (dev); spin_unlock_irqrestore (&dev->lock, flags); @@ -1175,10 +1309,10 @@ memset (&info, 0, sizeof info); info.cmd = ETHTOOL_GDRVINFO; - strncpy (info.driver, shortname, sizeof info.driver); - strncpy (info.version, DRIVER_VERSION, sizeof info.version); - strncpy (info.fw_version, CHIP, sizeof info.fw_version); - strncpy (info.bus_info, dev->gadget->dev.bus_id, + strlcpy (info.driver, shortname, sizeof info.driver); + strlcpy (info.version, DRIVER_VERSION, sizeof info.version); + strlcpy (info.fw_version, CHIP, sizeof info.fw_version); + strlcpy (info.bus_info, dev->gadget->dev.bus_id, sizeof info.bus_info); if (copy_to_user (useraddr, &info, sizeof (info))) return -EFAULT; @@ -1227,7 +1361,7 @@ int retval = 0; size_t size; - size = (sizeof (struct ethhdr) + dev->net.mtu + RX_EXTRA); + size = (sizeof (struct ethhdr) + dev->net->mtu + RX_EXTRA); if ((skb = alloc_skb (size, gfp_flags)) == 0) { DEBUG (dev, "no rx skb\n"); @@ -1241,16 +1375,9 @@ req->complete = rx_complete; req->context = skb; - if (netif_running (&dev->net)) { - retval = usb_ep_queue (dev->out_ep, req, gfp_flags); - if (retval == -ENOMEM) - defer_kevent (dev, WORK_RX_MEMORY); - if (retval) - DEBUG (dev, "%s %d\n", __FUNCTION__, retval); - } else { - DEBUG (dev, "%s stopped\n", __FUNCTION__); - retval = -ENOLINK; - } + retval = usb_ep_queue (dev->out_ep, req, gfp_flags); + if (retval == -ENOMEM) + defer_kevent (dev, WORK_RX_MEMORY); if (retval) { DEBUG (dev, "rx submit --> %d\n", retval); dev_kfree_skb_any (skb); @@ -1278,8 +1405,8 @@ break; } - skb->dev = &dev->net; - skb->protocol = eth_type_trans (skb, &dev->net); + skb->dev = dev->net; + skb->protocol = eth_type_trans (skb, dev->net); dev->stats.rx_packets++; dev->stats.rx_bytes += skb->len; @@ -1294,9 +1421,7 @@ case -ECONNRESET: // unlink case -ESHUTDOWN: // disconnect etc VDEBUG (dev, "rx shutdown, code %d\n", status); - usb_ep_free_request (dev->out_ep, req); - req = 0; - break; + goto clean; /* data overrun */ case -EOVERFLOW: @@ -1311,7 +1436,11 @@ if (skb) dev_kfree_skb_any (skb); - + if (!netif_running (dev->net)) { +clean: + usb_ep_free_request (dev->out_ep, req); + req = 0; + } if (req) rx_submit (dev, req, GFP_ATOMIC); } @@ -1323,7 +1452,7 @@ if (test_bit (WORK_RX_MEMORY, &dev->todo)) { struct usb_request *req = 0; - if (netif_running (&dev->net)) + if (netif_running (dev->net)) req = usb_ep_alloc_request (dev->in_ep, GFP_KERNEL); else clear_bit (WORK_RX_MEMORY, &dev->todo); @@ -1342,18 +1471,25 @@ struct sk_buff *skb = req->context; struct eth_dev *dev = ep->driver_data; - if (req->status) + switch (req->status) { + default: dev->stats.tx_errors++; - else + VDEBUG (dev, "tx err %d\n", req->status); + /* FALLTHROUGH */ + case -ECONNRESET: // unlink + case -ESHUTDOWN: // disconnect etc + break; + case 0: dev->stats.tx_bytes += skb->len; + } dev->stats.tx_packets++; usb_ep_free_request (ep, req); dev_kfree_skb_any (skb); atomic_inc (&dev->tx_qlen); - if (netif_carrier_ok (&dev->net)) - netif_wake_queue (&dev->net); + if (netif_carrier_ok (dev->net)) + netif_wake_queue (dev->net); } static int eth_start_xmit (struct sk_buff *skb, struct net_device *net) @@ -1437,7 +1573,7 @@ /* and open the tx floodgates */ atomic_set (&dev->tx_qlen, size); - netif_wake_queue (&dev->net); + netif_wake_queue (dev->net); } static int eth_open (struct net_device *net) @@ -1445,10 +1581,8 @@ struct eth_dev *dev = (struct eth_dev *) net->priv; DEBUG (dev, "%s\n", __FUNCTION__); - down (&dev->mutex); - if (netif_carrier_ok (&dev->net)) + if (netif_carrier_ok (dev->net)) eth_start (dev, GFP_KERNEL); - up (&dev->mutex); return 0; } @@ -1457,7 +1591,6 @@ struct eth_dev *dev = (struct eth_dev *) net->priv; DEBUG (dev, "%s\n", __FUNCTION__); - down (&dev->mutex); netif_stop_queue (net); DEBUG (dev, "stop stats: rx/tx %ld/%ld, errs %ld/%ld\n", @@ -1469,7 +1602,7 @@ if (dev->gadget->speed != USB_SPEED_UNKNOWN) { usb_ep_disable (dev->in_ep); usb_ep_disable (dev->out_ep); - if (netif_carrier_ok (&dev->net)) { + if (netif_carrier_ok (dev->net)) { DEBUG (dev, "host still using in/out endpoints\n"); usb_ep_enable (dev->in_ep, dev->in); usb_ep_enable (dev->out_ep, dev->out); @@ -1480,7 +1613,6 @@ #endif } - up (&dev->mutex); return 0; } @@ -1492,7 +1624,6 @@ struct eth_dev *dev = get_gadget_data (gadget); DEBUG (dev, "unbind\n"); - down (&dev->mutex); /* we've already been disconnected ... no i/o is active */ if (dev->req) { @@ -1500,15 +1631,13 @@ dev->req->buf, dev->req->dma, USB_BUFSIZ); usb_ep_free_request (gadget->ep0, dev->req); + dev->req = 0; } - unregister_netdev (&dev->net); - up (&dev->mutex); + unregister_netdev (dev->net); /* assuming we used keventd, it must quiesce too */ flush_scheduled_work (); - - kfree (dev); set_gadget_data (gadget, 0); } @@ -1517,22 +1646,24 @@ { struct eth_dev *dev; struct net_device *net; + int status = -ENOMEM; +#ifdef DEV_CONFIG_CDC u8 node_id [ETH_ALEN]; /* just one upstream link at a time */ if (ethaddr [0] != 0) return -ENODEV; +#endif - dev = kmalloc (sizeof *dev, SLAB_KERNEL); - if (!dev) - return -ENOMEM; - memset (dev, 0, sizeof *dev); + net = alloc_etherdev (sizeof *dev); + if (!net) + return status; + dev = net->priv; spin_lock_init (&dev->lock); - init_MUTEX_LOCKED (&dev->mutex); INIT_WORK (&dev->work, eth_work, dev); /* network device setup */ - net = &dev->net; + dev->net = net; SET_MODULE_OWNER (net); net->priv = dev; strcpy (net->name, "usb%d"); @@ -1545,6 +1676,7 @@ net->dev_addr [0] &= 0xfe; // clear multicast bit net->dev_addr [0] |= 0x02; // set local assignment bit (IEEE802) +#ifdef DEV_CONFIG_CDC /* ... another address for the host, on the other end of the * link, gets exported through CDC (see CDC spec table 41) */ @@ -1554,6 +1686,7 @@ snprintf (ethaddr, sizeof ethaddr, "%02X%02X%02X%02X%02X%02X", node_id [0], node_id [1], node_id [2], node_id [3], node_id [4], node_id [5]); +#endif net->change_mtu = eth_change_mtu; net->get_stats = eth_get_stats; @@ -1567,36 +1700,38 @@ /* preallocate control response and buffer */ dev->req = usb_ep_alloc_request (gadget->ep0, GFP_KERNEL); if (!dev->req) - goto enomem; + goto fail; dev->req->complete = eth_setup_complete; dev->req->buf = usb_ep_alloc_buffer (gadget->ep0, USB_BUFSIZ, &dev->req->dma, GFP_KERNEL); if (!dev->req->buf) { usb_ep_free_request (gadget->ep0, dev->req); - goto enomem; + goto fail; } /* finish hookup to lower layer ... */ dev->gadget = gadget; set_gadget_data (gadget, dev); gadget->ep0->driver_data = dev; - + INFO (dev, "%s, " CHIP ", version: " DRIVER_VERSION "\n", driver_desc); +#ifdef DEV_CONFIG_CDC + INFO (dev, "CDC host enet %s\n", ethaddr); +#endif + /* two kinds of host-initiated state changes: * - iff DATA transfer is active, carrier is "on" * - tx queueing enabled if open *and* carrier is "on" */ - INFO (dev, "%s, host enet %s, version: " DRIVER_VERSION "\n", - driver_desc, ethaddr); - register_netdev (&dev->net); - netif_stop_queue (&dev->net); - netif_carrier_off (&dev->net); - - up (&dev->mutex); - return 0; + netif_stop_queue (dev->net); + netif_carrier_off (dev->net); -enomem: + // SET_NETDEV_DEV (dev->net, &gadget->dev); + status = register_netdev (dev->net); + if (status == 0) + return status; +fail: eth_unbind (gadget); - return -ENOMEM; + return status; } /*-------------------------------------------------------------------------*/ diff -Nru a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c --- a/drivers/usb/gadget/net2280.c Sun Jul 27 10:13:40 2003 +++ b/drivers/usb/gadget/net2280.c Sun Jul 27 10:13:40 2003 @@ -2496,7 +2496,7 @@ device_remove_file (&pdev->dev, &dev_attr_registers); pci_set_drvdata (pdev, 0); - INFO (dev, "unbind from pci %s\n", pdev->slot_name); + INFO (dev, "unbind from pci %s\n", pci_name(pdev)); kfree (dev); the_controller = 0; @@ -2518,7 +2518,7 @@ * usb_gadget_driver_{register,unregister}() must change. */ if (the_controller) { - WARN (the_controller, "ignoring %s\n", pdev->slot_name); + WARN (the_controller, "ignoring %s\n", pci_name(pdev)); return -EBUSY; } @@ -2534,7 +2534,7 @@ dev->pdev = pdev; dev->gadget.ops = &net2280_ops; - strcpy (dev->gadget.dev.bus_id, pdev->slot_name); + strcpy (dev->gadget.dev.bus_id, pci_name(pdev)); strcpy (dev->gadget.dev.name, pdev->dev.name); dev->gadget.dev.parent = &pdev->dev; dev->gadget.dev.dma_mask = pdev->dev.dma_mask; diff -Nru a/drivers/usb/gadget/net2280.h b/drivers/usb/gadget/net2280.h --- a/drivers/usb/gadget/net2280.h Sun Jul 27 10:13:49 2003 +++ b/drivers/usb/gadget/net2280.h Sun Jul 27 10:13:49 2003 @@ -654,7 +654,7 @@ #define xprintk(dev,level,fmt,args...) \ printk(level "%s %s: " fmt , driver_name , \ - dev->pdev->slot_name , ## args) + pci_name(dev->pdev) , ## args) #ifdef DEBUG #undef DEBUG diff -Nru a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c --- a/drivers/usb/gadget/zero.c Sun Jul 27 10:13:44 2003 +++ b/drivers/usb/gadget/zero.c Sun Jul 27 10:13:44 2003 @@ -92,7 +92,7 @@ /*-------------------------------------------------------------------------*/ -#define DRIVER_VERSION "19 Feb 2003" +#define DRIVER_VERSION "Bastille Day 2003" static const char shortname [] = "zero"; static const char longname [] = "Gadget Zero"; @@ -160,18 +160,18 @@ #endif /* - * PXA-250 UDC: widely used in second gen Linux-capable PDAs. + * PXA-2xx UDC: widely used in second gen Linux-capable PDAs. * * This has fifteen fixed-function full speed endpoints, and it * can support all USB transfer types. * - * It only supports three configurations (numbered 1, 2, or 3) - * with two interfaces each ... there's partial hardware support - * for set_configuration and set_interface, preventing some more - * interesting config/interface/endpoint arrangements. + * These supports three or four configurations, with fixed numbers. + * The hardware interprets SET_INTERFACE, net effect is that you + * can't use altsettings or reset the interfaces independently. + * So stick to a single interface. */ -#ifdef CONFIG_USB_ZERO_PXA250 -#define CHIP "pxa250" +#ifdef CONFIG_USB_ZERO_PXA2XX +#define CHIP "pxa2xx" #define DRIVER_VERSION_NUM 0x0103 #define EP0_MAXPACKET 16 static const char EP_OUT_NAME [] = "ep12out-bulk"; @@ -291,9 +291,12 @@ static unsigned buflen = 4096; static unsigned qlen = 32; +static unsigned pattern = 0; module_param (buflen, uint, S_IRUGO|S_IWUSR); module_param (qlen, uint, S_IRUGO|S_IWUSR); +module_param (pattern, uint, S_IRUGO|S_IWUSR); + /* * Normally the "loopback" configuration is second (index 1) so @@ -497,8 +500,8 @@ /* * config descriptors are also handcrafted. these must agree with code - * that sets configurations, and with code managing interface altsettings. - * other complexity may come from: + * that sets configurations, and with code managing interfaces and their + * altsettings. other complexity may come from: * * - high speed support, including "other speed config" rules * - multiple configurations @@ -506,7 +509,7 @@ * - embedded class or vendor-specific descriptors * * this handles high speed, and has a second config that could as easily - * have been an alternate interface setting. + * have been an alternate interface setting (on most hardware). * * NOTE: to demonstrate (and test) more USB capabilities, this driver * should include an altsetting to test interrupt transfers, including @@ -608,16 +611,29 @@ struct usb_request *req ) { - int i; + unsigned i; + u8 *buf = req->buf; - for (i = 0; i < req->actual; i++) { - if (((u8 *)req->buf) [i] != 0) { - ERROR (dev, "nonzero OUT byte from host, " - "buf [%d] = %d\n", - i, ((u8 *)req->buf) [i]); - usb_ep_set_halt (ep); - return -EINVAL; + for (i = 0; i < req->actual; i++, buf++) { + switch (pattern) { + /* all-zeroes has no synchronization issues */ + case 0: + if (*buf == 0) + continue; + break; + /* mod63 stays in sync with short-terminated transfers, + * or otherwise when host and gadget agree on how large + * each usb transfer request should be. resync is done + * with set_interface or set_config. + */ + case 1: + if (*buf == (u8)(i % 63)) + continue; + break; } + ERROR (dev, "bad OUT byte, buf [%d] = %d\n", i, *buf); + usb_ep_set_halt (ep); + return -EINVAL; } return 0; } @@ -629,7 +645,18 @@ struct usb_request *req ) { - memset (req->buf, 0, req->length); + unsigned i; + u8 *buf = req->buf; + + switch (pattern) { + case 0: + memset (req->buf, 0, req->length); + break; + case 1: + for (i = 0; i < req->length; i++) + *buf++ = (u8) (i % 63); + break; + } } /* if there is only one request in the queue, there'll always be an @@ -651,10 +678,13 @@ break; /* this endpoint is normally active while we're configured */ + case -ECONNABORTED: /* hardware forced ep reset */ case -ECONNRESET: /* request dequeued */ case -ESHUTDOWN: /* disconnect from host */ VDEBUG (dev, "%s gone (%d), %d/%d\n", ep->name, status, req->actual, req->length); + if (ep == dev->out_ep) + check_read_data (dev, ep, req); free_ep_req (ep, req); return; @@ -693,6 +723,9 @@ memset (req->buf, 0, req->length); req->complete = source_sink_complete; + if (strcmp (ep->name, EP_IN_NAME) == 0) + reinit_write_data (ep->driver_data, ep, req); + status = usb_ep_queue (ep, req, gfp_flags); if (status) { struct zero_dev *dev = ep->driver_data; @@ -801,6 +834,8 @@ * rely on the hardware driver to clean up on disconnect or * endpoint disable. */ + case -ECONNABORTED: /* hardware forced ep reset */ + case -ECONNRESET: /* request dequeued */ case -ESHUTDOWN: /* disconnect from host */ free_ep_req (ep, req); return; @@ -905,7 +940,7 @@ * * note that some device controller hardware will constrain what this * code can do, perhaps by disallowing more than one configuration or - * by limiting configuration choices (like the pxa250). + * by limiting configuration choices (like the pxa2xx). */ static int zero_set_config (struct zero_dev *dev, unsigned number, int gfp_flags) @@ -1046,7 +1081,8 @@ break; /* until we add altsetting support, or other interfaces, - * only 0/0 are possible. + * only 0/0 are possible. pxa2xx only supports 0/0 (poorly) + * and already killed pending endpoint I/O. */ case USB_REQ_SET_INTERFACE: if (ctrl->bRequestType != USB_RECIP_INTERFACE) diff -Nru a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c --- a/drivers/usb/host/ohci-hcd.c Sun Jul 27 10:13:41 2003 +++ b/drivers/usb/host/ohci-hcd.c Sun Jul 27 10:13:41 2003 @@ -319,6 +319,7 @@ int epnum = ep & USB_ENDPOINT_NUMBER_MASK; unsigned long flags; struct ed *ed; + unsigned limit = 1000; /* ASSERT: any requests/urbs are being unlinked */ /* ASSERT: nobody can be submitting urbs for this any more */ @@ -337,6 +338,8 @@ ed->state = ED_IDLE; switch (ed->state) { case ED_UNLINK: /* wait for hw to finish? */ + /* major IRQ delivery trouble loses INTR_SF too... */ + WARN_ON (limit-- == 0); spin_unlock_irqrestore (&ohci->lock, flags); set_current_state (TASK_UNINTERRUPTIBLE); schedule_timeout (1); diff -Nru a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c --- a/drivers/usb/host/ohci-q.c Sun Jul 27 10:13:51 2003 +++ b/drivers/usb/host/ohci-q.c Sun Jul 27 10:13:51 2003 @@ -43,6 +43,16 @@ spin_lock (&urb->lock); if (likely (urb->status == -EINPROGRESS)) urb->status = 0; + /* report short control reads right even though the data TD always + * has TD_R set. (much simpler, but creates the 1-td limit.) + */ + if (unlikely (urb->transfer_flags & URB_SHORT_NOT_OK) + && unlikely (usb_pipecontrol (urb->pipe)) + && urb->actual_length < urb->transfer_buffer_length + && usb_pipein (urb->pipe) + && urb->status == 0) { + urb->status = -EREMOTEIO; + } spin_unlock (&urb->lock); // what lock protects these? diff -Nru a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c --- a/drivers/usb/host/uhci-hcd.c Sun Jul 27 10:13:51 2003 +++ b/drivers/usb/host/uhci-hcd.c Sun Jul 27 10:13:51 2003 @@ -2007,19 +2007,17 @@ unsigned int io_addr = uhci->io_addr; int i; - if (!uhci->hcd.pdev || - uhci->hcd.pdev->vendor != PCI_VENDOR_ID_INTEL || - uhci->hcd.pdev->device != PCI_DEVICE_ID_INTEL_82371AB_2) + if (!uhci->hcd.pdev || uhci->hcd.pdev->vendor != PCI_VENDOR_ID_INTEL) return 1; - /* This is a 82371AB/EB/MB USB controller which has a bug that - * causes false resume indications if any port has an - * over current condition. To prevent problems, we will not - * allow a global suspend if any ports are OC. + /* Some of Intel's USB controllers have a bug that causes false + * resume indications if any port has an over current condition. + * To prevent problems, we will not allow a global suspend if + * any ports are OC. * - * Some motherboards using the 82371AB/EB/MB (but not the USB portion) - * appear to hardwire the over current inputs active to disable - * the USB ports. + * Some motherboards using Intel's chipsets (but not using all + * the USB ports) appear to hardwire the over current inputs active + * to disable the USB ports. */ /* check for over current condition on any port */ diff -Nru a/drivers/usb/image/hpusbscsi.c b/drivers/usb/image/hpusbscsi.c --- a/drivers/usb/image/hpusbscsi.c Sun Jul 27 10:13:52 2003 +++ b/drivers/usb/image/hpusbscsi.c Sun Jul 27 10:13:52 2003 @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include "../../scsi/scsi.h" #include "../../scsi/hosts.h" @@ -109,7 +109,8 @@ goto out_unlink_controlurb; new->host->hostdata[0] = (unsigned long)new; - scsi_add_host(new->host, &intf->dev); + scsi_add_host(new->host, &intf->dev); /* XXX handle failure */ + scsi_scan_host(new->host); new->sense_command[0] = REQUEST_SENSE; new->sense_command[4] = HPUSBSCSI_SENSE_LENGTH; @@ -306,7 +307,10 @@ if(unlikely(u->status < 0)) { if (likely(hpusbscsi->state != HP_STATE_FREE)) handle_usb_error(hpusbscsi); - return; + if (u->status == -ECONNRESET || u->status == -ENOENT || u->status == -ESHUTDOWN) + return; + else + goto resub; } scsi_state = hpusbscsi->scsi_state_byte; @@ -348,6 +352,8 @@ TRACE_STATE; break; } +resub: + usb_submit_urb(u, GFP_ATOMIC); } static void simple_command_callback(struct urb *u, struct pt_regs *regs) @@ -427,7 +433,7 @@ hpusbscsi->state = HP_STATE_WAIT; } else { issue_request_sense(hpusbscsi); - } + } } } else { if (likely(hpusbscsi->scallback != NULL)) diff -Nru a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c --- a/drivers/usb/image/microtek.c Sun Jul 27 10:13:52 2003 +++ b/drivers/usb/image/microtek.c Sun Jul 27 10:13:52 2003 @@ -134,7 +134,7 @@ #include #include -#include +#include #include "../../scsi/scsi.h" #include "../../scsi/hosts.h" @@ -817,7 +817,8 @@ goto out_free_urb; new_desc->host->hostdata[0] = (unsigned long)new_desc; - scsi_add_host(new_desc->host, NULL); + scsi_add_host(new_desc->host, NULL); /* XXX handle failure */ + scsi_scan_host(new_desc->host); usb_set_intfdata(intf, new_desc); return 0; diff -Nru a/drivers/usb/image/scanner.c b/drivers/usb/image/scanner.c --- a/drivers/usb/image/scanner.c Sun Jul 27 10:13:43 2003 +++ b/drivers/usb/image/scanner.c Sun Jul 27 10:13:43 2003 @@ -364,6 +364,11 @@ * Mustek, Pacific Image Electronics, Plustek, and Visioneer scanners. * Fixed names of some other scanners. * + * 0.4.14 2003-07-15 + * - Fixed race between open and probe (Oliver Neukum). + * - Added vendor/product ids for Avision, Canon, HP, Microtek and Relisys scanners. + * - Clean up irq urb when not enough memory is available. + * * TODO * - Performance * - Select/poll methods @@ -1068,6 +1073,9 @@ /* Ok, now initialize all the relevant values */ if (!(scn->obuf = (char *)kmalloc(OBUF_SIZE, GFP_KERNEL))) { err("probe_scanner(%d): Not enough memory for the output buffer.", intf->minor); + if (have_intr) + usb_unlink_urb(scn->scn_irq); + usb_free_urb(scn->scn_irq); kfree(scn); up(&scn_mutex); return -ENOMEM; @@ -1076,6 +1084,9 @@ if (!(scn->ibuf = (char *)kmalloc(IBUF_SIZE, GFP_KERNEL))) { err("probe_scanner(%d): Not enough memory for the input buffer.", intf->minor); + if (have_intr) + usb_unlink_urb(scn->scn_irq); + usb_free_urb(scn->scn_irq); kfree(scn->obuf); kfree(scn); up(&scn_mutex); @@ -1117,10 +1128,9 @@ info ("USB scanner device (0x%04x/0x%04x) now attached to %s", dev->descriptor.idVendor, dev->descriptor.idProduct, name); - up(&scn_mutex); - usb_set_intfdata(intf, scn); - + up(&scn_mutex); + return 0; } diff -Nru a/drivers/usb/image/scanner.h b/drivers/usb/image/scanner.h --- a/drivers/usb/image/scanner.h Sun Jul 27 10:13:44 2003 +++ b/drivers/usb/image/scanner.h Sun Jul 27 10:13:44 2003 @@ -43,7 +43,7 @@ // #define DEBUG -#define DRIVER_VERSION "0.4.13" +#define DRIVER_VERSION "0.4.14" #define DRIVER_DESC "USB Scanner Driver" #include @@ -103,6 +103,7 @@ /* Avision */ { USB_DEVICE(0x0638, 0x0268) }, /* iVina 1200U */ { USB_DEVICE(0x0638, 0x0a10) }, /* iVina FB1600 (=Umax Astra 4500) */ + { USB_DEVICE(0x0638, 0x0a20) }, /* iVina FB1800 (=Umax Astra 4700) */ /* Benq: see Acer */ /* Brother */ { USB_DEVICE(0x04f9, 0x010f) }, /* MFC 5100C */ @@ -115,10 +116,12 @@ { USB_DEVICE(0x04a9, 0x2206) }, /* CanoScan N650U/N656U */ { USB_DEVICE(0x04a9, 0x2207) }, /* CanoScan N1220U */ { USB_DEVICE(0x04a9, 0x2208) }, /* CanoScan D660U */ + { USB_DEVICE(0x04a9, 0x220a) }, /* CanoScan D2400UF */ { USB_DEVICE(0x04a9, 0x220b) }, /* CanoScan D646U */ { USB_DEVICE(0x04a9, 0x220c) }, /* CanoScan D1250U2 */ { USB_DEVICE(0x04a9, 0x220d) }, /* CanoScan N670U/N676U/LIDE 20 */ { USB_DEVICE(0x04a9, 0x220e) }, /* CanoScan N1240U/LIDE 30 */ + { USB_DEVICE(0x04a9, 0x220f) }, /* CanoScan 8000F */ { USB_DEVICE(0x04a9, 0x2213) }, /* LIDE 50 */ { USB_DEVICE(0x04a9, 0x3042) }, /* FS4000US */ /* Colorado -- See Primax/Colorado below */ @@ -158,6 +161,7 @@ { USB_DEVICE(0x03f0, 0x0901) }, /* ScanJet 2300C */ { USB_DEVICE(0x03F0, 0x1005) }, /* ScanJet 5400C */ { USB_DEVICE(0x03F0, 0x1105) }, /* ScanJet 5470C */ + { USB_DEVICE(0x03f0, 0x1205) }, /* ScanJet 5550C */ { USB_DEVICE(0x03f0, 0x1305) }, /* Scanjet 4570c */ { USB_DEVICE(0x03f0, 0x1411) }, /* PSC 750 */ { USB_DEVICE(0x03f0, 0x2005) }, /* ScanJet 3570c */ @@ -173,6 +177,7 @@ /* Memorex */ { USB_DEVICE(0x0461, 0x0346) }, /* 6136u - repackaged Primax ? */ /* Microtek */ + { USB_DEVICE(0x05da, 0x20c9) }, /* ScanMaker 6700 */ { USB_DEVICE(0x05da, 0x30ce) }, /* ScanMaker 3800 */ { USB_DEVICE(0x05da, 0x30cf) }, /* ScanMaker 4800 */ { USB_DEVICE(0x04a7, 0x0224) }, /* Scanport 3000 (actually Visioneer?)*/ @@ -250,6 +255,7 @@ { USB_DEVICE(0x06dc, 0x0014) }, /* Winscan Pro 2448U */ /* Relisis */ // { USB_DEVICE(0x0475, 0x0103) }, /* Episode - undetected endpoint */ + { USB_DEVICE(0x0475, 0x0210) }, /* Scorpio Ultra 3 */ /* Seiko/Epson Corp. */ { USB_DEVICE(0x04b8, 0x0101) }, /* Perfection 636U and 636Photo */ { USB_DEVICE(0x04b8, 0x0102) }, /* GT-2200 */ diff -Nru a/drivers/usb/media/dabusb.c b/drivers/usb/media/dabusb.c --- a/drivers/usb/media/dabusb.c Sun Jul 27 10:13:46 2003 +++ b/drivers/usb/media/dabusb.c Sun Jul 27 10:13:46 2003 @@ -721,7 +721,7 @@ /* --------------------------------------------------------------------- */ -static int dabusb_probe (struct usb_interface *intf, +static int dabusb_probe (struct usb_interface *intf, const struct usb_device_id *id) { struct usb_device *usbdev = interface_to_usbdev(intf); @@ -738,9 +738,7 @@ if (intf->altsetting->desc.bInterfaceNumber != _DABUSB_IF && usbdev->descriptor.idProduct == 0x9999) return -ENODEV; - retval = usb_register_dev(intf, &dabusb_class); - if (retval) - return -ENOMEM; + s = &dabusb[intf->minor]; @@ -766,8 +764,15 @@ } } dbg("bound to interface: %d", ifnum); - up (&s->mutex); usb_set_intfdata (intf, s); + up (&s->mutex); + + retval = usb_register_dev(intf, &dabusb_class); + if (retval) { + usb_set_intfdata (intf, NULL); + return -ENOMEM; + } + return 0; reject: diff -Nru a/drivers/usb/misc/usblcd.c b/drivers/usb/misc/usblcd.c --- a/drivers/usb/misc/usblcd.c Sun Jul 27 10:13:40 2003 +++ b/drivers/usb/misc/usblcd.c Sun Jul 27 10:13:40 2003 @@ -1,4 +1,4 @@ -/***************************************************************************** +/***************************************************************************** * USBLCD Kernel Driver * * See http://www.usblcd.de for Hardware and Documentation. * * Version 1.03 * @@ -18,7 +18,7 @@ #include #include -#define DRIVER_VERSION "USBLCD Driver Version 1.03" +#define DRIVER_VERSION "USBLCD Driver Version 1.04" #define USBLCD_MINOR 144 @@ -257,7 +257,7 @@ struct lcd_usb_data *lcd = &lcd_instance; int i; int retval; - + if (dev->descriptor.idProduct != 0x0001 ) { warn(KERN_INFO "USBLCD model not supported."); return -ENODEV; @@ -274,29 +274,31 @@ (i & 0xF000)>>12,(i & 0xF00)>>8,(i & 0xF0)>>4,(i & 0xF), dev->devnum); - retval = usb_register_dev(intf, &usb_lcd_class); - if (retval) { - err("Not able to get a minor for this device."); - return -ENOMEM; - } + lcd->present = 1; lcd->lcd_dev = dev; if (!(lcd->obuf = (char *) kmalloc(OBUF_SIZE, GFP_KERNEL))) { err("probe_lcd: Not enough memory for the output buffer"); - usb_deregister_dev(intf, &usb_lcd_class); return -ENOMEM; } dbg("probe_lcd: obuf address:%p", lcd->obuf); if (!(lcd->ibuf = (char *) kmalloc(IBUF_SIZE, GFP_KERNEL))) { err("probe_lcd: Not enough memory for the input buffer"); - usb_deregister_dev(intf, &usb_lcd_class); kfree(lcd->obuf); return -ENOMEM; } dbg("probe_lcd: ibuf address:%p", lcd->ibuf); + + retval = usb_register_dev(intf, &usb_lcd_class); + if (retval) { + err("Not able to get a minor for this device."); + kfree(lcd->obuf); + kfree(lcd->ibuf); + return -ENOMEM; + } usb_set_intfdata (intf, lcd); return 0; diff -Nru a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c --- a/drivers/usb/misc/usbtest.c Sun Jul 27 10:13:52 2003 +++ b/drivers/usb/misc/usbtest.c Sun Jul 27 10:13:52 2003 @@ -47,6 +47,7 @@ const char *name; u8 ep_in; /* bulk/intr source */ u8 ep_out; /* bulk/intr sink */ + unsigned autoconf : 1; int alt; }; @@ -78,6 +79,61 @@ /*-------------------------------------------------------------------------*/ +static int +get_endpoints (struct usbtest_dev *dev, struct usb_interface *intf) +{ + int tmp; + struct usb_host_interface *alt; + struct usb_host_endpoint *in, *out; + struct usb_device *udev; + + for (tmp = 0; tmp < intf->max_altsetting; tmp++) { + unsigned ep; + + in = out = 0; + alt = intf->altsetting + tmp; + + /* take the first altsetting with in-bulk + out-bulk; + * ignore other endpoints and altsetttings. + */ + for (ep = 0; ep < alt->desc.bNumEndpoints; ep++) { + struct usb_host_endpoint *e; + + e = alt->endpoint + ep; + if (e->desc.bmAttributes != USB_ENDPOINT_XFER_BULK) + continue; + if (e->desc.bEndpointAddress & USB_DIR_IN) { + if (!in) + in = e; + } else { + if (!out) + out = e; + } + if (in && out) + goto found; + } + } + return -EINVAL; + +found: + udev = testdev_to_usbdev (dev); + if (alt->desc.bAlternateSetting != 0) { + tmp = usb_set_interface (udev, + alt->desc.bInterfaceNumber, + alt->desc.bAlternateSetting); + if (tmp < 0) + return tmp; + } + + dev->in_pipe = usb_rcvbulkpipe (udev, + in->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); + dev->out_pipe = usb_sndbulkpipe (udev, + out->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); + return 0; +} + +/*-------------------------------------------------------------------------*/ + /* Support for testing basic non-queued I/O streams. * * These just package urbs as requests that can be easily canceled. @@ -1275,14 +1331,26 @@ wtest = " intr-out"; } } else { - if (info->ep_in) { - dev->in_pipe = usb_rcvbulkpipe (udev, info->ep_in); - rtest = " bulk-in"; + if (info->autoconf) { + int status; + + status = get_endpoints (dev, intf); + if (status < 0) { + dbg ("couldn't get endpoints, %d\n", status); + return status; + } + } else { + if (info->ep_in) + dev->in_pipe = usb_rcvbulkpipe (udev, + info->ep_in); + if (info->ep_out) + dev->out_pipe = usb_sndbulkpipe (udev, + info->ep_out); } - if (info->ep_out) { - dev->out_pipe = usb_sndbulkpipe (udev, info->ep_out); + if (dev->in_pipe) + rtest = " bulk-in"; + if (dev->out_pipe) wtest = " bulk-out"; - } } usb_set_intfdata (intf, dev); @@ -1336,11 +1404,6 @@ }; /* ezusb family device with dedicated usb test firmware, - * or a peripheral running Linux and 'zero.c' test firmware. - * - * FIXME usbtest should read the descriptors, since compatible - * test firmware might run on hardware (pxa250 for one) that - * can't configure an ep2in-bulk. */ static struct usbtest_info fw_info = { .name = "usb test device", @@ -1349,10 +1412,20 @@ .alt = 0, }; +/* peripheral running Linux and 'zero.c' test firmware, or + * its user-mode cousin. different versions of this use + * different hardware with the same vendor/product codes. + * host side MUST rely on the endpoint descriptors. + */ +static struct usbtest_info gz_info = { + .name = "Linux gadget zero", + .autoconf = 1, + .alt = 0, +}; + static struct usbtest_info um_info = { - .name = "user mode test driver", - .ep_in = 7, - .ep_out = 3, + .name = "Linux user mode test driver", + .autoconf = 1, .alt = -1, }; @@ -1418,7 +1491,7 @@ /* "Gadget Zero" firmware runs under Linux */ { USB_DEVICE (0x0525, 0xa4a0), - .driver_info = (unsigned long) &fw_info, + .driver_info = (unsigned long) &gz_info, }, /* so does a user-mode variant */ diff -Nru a/drivers/usb/net/ax8817x.c b/drivers/usb/net/ax8817x.c --- a/drivers/usb/net/ax8817x.c Sun Jul 27 10:13:42 2003 +++ b/drivers/usb/net/ax8817x.c Sun Jul 27 10:13:42 2003 @@ -1208,6 +1208,7 @@ net->init = ax8817x_net_init; net->priv = ax_info; + SET_NETDEV_DEV(net, &intf->dev); ret = register_netdev(net); if (ret < 0) { err("%s: Failed net init (%d)\n", __FUNCTION__, ret); diff -Nru a/drivers/usb/net/catc.c b/drivers/usb/net/catc.c --- a/drivers/usb/net/catc.c Sun Jul 27 10:13:45 2003 +++ b/drivers/usb/net/catc.c Sun Jul 27 10:13:45 2003 @@ -936,6 +936,7 @@ printk("%2.2x.\n", netdev->dev_addr[i]); usb_set_intfdata(intf, catc); + SET_NETDEV_DEV(netdev, &intf->dev); if (register_netdev(netdev) != 0) { usb_set_intfdata(intf, NULL); usb_free_urb(catc->ctrl_urb); diff -Nru a/drivers/usb/net/kaweth.c b/drivers/usb/net/kaweth.c --- a/drivers/usb/net/kaweth.c Sun Jul 27 10:13:49 2003 +++ b/drivers/usb/net/kaweth.c Sun Jul 27 10:13:49 2003 @@ -1123,8 +1123,9 @@ if (dma_supported (&intf->dev, 0xffffffffffffffffULL)) kaweth->net->features |= NETIF_F_HIGHDMA; + SET_NETDEV_DEV(netdev, &intf->dev); if (register_netdev(netdev) != 0) { - kaweth_err("Error calling init_etherdev."); + kaweth_err("Error registering netdev."); goto err_intfdata; } diff -Nru a/drivers/usb/net/pegasus.c b/drivers/usb/net/pegasus.c --- a/drivers/usb/net/pegasus.c Sun Jul 27 10:13:52 2003 +++ b/drivers/usb/net/pegasus.c Sun Jul 27 10:13:52 2003 @@ -1262,7 +1262,6 @@ } set_ethernet_addr(pegasus); fill_skb_pool(pegasus); - printk("%s: %s\n", net->name, usb_dev_id[dev_index].name); if (pegasus->features & PEGASUS_II) { info("setup Pegasus II specific registers"); setup_pegasus_II(pegasus); @@ -1273,9 +1272,11 @@ pegasus->phy = 1; } usb_set_intfdata(intf, pegasus); + SET_NETDEV_DEV(net, &intf->dev); res = register_netdev(net); if (res) goto out4; + printk("%s: %s\n", net->name, usb_dev_id[dev_index].name); return 0; out4: diff -Nru a/drivers/usb/net/rtl8150.c b/drivers/usb/net/rtl8150.c --- a/drivers/usb/net/rtl8150.c Sun Jul 27 10:13:47 2003 +++ b/drivers/usb/net/rtl8150.c Sun Jul 27 10:13:47 2003 @@ -830,6 +830,7 @@ usb_set_intfdata(intf, dev); + SET_NETDEV_DEV(netdev, &intf->dev); if (register_netdev(netdev) != 0) { err("couldn't register the device"); goto out2; diff -Nru a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c --- a/drivers/usb/net/usbnet.c Sun Jul 27 10:13:46 2003 +++ b/drivers/usb/net/usbnet.c Sun Jul 27 10:13:46 2003 @@ -2602,7 +2602,7 @@ dev->maxpacket = usb_maxpacket (dev->udev, dev->out, 1); - SET_NETDEV_DEV(dev->net, &dev->udev->dev); + SET_NETDEV_DEV(dev->net, &udev->dev); status = register_netdev (dev->net); if (status) goto out3; diff -Nru a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c --- a/drivers/usb/serial/ftdi_sio.c Sun Jul 27 10:13:50 2003 +++ b/drivers/usb/serial/ftdi_sio.c Sun Jul 27 10:13:50 2003 @@ -257,6 +257,7 @@ { USB_DEVICE_VER(FTDI_VID, FTDI_XF_634_PID, 0, 0x3ff) }, { USB_DEVICE_VER(FTDI_VID, FTDI_XF_632_PID, 0, 0x3ff) }, { USB_DEVICE_VER(FTDI_VID, FTDI_VNHCPCUSB_D_PID, 0, 0x3ff) }, + { USB_DEVICE_VER(FTDI_VID, FTDI_DSS20_PID, 0, 0x3ff) }, { USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_0_PID, 0, 0x3ff) }, { USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_1_PID, 0, 0x3ff) }, { USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_2_PID, 0, 0x3ff) }, @@ -321,6 +322,7 @@ { USB_DEVICE_VER(FTDI_VID, FTDI_XF_634_PID, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_VID, FTDI_XF_632_PID, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_VID, FTDI_VNHCPCUSB_D_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(FTDI_VID, FTDI_DSS20_PID, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_0_PID, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_1_PID, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_2_PID, 0x400, 0xffff) }, @@ -396,6 +398,7 @@ { USB_DEVICE(FTDI_VID, FTDI_RELAIS_PID) }, { USB_DEVICE(FTDI_VID, FTDI_XF_634_PID) }, { USB_DEVICE(FTDI_VID, FTDI_XF_632_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_DSS20_PID) }, { USB_DEVICE(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID) }, { USB_DEVICE(FTDI_VID, FTDI_VNHCPCUSB_D_PID) }, { USB_DEVICE(FTDI_MTXORB_VID, FTDI_MTXORB_0_PID) }, diff -Nru a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h --- a/drivers/usb/serial/ftdi_sio.h Sun Jul 27 10:13:50 2003 +++ b/drivers/usb/serial/ftdi_sio.h Sun Jul 27 10:13:50 2003 @@ -105,7 +105,13 @@ #define SEALEVEL_2803_6_PID 0X2863 /* SeaLINK+8 (2803) Port 6 */ #define SEALEVEL_2803_7_PID 0X2873 /* SeaLINK+8 (2803) Port 7 */ #define SEALEVEL_2803_8_PID 0X2883 /* SeaLINK+8 (2803) Port 8 */ + +/* + * DSS-20 Sync Station for Sony Ericsson P800 + */ +#define FTDI_DSS20_PID 0xFC82 + /* * Home Electronics (www.home-electro.com) USB gadgets */ diff -Nru a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c --- a/drivers/usb/serial/ipaq.c Sun Jul 27 10:13:50 2003 +++ b/drivers/usb/serial/ipaq.c Sun Jul 27 10:13:50 2003 @@ -125,10 +125,13 @@ { USB_DEVICE(LINKUP_VENDOR_ID, LINKUP_PRODUCT_ID) }, { USB_DEVICE(MICROSOFT_VENDOR_ID, MICROSOFT_00CE_ID) }, { USB_DEVICE(PORTATEC_VENDOR_ID, PORTATEC_PRODUCT_ID) }, + { USB_DEVICE(ROVER_VENDOR_ID, ROVER_P5_ID) }, { USB_DEVICE(SAGEM_VENDOR_ID, SAGEM_WIRELESS_ID) }, { USB_DEVICE(SOCKET_VENDOR_ID, SOCKET_PRODUCT_ID) }, { USB_DEVICE(TOSHIBA_VENDOR_ID, TOSHIBA_PRODUCT_ID) }, + { USB_DEVICE(TOSHIBA_VENDOR_ID, TOSHIBA_E310_ID) }, { USB_DEVICE(TOSHIBA_VENDOR_ID, TOSHIBA_E740_ID) }, + { USB_DEVICE(TOSHIBA_VENDOR_ID, TOSHIBA_E335_ID) }, { USB_DEVICE(HTC_VENDOR_ID, HTC_PRODUCT_ID) }, { USB_DEVICE(NEC_VENDOR_ID, NEC_PRODUCT_ID) }, { USB_DEVICE(ASUS_VENDOR_ID, ASUS_A600_PRODUCT_ID) }, diff -Nru a/drivers/usb/serial/ipaq.h b/drivers/usb/serial/ipaq.h --- a/drivers/usb/serial/ipaq.h Sun Jul 27 10:13:40 2003 +++ b/drivers/usb/serial/ipaq.h Sun Jul 27 10:13:40 2003 @@ -61,6 +61,9 @@ #define PORTATEC_VENDOR_ID 0x0961 #define PORTATEC_PRODUCT_ID 0x0010 +#define ROVER_VENDOR_ID 0x047b +#define ROVER_P5_ID 0x3000 + #define SAGEM_VENDOR_ID 0x5e04 #define SAGEM_WIRELESS_ID 0xce00 @@ -69,7 +72,9 @@ #define TOSHIBA_VENDOR_ID 0x0930 #define TOSHIBA_PRODUCT_ID 0x0700 +#define TOSHIBA_E310_ID 0x0705 #define TOSHIBA_E740_ID 0x0706 +#define TOSHIBA_E335_ID 0x0707 #define HTC_VENDOR_ID 0x0bb4 #define HTC_PRODUCT_ID 0x00ce diff -Nru a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c --- a/drivers/usb/serial/usb-serial.c Sun Jul 27 10:13:44 2003 +++ b/drivers/usb/serial/usb-serial.c Sun Jul 27 10:13:44 2003 @@ -530,7 +530,9 @@ /* if disconnect beat us to the punch here, there's nothing to do */ if (tty && tty->driver_data) { __serial_close(port, filp); + tty->driver_data = NULL; } + port->tty = NULL; } static int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count) diff -Nru a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c --- a/drivers/usb/serial/visor.c Sun Jul 27 10:13:43 2003 +++ b/drivers/usb/serial/visor.c Sun Jul 27 10:13:43 2003 @@ -509,18 +509,17 @@ { struct usb_serial_port *port = (struct usb_serial_port *)urb->context; + /* free up the transfer buffer, as usb_free_urb() does not do this */ + kfree (urb->transfer_buffer); + if (port_paranoia_check (port, __FUNCTION__)) return; dbg("%s - port %d", __FUNCTION__, port->number); - if (urb->status) { - dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status); - return; - } - - /* free up the transfer buffer, as usb_free_urb() does not do this */ - kfree (urb->transfer_buffer); + if (urb->status) + dbg("%s - nonzero write bulk status received: %d", + __FUNCTION__, urb->status); schedule_work(&port->work); } diff -Nru a/drivers/usb/storage/debug.h b/drivers/usb/storage/debug.h --- a/drivers/usb/storage/debug.h Sun Jul 27 10:13:52 2003 +++ b/drivers/usb/storage/debug.h Sun Jul 27 10:13:52 2003 @@ -46,7 +46,6 @@ #include #include -#include #include #include "usb.h" diff -Nru a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c --- a/drivers/usb/storage/isd200.c Sun Jul 27 10:13:45 2003 +++ b/drivers/usb/storage/isd200.c Sun Jul 27 10:13:45 2003 @@ -280,6 +280,7 @@ /* maximum number of LUNs supported */ unsigned char MaxLUNs; + struct scsi_cmnd srb; }; @@ -404,15 +405,15 @@ void* pointer, int value ) { union ata_cdb ata; - struct scsi_cmnd srb; struct scsi_device srb_dev; struct isd200_info *info = (struct isd200_info *)us->extra; + struct scsi_cmnd *srb = &info->srb; int status; memset(&ata, 0, sizeof(ata)); - memset(&srb, 0, sizeof(srb)); memset(&srb_dev, 0, sizeof(srb_dev)); - srb.device = &srb_dev; + srb->device = &srb_dev; + ++srb->serial_number; ata.generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; ata.generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; @@ -425,9 +426,9 @@ ata.generic.RegisterSelect = REG_CYLINDER_LOW | REG_CYLINDER_HIGH | REG_STATUS | REG_ERROR; - srb.sc_data_direction = SCSI_DATA_READ; - srb.request_buffer = pointer; - srb.request_bufflen = value; + srb->sc_data_direction = SCSI_DATA_READ; + srb->request_buffer = pointer; + srb->request_bufflen = value; break; case ACTION_ENUM: @@ -437,7 +438,7 @@ ACTION_SELECT_5; ata.generic.RegisterSelect = REG_DEVICE_HEAD; ata.write.DeviceHeadByte = value; - srb.sc_data_direction = SCSI_DATA_NONE; + srb->sc_data_direction = SCSI_DATA_NONE; break; case ACTION_RESET: @@ -446,7 +447,7 @@ ACTION_SELECT_3|ACTION_SELECT_4; ata.generic.RegisterSelect = REG_DEVICE_CONTROL; ata.write.DeviceControlByte = ATA_DC_RESET_CONTROLLER; - srb.sc_data_direction = SCSI_DATA_NONE; + srb->sc_data_direction = SCSI_DATA_NONE; break; case ACTION_REENABLE: @@ -455,7 +456,7 @@ ACTION_SELECT_3|ACTION_SELECT_4; ata.generic.RegisterSelect = REG_DEVICE_CONTROL; ata.write.DeviceControlByte = ATA_DC_REENABLE_CONTROLLER; - srb.sc_data_direction = SCSI_DATA_NONE; + srb->sc_data_direction = SCSI_DATA_NONE; break; case ACTION_SOFT_RESET: @@ -464,16 +465,16 @@ ata.generic.RegisterSelect = REG_DEVICE_HEAD | REG_COMMAND; ata.write.DeviceHeadByte = info->DeviceHead; ata.write.CommandByte = WIN_SRST; - srb.sc_data_direction = SCSI_DATA_NONE; + srb->sc_data_direction = SCSI_DATA_NONE; break; case ACTION_IDENTIFY: US_DEBUGP(" isd200_action(IDENTIFY)\n"); ata.generic.RegisterSelect = REG_COMMAND; ata.write.CommandByte = WIN_IDENTIFY; - srb.sc_data_direction = SCSI_DATA_READ; - srb.request_buffer = (void *)&info->drive; - srb.request_bufflen = sizeof(struct hd_driveid); + srb->sc_data_direction = SCSI_DATA_READ; + srb->request_buffer = (void *)&info->drive; + srb->request_bufflen = sizeof(struct hd_driveid); break; default: @@ -481,9 +482,9 @@ break; } - memcpy(srb.cmnd, &ata, sizeof(ata.generic)); - srb.cmd_len = sizeof(ata.generic); - status = usb_stor_Bulk_transport(&srb, us); + memcpy(srb->cmnd, &ata, sizeof(ata.generic)); + srb->cmd_len = sizeof(ata.generic); + status = usb_stor_Bulk_transport(srb, us); if (status == USB_STOR_TRANSPORT_GOOD) status = ISD200_GOOD; else { @@ -834,7 +835,7 @@ int detect ) { int status = ISD200_GOOD; - unsigned char regs[8]; + unsigned char *regs = us->iobuf; unsigned long endTime; struct isd200_info *info = (struct isd200_info *)us->extra; int recheckAsMaster = FALSE; @@ -856,7 +857,7 @@ break; status = isd200_action( us, ACTION_READ_STATUS, - regs, sizeof(regs) ); + regs, 8 ); if ( status != ISD200_GOOD ) break; diff -Nru a/drivers/usb/storage/jumpshot.c b/drivers/usb/storage/jumpshot.c --- a/drivers/usb/storage/jumpshot.c Sun Jul 27 10:13:40 2003 +++ b/drivers/usb/storage/jumpshot.c Sun Jul 27 10:13:40 2003 @@ -86,7 +86,6 @@ static int jumpshot_get_status(struct us_data *us) { - unsigned char reply; int rc; if (!us) @@ -94,14 +93,14 @@ // send the setup rc = usb_stor_ctrl_transfer(us, us->recv_ctrl_pipe, - 0, 0xA0, 0, 7, &reply, 1); + 0, 0xA0, 0, 7, us->iobuf, 1); if (rc != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; - if (reply != 0x50) { + if (us->iobuf[0] != 0x50) { US_DEBUGP("jumpshot_get_status: 0x%2x\n", - (unsigned short) (reply)); + us->iobuf[0]); return USB_STOR_TRANSPORT_ERROR; } @@ -115,7 +114,7 @@ unsigned char *dest, int use_sg) { - unsigned char command[] = { 0, 0, 0, 0, 0, 0xe0, 0x20 }; + unsigned char *command = us->iobuf; unsigned char *buffer = NULL; unsigned char *ptr; unsigned char thistime; @@ -154,7 +153,8 @@ command[3] = (sector >> 8) & 0xFF; command[4] = (sector >> 16) & 0xFF; - command[5] |= (sector >> 24) & 0x0F; + command[5] = 0xE0 | ((sector >> 24) & 0x0F); + command[6] = 0x20; // send the setup + command result = usb_stor_ctrl_transfer(us, us->send_ctrl_pipe, @@ -199,7 +199,7 @@ unsigned char *src, int use_sg) { - unsigned char command[7] = { 0, 0, 0, 0, 0, 0xE0, 0x30 }; + unsigned char *command = us->iobuf; unsigned char *buffer = NULL; unsigned char *ptr; unsigned char thistime; @@ -240,7 +240,8 @@ command[3] = (sector >> 8) & 0xFF; command[4] = (sector >> 16) & 0xFF; - command[5] |= (sector >> 24) & 0x0F; + command[5] = 0xE0 | ((sector >> 24) & 0x0F); + command[6] = 0x30; // send the setup + command result = usb_stor_ctrl_transfer(us, us->send_ctrl_pipe, @@ -291,13 +292,19 @@ static int jumpshot_id_device(struct us_data *us, struct jumpshot_info *info) { - unsigned char command[2] = { 0xe0, 0xec }; - unsigned char reply[512]; + unsigned char *command = us->iobuf; + unsigned char *reply; int rc; if (!us || !info) return USB_STOR_TRANSPORT_ERROR; + command[0] = 0xE0; + command[1] = 0xEC; + reply = kmalloc(512, GFP_NOIO); + if (!reply) + return USB_STOR_TRANSPORT_ERROR; + // send the setup rc = usb_stor_ctrl_transfer(us, us->send_ctrl_pipe, 0, 0x20, 0, 6, command, 2); @@ -305,20 +312,27 @@ if (rc != USB_STOR_XFER_GOOD) { US_DEBUGP("jumpshot_id_device: Gah! " "send_control for read_capacity failed\n"); - return rc; + rc = USB_STOR_TRANSPORT_ERROR; + goto leave; } // read the reply rc = jumpshot_bulk_read(us, reply, sizeof(reply)); - if (rc != USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; + if (rc != USB_STOR_XFER_GOOD) { + rc = USB_STOR_TRANSPORT_ERROR; + goto leave; + } info->sectors = ((u32)(reply[117]) << 24) | ((u32)(reply[116]) << 16) | ((u32)(reply[115]) << 8) | ((u32)(reply[114]) ); - return USB_STOR_TRANSPORT_GOOD; + rc = USB_STOR_TRANSPORT_GOOD; + + leave: + kfree(reply); + return rc; } static int jumpshot_handle_mode_sense(struct us_data *us, diff -Nru a/drivers/usb/storage/protocol.c b/drivers/usb/storage/protocol.c --- a/drivers/usb/storage/protocol.c Sun Jul 27 10:13:40 2003 +++ b/drivers/usb/storage/protocol.c Sun Jul 27 10:13:40 2003 @@ -130,8 +130,9 @@ void usb_stor_qic157_command(Scsi_Cmnd *srb, struct us_data *us) { /* Pad the ATAPI command with zeros + * * NOTE: This only works because a Scsi_Cmnd struct field contains - * a unsigned char cmnd[12], so we know we have storage available + * a unsigned char cmnd[16], so we know we have storage available */ for (; srb->cmd_len<12; srb->cmd_len++) srb->cmnd[srb->cmd_len] = 0; @@ -149,13 +150,10 @@ void usb_stor_ATAPI_command(Scsi_Cmnd *srb, struct us_data *us) { - int old_cmnd = 0; - - /* Fix some commands -- this is a form of mode translation - * ATAPI devices only accept 12 byte long commands + /* Pad the ATAPI command with zeros * * NOTE: This only works because a Scsi_Cmnd struct field contains - * a unsigned char cmnd[12], so we know we have storage available + * a unsigned char cmnd[16], so we know we have storage available */ /* Pad the ATAPI command with zeros */ @@ -165,60 +163,10 @@ /* set command length to 12 bytes */ srb->cmd_len = 12; - /* determine the correct (or minimum) data length for these commands */ - switch (srb->cmnd[0]) { - - /* change MODE_SENSE/MODE_SELECT from 6 to 10 byte commands */ - case MODE_SENSE: - case MODE_SELECT: - /* save the command so we can tell what it was */ - old_cmnd = srb->cmnd[0]; - - srb->cmnd[11] = 0; - srb->cmnd[10] = 0; - srb->cmnd[9] = 0; - srb->cmnd[8] = srb->cmnd[4]; - srb->cmnd[7] = 0; - srb->cmnd[6] = 0; - srb->cmnd[5] = 0; - srb->cmnd[4] = 0; - srb->cmnd[3] = 0; - srb->cmnd[2] = srb->cmnd[2]; - srb->cmnd[1] = srb->cmnd[1]; - srb->cmnd[0] = srb->cmnd[0] | 0x40; - break; - - /* change READ_6/WRITE_6 to READ_10/WRITE_10, which - * are ATAPI commands */ - case WRITE_6: - case READ_6: - srb->cmnd[11] = 0; - srb->cmnd[10] = 0; - srb->cmnd[9] = 0; - srb->cmnd[8] = srb->cmnd[4]; - srb->cmnd[7] = 0; - srb->cmnd[6] = 0; - srb->cmnd[5] = srb->cmnd[3]; - srb->cmnd[4] = srb->cmnd[2]; - srb->cmnd[3] = srb->cmnd[1] & 0x1F; - srb->cmnd[2] = 0; - srb->cmnd[1] = srb->cmnd[1] & 0xE0; - srb->cmnd[0] = srb->cmnd[0] | 0x20; - break; - } /* end switch on cmnd[0] */ - - /* convert MODE_SELECT data here */ - if (old_cmnd == MODE_SELECT) - usb_stor_scsiSense6to10(srb); - /* send the command to the transport layer */ usb_stor_invoke_transport(srb, us); - if (srb->result == SAM_STAT_GOOD) { - - /* Fix the MODE_SENSE data if we translated the command */ - if (old_cmnd == MODE_SENSE) - usb_stor_scsiSense10to6(srb); + if (srb->result == SAM_STAT_GOOD) { /* fix the INQUIRY data if necessary */ fix_inquiry_data(srb); } @@ -227,19 +175,23 @@ void usb_stor_ufi_command(Scsi_Cmnd *srb, struct us_data *us) { - int old_cmnd = 0; - /* fix some commands -- this is a form of mode translation * UFI devices only accept 12 byte long commands * * NOTE: This only works because a Scsi_Cmnd struct field contains - * a unsigned char cmnd[12], so we know we have storage available + * a unsigned char cmnd[16], so we know we have storage available */ + /* Pad the ATAPI command with zeros */ + for (; srb->cmd_len<12; srb->cmd_len++) + srb->cmnd[srb->cmd_len] = 0; + /* set command length to 12 bytes (this affects the transport layer) */ srb->cmd_len = 12; - /* determine the correct (or minimum) data length for these commands */ + /* XXX We should be constantly re-evaluating the need for these */ + + /* determine the correct data length for these commands */ switch (srb->cmnd[0]) { /* for INQUIRY, UFI devices only ever return 36 bytes */ @@ -247,33 +199,6 @@ srb->cmnd[4] = 36; break; - /* change MODE_SENSE/MODE_SELECT from 6 to 10 byte commands */ - case MODE_SENSE: - case MODE_SELECT: - /* save the command so we can tell what it was */ - old_cmnd = srb->cmnd[0]; - - srb->cmnd[11] = 0; - srb->cmnd[10] = 0; - srb->cmnd[9] = 0; - - /* if we're sending data, we send all. If getting data, - * get the minimum */ - if (srb->cmnd[0] == MODE_SELECT) - srb->cmnd[8] = srb->cmnd[4]; - else - srb->cmnd[8] = 8; - - srb->cmnd[7] = 0; - srb->cmnd[6] = 0; - srb->cmnd[5] = 0; - srb->cmnd[4] = 0; - srb->cmnd[3] = 0; - srb->cmnd[2] = srb->cmnd[2]; - srb->cmnd[1] = srb->cmnd[1]; - srb->cmnd[0] = srb->cmnd[0] | 0x40; - break; - /* again, for MODE_SENSE_10, we get the minimum (8) */ case MODE_SENSE_10: srb->cmnd[7] = 0; @@ -284,38 +209,12 @@ case REQUEST_SENSE: srb->cmnd[4] = 18; break; - - /* change READ_6/WRITE_6 to READ_10/WRITE_10, which - * are UFI commands */ - case WRITE_6: - case READ_6: - srb->cmnd[11] = 0; - srb->cmnd[10] = 0; - srb->cmnd[9] = 0; - srb->cmnd[8] = srb->cmnd[4]; - srb->cmnd[7] = 0; - srb->cmnd[6] = 0; - srb->cmnd[5] = srb->cmnd[3]; - srb->cmnd[4] = srb->cmnd[2]; - srb->cmnd[3] = srb->cmnd[1] & 0x1F; - srb->cmnd[2] = 0; - srb->cmnd[1] = srb->cmnd[1] & 0xE0; - srb->cmnd[0] = srb->cmnd[0] | 0x20; - break; } /* end switch on cmnd[0] */ - /* convert MODE_SELECT data here */ - if (old_cmnd == MODE_SELECT) - usb_stor_scsiSense6to10(srb); - /* send the command to the transport layer */ usb_stor_invoke_transport(srb, us); - if (srb->result == SAM_STAT_GOOD) { - - /* Fix the MODE_SENSE data if we translated the command */ - if (old_cmnd == MODE_SENSE) - usb_stor_scsiSense10to6(srb); + if (srb->result == SAM_STAT_GOOD) { /* Fix the data for an INQUIRY, if necessary */ fix_inquiry_data(srb); } @@ -323,68 +222,10 @@ void usb_stor_transparent_scsi_command(Scsi_Cmnd *srb, struct us_data *us) { - int old_cmnd = 0; - - /* This code supports devices which do not support {READ|WRITE}_6 - * Apparently, neither Windows or MacOS will use these commands, - * so some devices do not support them - */ - if (us->flags & US_FL_MODE_XLATE) { - US_DEBUGP("Invoking Mode Translation\n"); - /* save the old command for later */ - old_cmnd = srb->cmnd[0]; - - switch (srb->cmnd[0]) { - /* change READ_6/WRITE_6 to READ_10/WRITE_10 */ - case WRITE_6: - case READ_6: - srb->cmd_len = 12; - srb->cmnd[11] = 0; - srb->cmnd[10] = 0; - srb->cmnd[9] = 0; - srb->cmnd[8] = srb->cmnd[4]; - srb->cmnd[7] = 0; - srb->cmnd[6] = 0; - srb->cmnd[5] = srb->cmnd[3]; - srb->cmnd[4] = srb->cmnd[2]; - srb->cmnd[3] = srb->cmnd[1] & 0x1F; - srb->cmnd[2] = 0; - srb->cmnd[1] = srb->cmnd[1] & 0xE0; - srb->cmnd[0] = srb->cmnd[0] | 0x20; - break; - - /* convert MODE_SELECT data here */ - case MODE_SENSE: - case MODE_SELECT: - srb->cmd_len = 12; - srb->cmnd[11] = 0; - srb->cmnd[10] = 0; - srb->cmnd[9] = 0; - srb->cmnd[8] = srb->cmnd[4]; - srb->cmnd[7] = 0; - srb->cmnd[6] = 0; - srb->cmnd[5] = 0; - srb->cmnd[4] = 0; - srb->cmnd[3] = 0; - srb->cmnd[2] = srb->cmnd[2]; - srb->cmnd[1] = srb->cmnd[1]; - srb->cmnd[0] = srb->cmnd[0] | 0x40; - break; - } /* switch (srb->cmnd[0]) */ - } /* if (us->flags & US_FL_MODE_XLATE) */ - - /* convert MODE_SELECT data here */ - if ((us->flags & US_FL_MODE_XLATE) && (old_cmnd == MODE_SELECT)) - usb_stor_scsiSense6to10(srb); - /* send the command to the transport layer */ usb_stor_invoke_transport(srb, us); - if (srb->result == SAM_STAT_GOOD) { - - /* Fix the MODE_SENSE data if we translated the command */ - if ((us->flags & US_FL_MODE_XLATE) && (old_cmnd == MODE_SENSE)) - usb_stor_scsiSense10to6(srb); + if (srb->result == SAM_STAT_GOOD) { /* Fix the INQUIRY data if necessary */ fix_inquiry_data(srb); diff -Nru a/drivers/usb/storage/protocol.h b/drivers/usb/storage/protocol.h --- a/drivers/usb/storage/protocol.h Sun Jul 27 10:13:44 2003 +++ b/drivers/usb/storage/protocol.h Sun Jul 27 10:13:44 2003 @@ -41,7 +41,7 @@ #ifndef _PROTOCOL_H_ #define _PROTOCOL_H_ -#include +#include #include "scsi.h" #include "usb.h" diff -Nru a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c --- a/drivers/usb/storage/scsiglue.c Sun Jul 27 10:13:45 2003 +++ b/drivers/usb/storage/scsiglue.c Sun Jul 27 10:13:45 2003 @@ -263,7 +263,6 @@ #define DO_FLAG(a) if (f & US_FL_##a) pos += sprintf(pos, " " #a) DO_FLAG(SINGLE_LUN); - DO_FLAG(MODE_XLATE); DO_FLAG(SCM_MULT_TARG); DO_FLAG(FIX_INQUIRY); DO_FLAG(FIX_CAPACITY); @@ -345,500 +344,4 @@ [7] = 0x0a, /* additional length */ [12] = 0x24 /* Invalid Field in CDB */ }; - -#define USB_STOR_SCSI_SENSE_HDRSZ 4 -#define USB_STOR_SCSI_SENSE_10_HDRSZ 8 - -struct usb_stor_scsi_sense_hdr -{ - __u8* dataLength; - __u8* mediumType; - __u8* devSpecParms; - __u8* blkDescLength; -}; - -typedef struct usb_stor_scsi_sense_hdr Usb_Stor_Scsi_Sense_Hdr; - -union usb_stor_scsi_sense_hdr_u -{ - Usb_Stor_Scsi_Sense_Hdr hdr; - __u8* array[USB_STOR_SCSI_SENSE_HDRSZ]; -}; - -typedef union usb_stor_scsi_sense_hdr_u Usb_Stor_Scsi_Sense_Hdr_u; - -struct usb_stor_scsi_sense_hdr_10 -{ - __u8* dataLengthMSB; - __u8* dataLengthLSB; - __u8* mediumType; - __u8* devSpecParms; - __u8* reserved1; - __u8* reserved2; - __u8* blkDescLengthMSB; - __u8* blkDescLengthLSB; -}; - -typedef struct usb_stor_scsi_sense_hdr_10 Usb_Stor_Scsi_Sense_Hdr_10; - -union usb_stor_scsi_sense_hdr_10_u -{ - Usb_Stor_Scsi_Sense_Hdr_10 hdr; - __u8* array[USB_STOR_SCSI_SENSE_10_HDRSZ]; -}; - -typedef union usb_stor_scsi_sense_hdr_10_u Usb_Stor_Scsi_Sense_Hdr_10_u; - -void usb_stor_scsiSenseParseBuffer( Scsi_Cmnd* , Usb_Stor_Scsi_Sense_Hdr_u*, - Usb_Stor_Scsi_Sense_Hdr_10_u*, int* ); - -int usb_stor_scsiSense10to6( Scsi_Cmnd* the10 ) -{ - __u8 *buffer=0; - int outputBufferSize = 0; - int length=0; - struct scatterlist *sg = 0; - int i=0, j=0, element=0; - Usb_Stor_Scsi_Sense_Hdr_u the6Locations; - Usb_Stor_Scsi_Sense_Hdr_10_u the10Locations; - int sb=0,si=0,db=0,di=0; - int sgLength=0; - - US_DEBUGP("-- converting 10 byte sense data to 6 byte\n"); - the10->cmnd[0] = the10->cmnd[0] & 0xBF; - - /* Determine buffer locations */ - usb_stor_scsiSenseParseBuffer( the10, &the6Locations, &the10Locations, - &length ); - - /* Work out minimum buffer to output */ - outputBufferSize = *the10Locations.hdr.dataLengthLSB; - outputBufferSize += USB_STOR_SCSI_SENSE_HDRSZ; - - /* Check to see if we need to trucate the output */ - if ( outputBufferSize > length ) - { - printk( KERN_WARNING USB_STORAGE - "Had to truncate MODE_SENSE_10 buffer into MODE_SENSE.\n" ); - printk( KERN_WARNING USB_STORAGE - "outputBufferSize is %d and length is %d.\n", - outputBufferSize, length ); - } - outputBufferSize = length; - - /* Data length */ - if ( *the10Locations.hdr.dataLengthMSB != 0 ) /* MSB must be zero */ - { - printk( KERN_WARNING USB_STORAGE - "Command will be truncated to fit in SENSE6 buffer.\n" ); - *the6Locations.hdr.dataLength = 0xff; - } - else - { - *the6Locations.hdr.dataLength = *the10Locations.hdr.dataLengthLSB; - } - - /* Medium type and DevSpecific parms */ - *the6Locations.hdr.mediumType = *the10Locations.hdr.mediumType; - *the6Locations.hdr.devSpecParms = *the10Locations.hdr.devSpecParms; - - /* Block descriptor length */ - if ( *the10Locations.hdr.blkDescLengthMSB != 0 ) /* MSB must be zero */ - { - printk( KERN_WARNING USB_STORAGE - "Command will be truncated to fit in SENSE6 buffer.\n" ); - *the6Locations.hdr.blkDescLength = 0xff; - } - else - { - *the6Locations.hdr.blkDescLength = *the10Locations.hdr.blkDescLengthLSB; - } - - if ( the10->use_sg == 0 ) - { - buffer = the10->request_buffer; - /* Copy the rest of the data */ - memmove( &(buffer[USB_STOR_SCSI_SENSE_HDRSZ]), - &(buffer[USB_STOR_SCSI_SENSE_10_HDRSZ]), - outputBufferSize - USB_STOR_SCSI_SENSE_HDRSZ ); - /* initialise last bytes left in buffer due to smaller header */ - memset( &(buffer[outputBufferSize - -(USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ)]), - 0, - USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ ); - } - else - { - sg = (struct scatterlist *) the10->request_buffer; - /* scan through this scatterlist and figure out starting positions */ - for ( i=0; i < the10->use_sg; i++) - { - sgLength = sg[i].length; - for ( j=0; juse_sg; - } - element++; - } - } - - /* Now we know where to start the copy from */ - element = USB_STOR_SCSI_SENSE_HDRSZ; - while ( element < outputBufferSize - -(USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ) ) - { - /* check limits */ - if ( sb >= the10->use_sg || - si >= sg[sb].length || - db >= the10->use_sg || - di >= sg[db].length ) - { - printk( KERN_ERR USB_STORAGE - "Buffer overrun averted, this shouldn't happen!\n" ); - break; - } - - /* copy one byte */ - { - char *src = sg_address(sg[sb]) + si; - char *dst = sg_address(sg[db]) + di; - - *dst = *src; - } - - /* get next destination */ - if ( sg[db].length-1 == di ) - { - db++; - di=0; - } - else - { - di++; - } - - /* get next source */ - if ( sg[sb].length-1 == si ) - { - sb++; - si=0; - } - else - { - si++; - } - - element++; - } - /* zero the remaining bytes */ - while ( element < outputBufferSize ) - { - /* check limits */ - if ( db >= the10->use_sg || - di >= sg[db].length ) - { - printk( KERN_ERR USB_STORAGE - "Buffer overrun averted, this shouldn't happen!\n" ); - break; - } - - *(char*)(sg_address(sg[db])) = 0; - - /* get next destination */ - if ( sg[db].length-1 == di ) - { - db++; - di=0; - } - else - { - di++; - } - element++; - } - } - - /* All done any everything was fine */ - return 0; -} - -int usb_stor_scsiSense6to10( Scsi_Cmnd* the6 ) -{ - /* will be used to store part of buffer */ - __u8 tempBuffer[USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ], - *buffer=0; - int outputBufferSize = 0; - int length=0; - struct scatterlist *sg = 0; - int i=0, j=0, element=0; - Usb_Stor_Scsi_Sense_Hdr_u the6Locations; - Usb_Stor_Scsi_Sense_Hdr_10_u the10Locations; - int sb=0,si=0,db=0,di=0; - int lsb=0,lsi=0,ldb=0,ldi=0; - - US_DEBUGP("-- converting 6 byte sense data to 10 byte\n"); - the6->cmnd[0] = the6->cmnd[0] | 0x40; - - /* Determine buffer locations */ - usb_stor_scsiSenseParseBuffer( the6, &the6Locations, &the10Locations, - &length ); - - /* Work out minimum buffer to output */ - outputBufferSize = *the6Locations.hdr.dataLength; - outputBufferSize += USB_STOR_SCSI_SENSE_10_HDRSZ; - - /* Check to see if we need to trucate the output */ - if ( outputBufferSize > length ) - { - printk( KERN_WARNING USB_STORAGE - "Had to truncate MODE_SENSE into MODE_SENSE_10 buffer.\n" ); - printk( KERN_WARNING USB_STORAGE - "outputBufferSize is %d and length is %d.\n", - outputBufferSize, length ); - } - outputBufferSize = length; - - /* Block descriptor length - save these before overwriting */ - tempBuffer[2] = *the10Locations.hdr.blkDescLengthMSB; - tempBuffer[3] = *the10Locations.hdr.blkDescLengthLSB; - *the10Locations.hdr.blkDescLengthLSB = *the6Locations.hdr.blkDescLength; - *the10Locations.hdr.blkDescLengthMSB = 0; - - /* reserved - save these before overwriting */ - tempBuffer[0] = *the10Locations.hdr.reserved1; - tempBuffer[1] = *the10Locations.hdr.reserved2; - *the10Locations.hdr.reserved1 = *the10Locations.hdr.reserved2 = 0; - - /* Medium type and DevSpecific parms */ - *the10Locations.hdr.devSpecParms = *the6Locations.hdr.devSpecParms; - *the10Locations.hdr.mediumType = *the6Locations.hdr.mediumType; - - /* Data length */ - *the10Locations.hdr.dataLengthLSB = *the6Locations.hdr.dataLength; - *the10Locations.hdr.dataLengthMSB = 0; - - if ( !the6->use_sg ) - { - buffer = the6->request_buffer; - /* Copy the rest of the data */ - memmove( &(buffer[USB_STOR_SCSI_SENSE_10_HDRSZ]), - &(buffer[USB_STOR_SCSI_SENSE_HDRSZ]), - outputBufferSize-USB_STOR_SCSI_SENSE_10_HDRSZ ); - /* Put the first four bytes (after header) in place */ - memcpy( &(buffer[USB_STOR_SCSI_SENSE_10_HDRSZ]), - tempBuffer, - USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ ); - } - else - { - sg = (struct scatterlist *) the6->request_buffer; - /* scan through this scatterlist and figure out ending positions */ - for ( i=0; i < the6->use_sg; i++) - { - for ( j=0; juse_sg; - break; - } - element++; - } - } - /* scan through this scatterlist and figure out starting positions */ - element = length-1; - /* destination is the last element */ - db=the6->use_sg-1; - di=sg[db].length-1; - for ( i=the6->use_sg-1; i >= 0; i--) - { - for ( j=sg[i].length-1; j>=0; j-- ) - { - /* get to end of header and find source for copy */ - if ( element == length - 1 - - (USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ) ) - { - sb=i; - si=j; - /* we've found both sets now, exit loops */ - j=-1; - i=-1; - } - element--; - } - } - /* Now we know where to start the copy from */ - element = length-1 - - (USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ); - while ( element >= USB_STOR_SCSI_SENSE_10_HDRSZ ) - { - /* check limits */ - if ( ( sb <= lsb && si < lsi ) || - ( db <= ldb && di < ldi ) ) - { - printk( KERN_ERR USB_STORAGE - "Buffer overrun averted, this shouldn't happen!\n" ); - break; - } - - /* copy one byte */ - { - char *src = sg_address(sg[sb]) + si; - char *dst = sg_address(sg[db]) + di; - - *dst = *src; - } - - /* get next destination */ - if ( di == 0 ) - { - db--; - di=sg[db].length-1; - } - else - { - di--; - } - - /* get next source */ - if ( si == 0 ) - { - sb--; - si=sg[sb].length-1; - } - else - { - si--; - } - - element--; - } - /* copy the remaining four bytes */ - while ( element >= USB_STOR_SCSI_SENSE_HDRSZ ) - { - /* check limits */ - if ( db <= ldb && di < ldi ) - { - printk( KERN_ERR USB_STORAGE - "Buffer overrun averted, this shouldn't happen!\n" ); - break; - } - - { - char *dst = sg_address(sg[db]) + di; - - *dst = tempBuffer[element-USB_STOR_SCSI_SENSE_HDRSZ]; - } - - - /* get next destination */ - if ( di == 0 ) - { - db--; - di=sg[db].length-1; - } - else - { - di--; - } - element--; - } - } - - /* All done and everything was fine */ - return 0; -} - -void usb_stor_scsiSenseParseBuffer( Scsi_Cmnd* srb, Usb_Stor_Scsi_Sense_Hdr_u* the6, - Usb_Stor_Scsi_Sense_Hdr_10_u* the10, - int* length_p ) - -{ - int i = 0, j=0, element=0; - struct scatterlist *sg = 0; - int length = 0; - __u8* buffer=0; - - /* are we scatter-gathering? */ - if ( srb->use_sg != 0 ) - { - /* loop over all the scatter gather structures and - * get pointer to the data members in the headers - * (also work out the length while we're here) - */ - sg = (struct scatterlist *) srb->request_buffer; - for (i = 0; i < srb->use_sg; i++) - { - length += sg[i].length; - /* We only do the inner loop for the headers */ - if ( element < USB_STOR_SCSI_SENSE_10_HDRSZ ) - { - /* scan through this scatterlist */ - for ( j=0; jarray[element] = sg_address(sg[i]) + j; - the10->array[element] = sg_address(sg[i]) + j; - - } - else if ( element < USB_STOR_SCSI_SENSE_10_HDRSZ ) - { - /* only the longer headers still cares now */ - the10->array[element] = sg_address(sg[i]) + j; - - } - /* increase element counter */ - element++; - } - } - } - } - else - { - length = srb->request_bufflen; - buffer = srb->request_buffer; - if ( length < USB_STOR_SCSI_SENSE_10_HDRSZ ) - printk( KERN_ERR USB_STORAGE - "Buffer length smaller than header!!" ); - for( i=0; iarray[i] = &(buffer[i]); - the10->array[i] = &(buffer[i]); - } - else - { - the10->array[i] = &(buffer[i]); - } - } - } - - /* Set value of length passed in */ - *length_p = length; -} diff -Nru a/drivers/usb/storage/scsiglue.h b/drivers/usb/storage/scsiglue.h --- a/drivers/usb/storage/scsiglue.h Sun Jul 27 10:13:46 2003 +++ b/drivers/usb/storage/scsiglue.h Sun Jul 27 10:13:46 2003 @@ -41,7 +41,7 @@ #ifndef _SCSIGLUE_H_ #define _SCSIGLUE_H_ -#include +#include #include "scsi.h" #include "hosts.h" diff -Nru a/drivers/usb/storage/sddr09.c b/drivers/usb/storage/sddr09.c --- a/drivers/usb/storage/sddr09.c Sun Jul 27 10:13:50 2003 +++ b/drivers/usb/storage/sddr09.c Sun Jul 27 10:13:50 2003 @@ -261,12 +261,13 @@ */ static int sddr09_test_unit_ready(struct us_data *us) { - unsigned char command[6] = { - 0, LUNBITS, 0, 0, 0, 0 - }; + unsigned char *command = us->iobuf; int result; - result = sddr09_send_scsi_command(us, command, sizeof(command)); + memset(command, 0, 6); + command[1] = LUNBITS; + + result = sddr09_send_scsi_command(us, command, 6); US_DEBUGP("sddr09_test_unit_ready returns %d\n", result); @@ -281,12 +282,15 @@ */ static int sddr09_request_sense(struct us_data *us, unsigned char *sensebuf, int buflen) { - unsigned char command[12] = { - 0x03, LUNBITS, 0, 0, buflen, 0, 0, 0, 0, 0, 0, 0 - }; + unsigned char *command = us->iobuf; int result; - result = sddr09_send_scsi_command(us, command, sizeof(command)); + memset(command, 0, 12); + command[0] = 0x03; + command[1] = LUNBITS; + command[4] = buflen; + + result = sddr09_send_scsi_command(us, command, 12); if (result != USB_STOR_TRANSPORT_GOOD) { US_DEBUGP("request sense failed\n"); return result; @@ -331,20 +335,23 @@ int nr_of_pages, int bulklen, unsigned char *buf, int use_sg) { - unsigned char command[12] = { - 0xe8, LUNBITS | x, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }; + unsigned char *command = us->iobuf; int result; + command[0] = 0xE8; + command[1] = LUNBITS | x; command[2] = MSB_of(fromaddress>>16); command[3] = LSB_of(fromaddress>>16); command[4] = MSB_of(fromaddress & 0xFFFF); command[5] = LSB_of(fromaddress & 0xFFFF); - + command[6] = 0; + command[7] = 0; + command[8] = 0; + command[9] = 0; command[10] = MSB_of(nr_of_pages); command[11] = LSB_of(nr_of_pages); - result = sddr09_send_scsi_command(us, command, sizeof(command)); + result = sddr09_send_scsi_command(us, command, 12); if (result != USB_STOR_TRANSPORT_GOOD) { US_DEBUGP("Result for send_control in sddr09_read2%d %d\n", @@ -458,17 +465,18 @@ */ static int sddr09_erase(struct us_data *us, unsigned long Eaddress) { - unsigned char command[12] = { - 0xea, LUNBITS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }; + unsigned char *command = us->iobuf; int result; + memset(command, 0, 12); + command[0] = 0xEA; + command[1] = LUNBITS; command[6] = MSB_of(Eaddress>>16); command[7] = LSB_of(Eaddress>>16); command[8] = MSB_of(Eaddress & 0xFFFF); command[9] = LSB_of(Eaddress & 0xFFFF); - result = sddr09_send_scsi_command(us, command, sizeof(command)); + result = sddr09_send_scsi_command(us, command, 12); if (result != USB_STOR_TRANSPORT_GOOD) US_DEBUGP("Result for send_control in sddr09_erase %d\n", @@ -493,11 +501,12 @@ unsigned long Waddress, unsigned long Eaddress, int nr_of_pages, int bulklen, unsigned char *buf, int use_sg) { - unsigned char command[12] = { - 0xe9, LUNBITS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }; + unsigned char *command = us->iobuf; int result; + command[0] = 0xE9; + command[1] = LUNBITS; + command[2] = MSB_of(Waddress>>16); command[3] = LSB_of(Waddress>>16); command[4] = MSB_of(Waddress & 0xFFFF); @@ -511,7 +520,7 @@ command[10] = MSB_of(nr_of_pages); command[11] = LSB_of(nr_of_pages); - result = sddr09_send_scsi_command(us, command, sizeof(command)); + result = sddr09_send_scsi_command(us, command, 12); if (result != USB_STOR_TRANSPORT_GOOD) { US_DEBUGP("Result for send_control in sddr09_writeX %d\n", @@ -554,15 +563,15 @@ */ static int sddr09_read_sg_test_only(struct us_data *us) { - unsigned char command[15] = { - 0xe7, LUNBITS, 0 - }; + unsigned char *command = us->iobuf; int result, bulklen, nsg, ct; unsigned char *buf; unsigned long address; nsg = bulklen = 0; - + command[0] = 0xE7; + command[1] = LUNBITS; + command[2] = 0; address = 040000; ct = 1; nsg++; bulklen += (ct << 9); @@ -628,20 +637,22 @@ static int sddr09_read_status(struct us_data *us, unsigned char *status) { - unsigned char command[12] = { - 0xec, LUNBITS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }; - unsigned char data[64]; + unsigned char *command = us->iobuf; + unsigned char *data = us->iobuf; int result; US_DEBUGP("Reading status...\n"); - result = sddr09_send_scsi_command(us, command, sizeof(command)); + memset(command, 0, 12); + command[0] = 0xEC; + command[1] = LUNBITS; + + result = sddr09_send_scsi_command(us, command, 12); if (result != USB_STOR_TRANSPORT_GOOD) return result; result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, - data, sizeof(data), NULL); + data, 64, NULL); *status = data[0]; return (result == USB_STOR_XFER_GOOD ? USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR); @@ -953,13 +964,15 @@ */ static int sddr09_read_deviceID(struct us_data *us, unsigned char *deviceID) { - unsigned char command[12] = { - 0xed, LUNBITS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }; - unsigned char content[64]; + unsigned char *command = us->iobuf; + unsigned char *content = us->iobuf; int result, i; - result = sddr09_send_scsi_command(us, command, sizeof(command)); + memset(command, 0, 12); + command[0] = 0xED; + command[1] = LUNBITS; + + result = sddr09_send_scsi_command(us, command, 12); if (result != USB_STOR_TRANSPORT_GOOD) return result; @@ -1006,11 +1019,13 @@ static int sddr09_reset(struct us_data *us) { - unsigned char command[12] = { - 0xeb, LUNBITS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }; + unsigned char *command = us->iobuf; + + memset(command, 0, 12); + command[0] = 0xEB; + command[1] = LUNBITS; - return sddr09_send_scsi_command(us, command, sizeof(command)); + return sddr09_send_scsi_command(us, command, 12); } #endif @@ -1313,7 +1328,7 @@ int sddr09_init(struct us_data *us) { int result; - unsigned char data[18]; + unsigned char *data = us->iobuf; result = sddr09_send_command(us, 0x01, USB_DIR_IN, data, 2); if (result != USB_STOR_TRANSPORT_GOOD) { @@ -1333,10 +1348,10 @@ US_DEBUGP("SDDR09init: %02X %02X\n", data[0], data[1]); // get 07 00 - result = sddr09_request_sense(us, data, sizeof(data)); + result = sddr09_request_sense(us, data, 18); if (result == USB_STOR_TRANSPORT_GOOD && data[2] != 0) { int j; - for (j=0; jiobuf; + unsigned char *status = us->iobuf; struct sddr55_card_info *info = (struct sddr55_card_info *)us->extra; /* send command */ + memset(command, 0, 8); + command[5] = 0xB0; + command[7] = 0x80; result = sddr55_bulk_transport(us, SCSI_DATA_WRITE, command, 8); @@ -158,10 +159,8 @@ int use_sg) { int result = USB_STOR_TRANSPORT_GOOD; - unsigned char command[8] = { - 0, 0, 0, 0, 0, 0xb0, 0, 0x85 - }; - unsigned char status[8]; + unsigned char *command = us->iobuf; + unsigned char *status = us->iobuf; struct sddr55_card_info *info = (struct sddr55_card_info *)us->extra; unsigned int pba; @@ -205,11 +204,15 @@ address = (pba << info->blockshift) + page; + command[0] = 0; command[1] = LSB_of(address>>16); command[2] = LSB_of(address>>8); command[3] = LSB_of(address); + command[4] = 0; + command[5] = 0xB0; command[6] = LSB_of(pages << (1 - info->smallpageshift)); + command[7] = 0x85; /* send command */ result = sddr55_bulk_transport(us, @@ -274,10 +277,8 @@ int use_sg) { int result = USB_STOR_TRANSPORT_GOOD; - unsigned char command[8] = { - 0, 0, 0, 0, 0, 0xb0, 0, 0x86 - }; - unsigned char status[8]; + unsigned char *command = us->iobuf; + unsigned char *status = us->iobuf; struct sddr55_card_info *info = (struct sddr55_card_info *)us->extra; unsigned int pba; @@ -380,6 +381,8 @@ command[6] = MSB_of(lba % 1000); command[4] |= LSB_of(pages >> info->smallpageshift); + command[5] = 0xB0; + command[7] = 0x86; /* send command */ result = sddr55_bulk_transport(us, @@ -473,11 +476,12 @@ unsigned char *deviceID) { int result; - unsigned char command[8] = { - 0, 0, 0, 0, 0, 0xb0, 0, 0x84 - }; - unsigned char content[64]; + unsigned char *command = us->iobuf; + unsigned char *content = us->iobuf; + memset(command, 0, 8); + command[5] = 0xB0; + command[7] = 0x84; result = sddr55_bulk_transport(us, SCSI_DATA_WRITE, command, 8); US_DEBUGP("Result of send_control for device ID is %d\n", @@ -598,7 +602,7 @@ struct sddr55_card_info *info = (struct sddr55_card_info *)(us->extra); int numblocks; unsigned char *buffer; - unsigned char command[8] = { 0, 0, 0, 0, 0, 0xb0, 0, 0x8a}; + unsigned char *command = us->iobuf; int i; unsigned short lba; unsigned short max_lba; @@ -614,7 +618,10 @@ if (!buffer) return -1; + memset(command, 0, 8); + command[5] = 0xB0; command[6] = numblocks * 2 / 256; + command[7] = 0x8A; result = sddr55_bulk_transport(us, SCSI_DATA_WRITE, command, 8); diff -Nru a/drivers/usb/storage/transport.h b/drivers/usb/storage/transport.h --- a/drivers/usb/storage/transport.h Sun Jul 27 10:13:44 2003 +++ b/drivers/usb/storage/transport.h Sun Jul 27 10:13:44 2003 @@ -42,7 +42,7 @@ #define _TRANSPORT_H_ #include -#include +#include #include "usb.h" #include "scsi.h" diff -Nru a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h --- a/drivers/usb/storage/unusual_devs.h Sun Jul 27 10:13:50 2003 +++ b/drivers/usb/storage/unusual_devs.h Sun Jul 27 10:13:50 2003 @@ -119,7 +119,7 @@ UNUSUAL_DEV( 0x04cb, 0x0100, 0x0000, 0x2210, "Fujifilm", "FinePix 1400Zoom", - US_SC_8070, US_PR_CBI, NULL, US_FL_FIX_INQUIRY), + US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY), /* Reported by Peter Wächtler * The device needs the flags only. @@ -236,7 +236,7 @@ UNUSUAL_DEV( 0x054c, 0x0010, 0x0106, 0x0450, "Sony", "DSC-S30/S70/S75/505V/F505/F707/F717/P8", - US_SC_SCSI, US_PR_CB, NULL, + US_SC_SCSI, US_PR_DEVICE, NULL, US_FL_SINGLE_LUN | US_FL_MODE_XLATE ), /* Reported by wim@geeks.nl */ @@ -555,7 +555,7 @@ UNUSUAL_DEV( 0x08ca, 0x2011, 0x0000, 0x9999, "AIPTEK", "PocketCAM 3Mega", - US_SC_SCSI, US_PR_BULK, NULL, + US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_MODE_XLATE ), /* aeb */ diff -Nru a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c --- a/drivers/usb/storage/usb.c Sun Jul 27 10:13:43 2003 +++ b/drivers/usb/storage/usb.c Sun Jul 27 10:13:43 2003 @@ -958,6 +958,8 @@ goto BadDevice; } + scsi_scan_host(us->host); + printk(KERN_DEBUG "WARNING: USB Mass Storage data integrity not assured\n"); printk(KERN_DEBUG diff -Nru a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h --- a/drivers/usb/storage/usb.h Sun Jul 27 10:13:48 2003 +++ b/drivers/usb/storage/usb.h Sun Jul 27 10:13:48 2003 @@ -45,7 +45,7 @@ #define _USB_H_ #include -#include +#include #include #include #include @@ -69,11 +69,10 @@ /* Flag definitions: these entries are static */ #define US_FL_SINGLE_LUN 0x00000001 /* allow access to only LUN 0 */ -#define US_FL_MODE_XLATE 0x00000002 /* translate _6 to _10 commands for - Win/MacOS compatibility */ +#define US_FL_MODE_XLATE 0 /* [no longer used] */ #define US_FL_IGNORE_SER 0 /* [no longer used] */ #define US_FL_SCM_MULT_TARG 0x00000020 /* supports multiple targets */ -#define US_FL_FIX_INQUIRY 0x00000040 /* INQUIRY response needs fixing */ +#define US_FL_FIX_INQUIRY 0x00000040 /* INQUIRY response needs faking */ #define US_FL_FIX_CAPACITY 0x00000080 /* READ CAPACITY response too big */ /* Dynamic flag definitions: used in set_bit() etc. */ diff -Nru a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c --- a/drivers/usb/usb-skeleton.c Sun Jul 27 10:13:45 2003 +++ b/drivers/usb/usb-skeleton.c Sun Jul 27 10:13:45 2003 @@ -507,7 +507,7 @@ struct usb_endpoint_descriptor *endpoint; size_t buffer_size; int i; - int retval; + int retval = -ENOMEM; /* See if the device offered us matches what we can accept */ if ((udev->descriptor.idVendor != USB_SKEL_VENDOR_ID) || @@ -515,18 +515,11 @@ return -ENODEV; } - retval = usb_register_dev (interface, &skel_class); - if (retval) { - /* something prevented us from registering this driver */ - err ("Not able to get a minor for this device."); - goto exit; - } - /* allocate memory for our device state and initialize it */ dev = kmalloc (sizeof(struct usb_skel), GFP_KERNEL); if (dev == NULL) { err ("Out of memory"); - goto exit_minor; + goto error; } memset (dev, 0x00, sizeof (*dev)); @@ -603,24 +596,24 @@ /* allow device read, write and ioctl */ dev->present = 1; + /* we can register the device now, as it is ready */ + usb_set_intfdata (interface, dev); + retval = usb_register_dev (interface, &skel_class); + if (retval) { + /* something prevented us from registering this driver */ + err ("Not able to get a minor for this device."); + usb_set_intfdata (interface, NULL); + goto error; + } + + /* let the user know what node this device is now attached to */ info ("USB Skeleton device now attached to USBSkel-%d", dev->minor); - - goto exit; + return 0; error: skel_delete (dev); - dev = NULL; - -exit_minor: - usb_deregister_dev (interface, &skel_class); - -exit: - if (dev) { - usb_set_intfdata (interface, dev); - return 0; - } - return -ENODEV; + return retval; } diff -Nru a/drivers/video/Makefile b/drivers/video/Makefile --- a/drivers/video/Makefile Sun Jul 27 10:13:41 2003 +++ b/drivers/video/Makefile Sun Jul 27 10:13:41 2003 @@ -26,7 +26,7 @@ obj-$(CONFIG_FB_IGA) += igafb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_CONTROL) += controlfb.o obj-$(CONFIG_FB_PLATINUM) += platinumfb.o -obj-$(CONFIG_FB_VALKYRIE) += valkyriefb.o +obj-$(CONFIG_FB_VALKYRIE) += valkyriefb.o macmodes.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_CT65550) += chipsfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_ANAKIN) += anakinfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_CLPS711X) += clps711xfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o @@ -69,7 +69,7 @@ obj-$(CONFIG_FB_VIRTUAL) += vfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_HIT) += hitfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_E1355) += epson1355fb.o -obj-$(CONFIG_FB_PVR2) += pvr2fb.o +obj-$(CONFIG_FB_PVR2) += pvr2fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_VOODOO1) += sstfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_FFB) += ffb.o sbuslib.o cfbimgblt.o cfbcopyarea.o diff -Nru a/drivers/video/logo/logo.c b/drivers/video/logo/logo.c --- a/drivers/video/logo/logo.c Sun Jul 27 10:13:47 2003 +++ b/drivers/video/logo/logo.c Sun Jul 27 10:13:47 2003 @@ -66,7 +66,7 @@ #endif #ifdef CONFIG_LOGO_DEC_CLUT224 /* DEC Linux logo on MIPS/MIPS64 */ - if (mips_machgroup == MACH_GROUP_SGI) + if (mips_machgroup == MACH_GROUP_DEC) logo = &logo_dec_clut224; #endif #ifdef CONFIG_LOGO_MAC_CLUT224 diff -Nru a/drivers/video/macfb.c b/drivers/video/macfb.c --- a/drivers/video/macfb.c Sun Jul 27 10:13:41 2003 +++ b/drivers/video/macfb.c Sun Jul 27 10:13:41 2003 @@ -233,11 +233,11 @@ /* Loop until we get to the register we want */ for (i = 0; i < regno; i++) { - nubus_writeb(info->cmap[i].red >> 8, &dafb_cmap_regs->lut); + nubus_writeb(info->cmap.red[i] >> 8, &dafb_cmap_regs->lut); nop(); - nubus_writeb(info->cmap[i].green >> 8, &dafb_cmap_regs->lut); + nubus_writeb(info->cmap.green[i] >> 8, &dafb_cmap_regs->lut); nop(); - nubus_writeb(info->cmap[i].blue >> 8, &dafb_cmap_regs->lut); + nubus_writeb(info->cmap.blue[i] >> 8, &dafb_cmap_regs->lut); nop(); } } @@ -528,10 +528,10 @@ * != 0 for invalid regno. */ - if (regno >= info->cmap.len) + if (regno >= fb_info->cmap.len) return 1; - switch (info->var.bits_per_pixel) { + switch (fb_info->var.bits_per_pixel) { case 1: /* We shouldn't get here */ break; @@ -539,21 +539,21 @@ case 4: case 8: if (macfb_setpalette) - macfb_setpalette(regno, red, green, blue, info); + macfb_setpalette(regno, red, green, blue, fb_info); else return 1; break; case 16: - if (info->var.red.offset == 10) { + if (fb_info->var.red.offset == 10) { /* 1:5:5:5 */ - ((u32*) (info->pseudo_palette))[regno] = + ((u32*) (fb_info->pseudo_palette))[regno] = ((red & 0xf800) >> 1) | ((green & 0xf800) >> 6) | ((blue & 0xf800) >> 11) | ((transp != 0) << 15); } else { /* 0:5:6:5 */ - ((u32*) (info->pseudo_palette))[regno] = + ((u32*) (fb_info->pseudo_palette))[regno] = ((red & 0xf800) ) | ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11); @@ -565,19 +565,19 @@ red >>= 8; green >>= 8; blue >>= 8; - ((u32 *)(info->pseudo_palette))[regno] = - (red << info->var.red.offset) | - (green << info->var.green.offset) | - (blue << info->var.blue.offset); + ((u32 *)(fb_info->pseudo_palette))[regno] = + (red << fb_info->var.red.offset) | + (green << fb_info->var.green.offset) | + (blue << fb_info->var.blue.offset); break; case 32: red >>= 8; green >>= 8; blue >>= 8; - ((u32 *)(info->pseudo_palette))[regno] = - (red << info->var.red.offset) | - (green << info->var.green.offset) | - (blue << info->var.blue.offset); + ((u32 *)(fb_info->pseudo_palette))[regno] = + (red << fb_info->var.red.offset) | + (green << fb_info->var.green.offset) | + (blue << fb_info->var.blue.offset); break; } return 0; diff -Nru a/drivers/video/pvr2fb.c b/drivers/video/pvr2fb.c --- a/drivers/video/pvr2fb.c Sun Jul 27 10:13:41 2003 +++ b/drivers/video/pvr2fb.c Sun Jul 27 10:13:41 2003 @@ -4,7 +4,7 @@ * Dreamcast. * * Copyright (c) 2001 M. R. Brown - * Copyright (c) 2001 Paul Mundt + * Copyright (c) 2001, 2002, 2003 Paul Mundt * * This file is part of the LinuxDC project (linuxdc.sourceforge.net). * @@ -12,14 +12,15 @@ /* * This driver is mostly based on the excellent amifb and vfb sources. It uses - * an odd scheme for converting hardware values to/from framebuffer values, here are - * some hacked-up formulas: + * an odd scheme for converting hardware values to/from framebuffer values, + * here are some hacked-up formulas: * - * The Dreamcast has screen offsets from each side of its four borders and the start - * offsets of the display window. I used these values to calculate 'pseudo' values - * (think of them as placeholders) for the fb video mode, so that when it came time - * to convert these values back into their hardware values, I could just add mode- - * specific offsets to get the correct mode settings: + * The Dreamcast has screen offsets from each side of its four borders and + * the start offsets of the display window. I used these values to calculate + * 'pseudo' values (think of them as placeholders) for the fb video mode, so + * that when it came time to convert these values back into their hardware + * values, I could just add mode- specific offsets to get the correct mode + * settings: * * left_margin = diwstart_h - borderstart_h; * right_margin = borderstop_h - (diwstart_h + xres); @@ -29,9 +30,9 @@ * hsync_len = borderstart_h + (hsync_total - borderstop_h); * vsync_len = borderstart_v + (vsync_total - borderstop_v); * - * Then, when it's time to convert back to hardware settings, the only constants - * are the borderstart_* offsets, all other values are derived from the fb video - * mode: + * Then, when it's time to convert back to hardware settings, the only + * constants are the borderstart_* offsets, all other values are derived from + * the fb video mode: * * // PAL * borderstart_h = 116; @@ -57,7 +58,6 @@ #include #include #include -#include #ifdef CONFIG_SH_DREAMCAST #include @@ -66,14 +66,9 @@ #endif #ifdef CONFIG_MTRR - #include +#include #endif -#include