Index: head/UPDATING =================================================================== --- head/UPDATING (revision 355393) +++ head/UPDATING (revision 355394) @@ -1,2144 +1,2144 @@ Updating Information for FreeBSD current users. This file is maintained and copyrighted by M. Warner Losh . See end of file for further details. For commonly done items, please see the COMMON ITEMS: section later in the file. These instructions assume that you basically know what you are doing. If not, then please consult the FreeBSD handbook: https://www.freebsd.org/doc/en_US.ISO8859-1/books/handbook/makeworld.html Items affecting the ports and packages system can be found in /usr/ports/UPDATING. Please read that file before running portupgrade. NOTE TO PEOPLE WHO THINK THAT FreeBSD 13.x IS SLOW: FreeBSD 13.x has many debugging features turned on, in both the kernel and userland. These features attempt to detect incorrect use of system primitives, and encourage loud failure through extra sanity checking and fail stop semantics. They also substantially impact system performance. If you want to do performance measurement, benchmarking, and optimization, you'll want to turn them off. This includes various WITNESS- related kernel options, INVARIANTS, malloc debugging flags in userland, and various verbose features in the kernel. Many developers choose to disable these features on build machines to maximize performance. (To completely disable malloc debugging, define MALLOC_PRODUCTION in /etc/make.conf, or to merely disable the most expensive debugging functionality run "ln -s 'abort:false,junk:false' /etc/malloc.conf".) 20191120: The amd(8) automount daemon has been disabled by default, and will be removed in the future. As of FreeBSD 10.1 the autofs(5) is available for automounting. 20191107: The nctgpio and wbwd drivers have been moved to the superio bus. If you have one of these drivers in a kernel configuration, then you should add device superio to it. If you use one of these drivers as a module and you compile a custom set of modules, then you should add superio to the set. 20191021: KPIs for network drivers to access interface addresses have changed. Users need to recompile NIC driver modules together with kernel. 20191021: The net.link.tap.user_open sysctl no longer prevents user opening of already created /dev/tapNN devices. Access is still controlled by node permissions, just like tun devices. The net.link.tap.user_open sysctl is now used only to allow users to perform devfs cloning of tap devices, and the subsequent open may not succeed if the user is not in the appropriate group. This sysctl may be deprecated/removed completely in the future. 20191009: mips, powerpc, and sparc64 are no longer built as part of universe / tinderbox unless MAKE_OBSOLETE_GCC is defined. If not defined, mips, powerpc, and sparc64 builds will look for the xtoolchain binaries and if installed use them for universe builds. As llvm 9.0 becomes vetted for these architectures, they will be removed from the list. 20191009: Clang, llvm, lld, lldb, compiler-rt, libc++, libunwind and openmp have been upgraded to 9.0.0. Please see the 20141231 entry below for information about prerequisites and upgrading, if you are not already using clang 3.5.0 or higher. 20191003: The hpt27xx, hptmv, hptnr, and hptrr drivers have been removed from GENERIC. They are available as modules and can be loaded by adding to /boot/loader.conf hpt27xx_load="YES", hptmv_load="YES", hptnr_load="YES", or hptrr_load="YES", respectively. 20190913: ntpd no longer by default locks its pages in memory, allowing them to be paged out by the kernel. Use rlimit memlock to restore historic BSD behaviour. For example, add "rlimit memlock 32" to ntp.conf to lock up to 32 MB of ntpd address space in memory. 20190823: Several of ping6's options have been renamed for better consistency with ping. If you use any of -ARWXaghmrtwx, you must update your scripts. See ping6(8) for details. 20190727: The vfs.fusefs.sync_unmount and vfs.fusefs.init_backgrounded sysctls and the "-o sync_unmount" and "-o init_backgrounded" mount options have been removed from mount_fusefs(8). You can safely remove them from your scripts, because they had no effect. The vfs.fusefs.fix_broken_io, vfs.fusefs.sync_resize, vfs.fusefs.refresh_size, vfs.fusefs.mmap_enable, vfs.fusefs.reclaim_revoked, and vfs.fusefs.data_cache_invalidate sysctls have been removed. If you felt the need to set any of them to a non-default value, please tell asomers@FreeBSD.org why. 20190713: Default permissions on the /var/account/acct file (and copies of it rotated by periodic daily scripts) are changed from 0644 to 0640 because the file contains sensitive information that should not be world-readable. If the /var/account directory must be created by rc.d/accounting, the mode used is now 0750. Admins who use the accounting feature are encouraged to change the mode of an existing /var/account directory to 0750 or 0700. 20190620: Entropy collection and the /dev/random device are no longer optional components. The "device random" option has been removed. Implementations of distilling algorithms can still be made loadable with "options RANDOM_LOADABLE" (e.g., random_fortuna.ko). 20190612: Clang, llvm, lld, lldb, compiler-rt, libc++, libunwind and openmp have been upgraded to 8.0.1. Please see the 20141231 entry below for information about prerequisites and upgrading, if you are not already using clang 3.5.0 or higher. 20190608: A fix was applied to i386 kernel modules to avoid panics with dpcpu or vnet. Users need to recompile i386 kernel modules having pcpu or vnet sections or they will refuse to load. 20190513: User-wired pages now have their own counter, vm.stats.vm.v_user_wire_count. The vm.max_wired sysctl was renamed to vm.max_user_wired and changed from an unsigned int to an unsigned long. bhyve VMs wired with the -S are now subject to the user wiring limit; the vm.max_user_wired sysctl may need to be tuned to avoid running into the limit. 20190507: The IPSEC option has been removed from GENERIC. Users requiring ipsec(4) must now load the ipsec(4) kernel module. 20190507: The tap(4) driver has been folded into tun(4), and the module has been renamed to tuntap. You should update any kld_list="if_tap" or kld_list="if_tun" entries in /etc/rc.conf, if_tap_load="YES" or if_tun_load="YES" entries in /boot/loader.conf to load the if_tuntap module instead, and "device tap" or "device tun" entries in kernel config files to select the tuntap device instead. 20190418: The following knobs have been added related to tradeoffs between safe use of the random device and availability in the absence of entropy: kern.random.initial_seeding.bypass_before_seeding: tunable; set non-zero to bypass the random device prior to seeding, or zero to block random requests until the random device is initially seeded. For now, set to 1 (unsafe) by default to restore pre-r346250 boot availability properties. kern.random.initial_seeding.read_random_bypassed_before_seeding: read-only diagnostic sysctl that is set when bypass is enabled and read_random(9) is bypassed, to enable programmatic handling of this initial condition, if desired. kern.random.initial_seeding.arc4random_bypassed_before_seeding: Similar to the above, but for for arc4random(9) initial seeding. kern.random.initial_seeding.disable_bypass_warnings: tunable; set non-zero to disable warnings in dmesg when the same conditions are met as for the diagnostic sysctls above. Defaults to zero, i.e., produce warnings in dmesg when the conditions are met. 20190416: The loadable random module KPI has changed; the random_infra_init() routine now requires a 3rd function pointer for a bool (*)(void) method that returns true if the random device is seeded (and therefore unblocked). 20190404: r345895 reverts r320698. This implies that an nfsuserd(8) daemon built from head sources between r320757 (July 6, 2017) and r338192 (Aug. 22, 2018) will not work unless the "-use-udpsock" is added to the command line. nfsuserd daemons built from head sources that are post-r338192 are not affected and should continue to work. 20190320: The fuse(4) module has been renamed to fusefs(4) for consistency with other filesystems. You should update any kld_load="fuse" entries in /etc/rc.conf, fuse_load="YES" entries in /boot/loader.conf, and "options FUSE" entries in kernel config files. 20190304: Clang, llvm, lld, lldb, compiler-rt and libc++ have been upgraded to 8.0.0. Please see the 20141231 entry below for information about prerequisites and upgrading, if you are not already using clang 3.5.0 or higher. 20190226: geom_uzip(4) depends on the new module xz. If geom_uzip is statically compiled into your custom kernel, add 'device xz' statement to the kernel config. 20190219: drm and drm2 have been removed from the tree. Please see https://wiki.freebsd.org/Graphics for the latest information on migrating to the drm ports. 20190131: Iflib is no longer unconditionally compiled into the kernel. Drivers using iflib and statically compiled into the kernel, now require the 'device iflib' config option. For the same drivers loaded as modules on kernels not having 'device iflib', the iflib.ko module is loaded automatically. 20190125: The IEEE80211_AMPDU_AGE and AH_SUPPORT_AR5416 kernel configuration options no longer exist since r343219 and r343427 respectively; nothing uses them, so they should be just removed from custom kernel config files. 20181230: r342635 changes the way efibootmgr(8) works by requiring users to add the -b (bootnum) parameter for commands where the bootnum was previously specified with each option. For example 'efibootmgr -B 0001' is now 'efibootmgr -B -b 0001'. 20181220: r342286 modifies the NFSv4 server so that it obeys vfs.nfsd.nfs_privport in the same as it is applied to NFSv2 and 3. This implies that NFSv4 servers that have vfs.nfsd.nfs_privport set will only allow mounts from clients using a reserved port#. Since both the FreeBSD and Linux NFSv4 clients use reserved port#s by default, this should not affect most NFSv4 mounts. 20181219: The XLP config has been removed. We can't support 64-bit atomics in this kernel because it is running in 32-bit mode. XLP users must transition to running a 64-bit kernel (XLP64 or XLPN32). The mips GXEMUL support has been removed from FreeBSD. MALTA* + qemu is the preferred emulator today and we don't need two different ones. The old sibyte / swarm / Broadcom BCM1250 support has been removed from the mips port. 20181211: Clang, llvm, lld, lldb, compiler-rt and libc++ have been upgraded to 7.0.1. Please see the 20141231 entry below for information about prerequisites and upgrading, if you are not already using clang 3.5.0 or higher. 20181211: Remove the timed and netdate programs from the base tree. Setting the time with these daemons has been obsolete for over a decade. 20181126: On amd64, arm64 and armv7 (architectures that install LLVM's ld.lld linker as /usr/bin/ld) GNU ld is no longer installed as ld.bfd, as it produces broken binaries when ifuncs are in use. Users needing GNU ld should install the binutils port or package. 20181123: The BSD crtbegin and crtend code has been enabled by default. It has had extensive testing on amd64, arm64, and i386. It can be disabled by building a world with -DWITHOUT_BSD_CRTBEGIN. 20181115: The set of CTM commands (ctm, ctm_smail, ctm_rmail, ctm_dequeue) has been converted to a port (misc/ctm) and will be removed from FreeBSD-13. It is available as a package (ctm) for all supported FreeBSD versions. 20181110: The default newsyslog.conf(5) file has been changed to only include files in /etc/newsyslog.conf.d/ and /usr/local/etc/newsyslog.conf.d/ if the filenames end in '.conf' and do not begin with a '.'. You should check the configuration files in these two directories match this naming convention. You can verify which configuration files are being included using the command: $ newsyslog -Nrv 20181015: Ports for the DRM modules have been simplified. Now, amd64 users should just install the drm-kmod port. All others should install drm-legacy-kmod. Graphics hardware that's newer than about 2010 usually works with drm-kmod. For hardware older than 2013, however, some users will need to use drm-legacy-kmod if drm-kmod doesn't work for them. Hardware older than 2008 usually only works in drm-legacy-kmod. The graphics team can only commit to hardware made since 2013 due to the complexity of the market and difficulty to test all the older cards effectively. If you have hardware supported by drm-kmod, you are strongly encouraged to use that as you will get better support. Other than KPI chasing, drm-legacy-kmod will not be updated. As outlined elsewhere, the drm and drm2 modules will be eliminated from the src base soon (with a limited exception for arm). Please update to the package asap and report any issues to x11@freebsd.org. Generally, anybody using the drm*-kmod packages should add WITHOUT_DRM_MODULE=t and WITHOUT_DRM2_MODULE=t to avoid nasty cross-threading surprises, especially with automatic driver loading from X11 startup. These will become the defaults in 13-current shortly. 20181012: The ixlv(4) driver has been renamed to iavf(4). As a consequence, custom kernel and module loading configuration files must be updated accordingly. Moreover, interfaces previous presented as ixlvN to the system are now exposed as iavfN and network configuration files must be adjusted as necessary. 20181009: OpenSSL has been updated to version 1.1.1. This update included additional various API changes throughout the base system. It is important to rebuild third-party software after upgrading. The value of __FreeBSD_version has been bumped accordingly. 20181006: The legacy DRM modules and drivers have now been added to the loader's module blacklist, in favor of loading them with kld_list in rc.conf(5). The module blacklist may be overridden with the loader.conf(5) 'module_blacklist' variable, but loading them via rc.conf(5) is strongly encouraged. 20181002: The cam(4) based nda(4) driver will be used over nvd(4) by default on powerpc64. You may set 'options NVME_USE_NVD=1' in your kernel conf or loader tunable 'hw.nvme.use_nvd=1' if you wish to use the existing driver. Make sure to edit /boot/etc/kboot.conf and fstab to use the nda device name. 20180913: Reproducible build mode is now on by default, in preparation for FreeBSD 12.0. This eliminates build metadata such as the user, host, and time from the kernel (and uname), unless the working tree corresponds to a modified checkout from a version control system. The previous behavior can be obtained by setting the /etc/src.conf knob WITHOUT_REPRODUCIBLE_BUILD. 20180826: The Yarrow CSPRNG has been removed from the kernel as it has not been supported by its designers since at least 2003. Fortuna has been the default since FreeBSD-11. 20180822: devctl freeze/thaw have gone into the tree, the rc scripts have been updated to use them and devmatch has been changed. You should update kernel, userland and rc scripts all at the same time. 20180818: The default interpreter has been switched from 4th to Lua. LOADER_DEFAULT_INTERP, documented in build(7), will override the default interpreter. If you have custom FORTH code you will need to set LOADER_DEFAULT_INTERP=4th (valid values are 4th, lua or simp) in src.conf for the build. This will create default hard links between loader and loader_4th instead of loader and loader_lua, the new default. If you are using UEFI it will create the proper hard link to loader.efi. bhyve uses userboot.so. It remains 4th-only until some issues are solved regarding coexisting with multiple versions of FreeBSD are resolved. 20180815: ls(1) now respects the COLORTERM environment variable used in other systems and software to indicate that a colored terminal is both supported and desired. If ls(1) is suddenly emitting colors, they may be disabled again by either removing the unwanted COLORTERM from your environment, or using `ls --color=never`. The ls(1) specific CLICOLOR may not be observed in a future release. 20180808: The default pager for most commands has been changed to "less". To restore the old behavior, set PAGER="more" and MANPAGER="more -s" in your environment. 20180731: The jedec_ts(4) driver has been removed. A superset of its functionality is available in the jedec_dimm(4) driver, and the manpage for that driver includes migration instructions. If you have "device jedec_ts" in your kernel configuration file, it must be removed. 20180730: amd64/GENERIC now has EFI runtime services, EFIRT, enabled by default. This should have no effect if the kernel is booted via BIOS/legacy boot. EFIRT may be disabled via a loader tunable, efi.rt.disabled, if a system has a buggy firmware that prevents a successful boot due to use of runtime services. 20180727: Atmel AT91RM9200 and AT91SAM9, Cavium CNS 11xx and XScale support has been removed from the tree. These ports were obsolete and/or known to be broken for many years. 20180723: loader.efi has been augmented to participate more fully in the UEFI boot manager protocol. loader.efi will now look at the BootXXXX environment variable to determine if a specific kernel or root partition was specified. XXXX is derived from BootCurrent. efibootmgr(8) manages these standard UEFI variables. 20180720: zfsloader's functionality has now been folded into loader. zfsloader is no longer necessary once you've updated your boot blocks. For a transition period, we will install a hardlink for zfsloader to loader to allow a smooth transition until the boot blocks can be updated (hard link because old zfs boot blocks don't understand symlinks). 20180719: ARM64 now have efifb support, if you want to have serial console on your arm64 board when an screen is connected and the bootloader setup a frame buffer for us to use, just add : boot_serial=YES boot_multicons=YES in /boot/loader.conf For Raspberry Pi 3 (RPI) users, this is needed even if you don't have an screen connected as the firmware will setup a frame buffer are that u-boot will expose as an EFI frame buffer. 20180719: New uid:gid added, ntpd:ntpd (123:123). Be sure to run mergemaster or take steps to update /etc/passwd before doing installworld on existing systems. Do not skip the "mergemaster -Fp" step before installworld, as described in the update procedures near the bottom of this document. Also, rc.d/ntpd now starts ntpd(8) as user ntpd if the new mac_ntpd(4) policy is available, unless ntpd_flags or the ntp config file contain options that change file/dir locations. When such options (e.g., "statsdir" or "crypto") are used, ntpd can still be run as non-root by setting ntpd_user=ntpd in rc.conf, after taking steps to ensure that all required files/dirs are accessible by the ntpd user. 20180717: Big endian arm support has been removed. 20180711: The static environment setup in kernel configs is no longer mutually exclusive with the loader(8) environment by default. In order to restore the previous default behavior of disabling the loader(8) environment if a static environment is present, you must specify loader_env.disabled=1 in the static environment. 20180705: The ABI of syscalls used by management tools like sockstat and netstat has been broken to allow 32-bit binaries to work on 64-bit kernels without modification. These programs will need to match the kernel in order to function. External programs may require minor modifications to accommodate a change of type in structures from pointers to 64-bit virtual addresses. 20180702: On i386 and amd64 atomics are now inlined. Out of tree modules using atomics will need to be rebuilt. 20180701: The '%I' format in the kern.corefile sysctl limits the number of core files that a process can generate to the number stored in the debug.ncores sysctl. The '%I' format is replaced by the single digit index. Previously, if all indexes were taken the kernel would overwrite only a core file with the highest index in a filename. Currently the system will create a new core file if there is a free index or if all slots are taken it will overwrite the oldest one. 20180630: Clang, llvm, lld, lldb, compiler-rt and libc++ have been upgraded to 6.0.1. Please see the 20141231 entry below for information about prerequisites and upgrading, if you are not already using clang 3.5.0 or higher. 20180628: r335753 introduced a new quoting method. However, etc/devd/devmatch.conf needed to be changed to work with it. This change was made with r335763 and requires a mergemaster / etcupdate / etc to update the installed file. 20180612: r334930 changed the interface between the NFS modules, so they all need to be rebuilt. r335018 did a __FreeBSD_version bump for this. 20180530: As of r334391 lld is the default amd64 system linker; it is installed as /usr/bin/ld. Kernel build workarounds (see 20180510 entry) are no longer necessary. 20180530: The kernel / userland interface for devinfo changed, so you'll need a new kernel and userland as a pair for it to work (rebuilding lib/libdevinfo is all that's required). devinfo and devmatch will not work, but everything else will when there's a mismatch. 20180523: The on-disk format for hwpmc callchain records has changed to include threadid corresponding to a given record. This changes the field offsets and thus requires that libpmcstat be rebuilt before using a kernel later than r334108. 20180517: The vxge(4) driver has been removed. This driver was introduced into HEAD one week before the Exar left the Ethernet market and is not known to be used. If you have device vxge in your kernel config file it must be removed. 20180510: The amd64 kernel now requires a ld that supports ifunc to produce a working kernel, either lld or a newer binutils. lld is built by default on amd64, and the 'buildkernel' target uses it automatically. However, it is not the default linker, so building the kernel the traditional way requires LD=ld.lld on the command line (or LD=/usr/local/bin/ld for binutils port/package). lld will soon be default, and this requirement will go away. NOTE: As of r334391 lld is the default system linker on amd64, and no workaround is necessary. 20180508: The nxge(4) driver has been removed. This driver was for PCI-X 10g cards made by s2io/Neterion. The company was acquired by Exar and no longer sells or supports Ethernet products. If you have device nxge in your kernel config file it must be removed. 20180504: The tz database (tzdb) has been updated to 2018e. This version more correctly models time stamps in time zones with negative DST such as Europe/Dublin (from 1971 on), Europe/Prague (1946/7), and Africa/Windhoek (1994/2017). This does not affect the UT offsets, only time zone abbreviations and the tm_isdst flag. 20180502: The ixgb(4) driver has been removed. This driver was for an early and uncommon legacy PCI 10GbE for a single ASIC, Intel 82597EX. Intel quickly shifted to the long lived ixgbe family. If you have device ixgb in your kernel config file it must be removed. 20180501: The lmc(4) driver has been removed. This was a WAN interface card that was already reportedly rare in 2003, and had an ambiguous license. If you have device lmc in your kernel config file it must be removed. 20180413: Support for Arcnet networks has been removed. If you have device arcnet or device cm in your kernel config file they must be removed. 20180411: Support for FDDI networks has been removed. If you have device fddi or device fpa in your kernel config file they must be removed. 20180406: In addition to supporting RFC 3164 formatted messages, the syslogd(8) service is now capable of parsing RFC 5424 formatted log messages. The main benefit of using RFC 5424 is that clients may now send log messages with timestamps containing year numbers, microseconds and time zone offsets. Similarly, the syslog(3) C library function has been altered to send RFC 5424 formatted messages to the local system logging daemon. On systems using syslogd(8), this change should have no negative impact, as long as syslogd(8) and the C library are updated at the same time. On systems using a different system logging daemon, it may be necessary to make configuration adjustments, depending on the software used. When using syslog-ng, add the 'syslog-protocol' flag to local input sources to enable parsing of RFC 5424 formatted messages: source src { unix-dgram("/var/run/log" flags(syslog-protocol)); } When using rsyslog, disable the 'SysSock.UseSpecialParser' option of the 'imuxsock' module to let messages be processed by the regular RFC 3164/5424 parsing pipeline: module(load="imuxsock" SysSock.UseSpecialParser="off") Do note that these changes only affect communication between local applications and syslogd(8). The format that syslogd(8) uses to store messages on disk or forward messages to other systems remains unchanged. syslogd(8) still uses RFC 3164 for these purposes. Options to customize this behaviour will be added in the future. Utilities that process log files stored in /var/log are thus expected to continue to function as before. __FreeBSD_version has been incremented to 1200061 to denote this change. 20180328: Support for token ring networks has been removed. If you have "device token" in your kernel config you should remove it. No device drivers supported token ring. 20180323: makefs was modified to be able to tag ISO9660 El Torito boot catalog entries as EFI instead of overloading the i386 tag as done previously. The amd64 mkisoimages.sh script used to build amd64 ISO images for release was updated to use this. This may mean that makefs must be updated before "make cdrom" can be run in the release directory. This should be as simple as: $ cd $SRCDIR/usr.sbin/makefs $ make depend all install 20180212: FreeBSD boot loader enhanced with Lua scripting. It's purely opt-in for now by building WITH_LOADER_LUA and WITHOUT_FORTH in /etc/src.conf. Co-existence for the transition period will come shortly. Booting is a complex environment and test coverage for Lua-enabled loaders has been thin, so it would be prudent to assume it might not work and make provisions for backup boot methods. 20180211: devmatch functionality has been turned on in devd. It will automatically load drivers for unattached devices. This may cause unexpected drivers to be loaded. Please report any problems to current@ and imp@freebsd.org. 20180114: Clang, llvm, lld, lldb, compiler-rt and libc++ have been upgraded to 6.0.0. Please see the 20141231 entry below for information about prerequisites and upgrading, if you are not already using clang 3.5.0 or higher. 20180110: LLVM's lld linker is now used as the FreeBSD/amd64 bootstrap linker. This means it is used to link the kernel and userland libraries and executables, but is not yet installed as /usr/bin/ld by default. To revert to ld.bfd as the bootstrap linker, in /etc/src.conf set WITHOUT_LLD_BOOTSTRAP=yes 20180110: On i386, pmtimer has been removed. Its functionality has been folded into apm. It was a no-op on ACPI in current for a while now (but was still needed on i386 in FreeBSD 11 and earlier). Users may need to remove it from kernel config files. 20180104: The use of RSS hash from the network card aka flowid has been disabled by default for lagg(4) as it's currently incompatible with the lacp and loadbalance protocols. This can be re-enabled by setting the following in loader.conf: net.link.lagg.default_use_flowid="1" 20180102: The SW_WATCHDOG option is no longer necessary to enable the hardclock-based software watchdog if no hardware watchdog is configured. As before, SW_WATCHDOG will cause the software watchdog to be enabled even if a hardware watchdog is configured. 20171215: r326887 fixes the issue described in the 20171214 UPDATING entry. r326888 flips the switch back to building GELI support always. 20171214: r362593 broke ZFS + GELI support for reasons unknown. However, it also broke ZFS support generally, so GELI has been turned off by default as the lesser evil in r326857. If you boot off ZFS and/or GELI, it might not be a good time to update. 20171125: PowerPC users must update loader(8) by rebuilding world before installing a new kernel, as the protocol connecting them has changed. Without the update, loader metadata will not be passed successfully to the kernel and users will have to enter their root partition at the kernel mountroot prompt to continue booting. Newer versions of loader can boot old kernels without issue. 20171110: The LOADER_FIREWIRE_SUPPORT build variable as been renamed to WITH/OUT_LOADER_FIREWIRE. LOADER_{NO_,}GELI_SUPPORT has been renamed to WITH/OUT_LOADER_GELI. 20171106: The naive and non-compliant support of posix_fallocate(2) in ZFS has been removed as of r325320. The system call now returns EINVAL when used on a ZFS file. Although the new behavior complies with the standard, some consumers are not prepared to cope with it. One known victim is lld prior to r325420. 20171102: Building in a FreeBSD src checkout will automatically create object directories now rather than store files in the current directory if 'make obj' was not ran. Calling 'make obj' is no longer necessary. This feature can be disabled by setting WITHOUT_AUTO_OBJ=yes in /etc/src-env.conf (not /etc/src.conf), or passing the option in the environment. 20171101: The default MAKEOBJDIR has changed from /usr/obj/ for native builds, and /usr/obj// for cross-builds, to a unified /usr/obj//. This behavior can be changed to the old format by setting WITHOUT_UNIFIED_OBJDIR=yes in /etc/src-env.conf, the environment, or with -DWITHOUT_UNIFIED_OBJDIR when building. The UNIFIED_OBJDIR option is a transitional feature that will be removed for 12.0 release; please migrate to the new format for any tools by looking up the OBJDIR used by 'make -V .OBJDIR' means rather than hardcoding paths. 20171028: The native-xtools target no longer installs the files by default to the OBJDIR. Use the native-xtools-install target with a DESTDIR to install to ${DESTDIR}/${NXTP} where NXTP defaults to /nxb-bin. 20171021: As part of the boot loader infrastructure cleanup, LOADER_*_SUPPORT options are changing from controlling the build if defined / undefined to controlling the build with explicit 'yes' or 'no' values. They will shift to WITH/WITHOUT options to match other options in the system. 20171010: libstand has turned into a private library for sys/boot use only. It is no longer supported as a public interface outside of sys/boot. 20171005: The arm port has split armv6 into armv6 and armv7. armv7 is now a valid TARGET_ARCH/MACHINE_ARCH setting. If you have an armv7 system and are running a kernel from before r324363, you will need to add MACHINE_ARCH=armv7 to 'make buildworld' to do a native build. 20171003: When building multiple kernels using KERNCONF, non-existent KERNCONF files will produce an error and buildkernel will fail. Previously missing KERNCONF files silently failed giving no indication as to why, only to subsequently discover during installkernel that the desired kernel was never built in the first place. 20170912: The default serial number format for CTL LUNs has changed. This will affect users who use /dev/diskid/* device nodes, or whose FibreChannel or iSCSI clients care about their LUNs' serial numbers. Users who require serial number stability should hardcode serial numbers in /etc/ctl.conf . 20170912: For 32-bit arm compiled for hard-float support, soft-floating point binaries now always get their shared libraries from LD_SOFT_LIBRARY_PATH (in the past, this was only used if /usr/libsoft also existed). Only users with a hard-float ld.so, but soft-float everything else should be affected. 20170826: The geli password typed at boot is now hidden. To restore the previous behavior, see geli(8) for configuration options. 20170825: Move PMTUD blackhole counters to TCPSTATS and remove them from bare sysctl values. Minor nit, but requires a rebuild of both world/kernel to complete. 20170814: "make check" behavior (made in ^/head@r295380) has been changed to execute from a limited sandbox, as opposed to executing from ${TESTSDIR}. Behavioral changes: - The "beforecheck" and "aftercheck" targets are now specified. - ${CHECKDIR} (added in commit noted above) has been removed. - Legacy behavior can be enabled by setting WITHOUT_MAKE_CHECK_USE_SANDBOX in src.conf(5) or the environment. If the limited sandbox mode is enabled, "make check" will execute "make distribution", then install, execute the tests, and clean up the sandbox if successful. The "make distribution" and "make install" targets are typically run as root to set appropriate permissions and ownership at installation time. The end-user should set "WITH_INSTALL_AS_USER" in src.conf(5) or the environment if executing "make check" with limited sandbox mode using an unprivileged user. 20170808: Since the switch to GPT disk labels, fsck for UFS/FFS has been unable to automatically find alternate superblocks. As of r322297, the information needed to find alternate superblocks has been moved to the end of the area reserved for the boot block. Filesystems created with a newfs of this vintage or later will create the recovery information. If you have a filesystem created prior to this change and wish to have a recovery block created for your filesystem, you can do so by running fsck in foreground mode (i.e., do not use the -p or -y options). As it starts, fsck will ask ``SAVE DATA TO FIND ALTERNATE SUPERBLOCKS'' to which you should answer yes. 20170728: As of r321665, an NFSv4 server configuration that services Kerberos mounts or clients that do not support the uid/gid in owner/owner_group string capability, must explicitly enable the nfsuserd daemon by adding nfsuserd_enable="YES" to the machine's /etc/rc.conf file. 20170722: Clang, llvm, lldb, compiler-rt and libc++ have been upgraded to 5.0.0. Please see the 20141231 entry below for information about prerequisites and upgrading, if you are not already using clang 3.5.0 or higher. 20170701: WITHOUT_RCMDS is now the default. Set WITH_RCMDS if you need the r-commands (rlogin, rsh, etc.) to be built with the base system. 20170625: The FreeBSD/powerpc platform now uses a 64-bit type for time_t. This is a very major ABI incompatible change, so users of FreeBSD/powerpc must be careful when performing source upgrades. It is best to run 'make installworld' from an alternate root system, either a live CD/memory stick, or a temporary root partition. Additionally, all ports must be recompiled. powerpc64 is largely unaffected, except in the case of 32-bit compatibility. All 32-bit binaries will be affected. 20170623: Forward compatibility for the "ino64" project have been committed. This will allow most new binaries to run on older kernels in a limited fashion. This prevents many of the common foot-shooting actions in the upgrade as well as the limited ability to roll back the kernel across the ino64 upgrade. Complicated use cases may not work properly, though enough simpler ones work to allow recovery in most situations. 20170620: Switch back to the BSDL dtc (Device Tree Compiler). Set WITH_GPL_DTC if you require the GPL compiler. 20170618: The internal ABI used for communication between the NFS kernel modules was changed by r320085, so __FreeBSD_version was bumped to ensure all the NFS related modules are updated together. 20170617: The ABI of struct event was changed by extending the data member to 64bit and adding ext fields. For upgrade, same precautions as for the entry 20170523 "ino64" must be followed. 20170531: The GNU roff toolchain has been removed from base. To render manpages which are not supported by mandoc(1), man(1) can fallback on GNU roff from ports (and recommends to install it). To render roff(7) documents, consider using GNU roff from ports or the heirloom doctools roff toolchain from ports via pkg install groff or via pkg install heirloom-doctools. 20170524: The ath(4) and ath_hal(4) modules now build piecemeal to allow for smaller runtime footprint builds. This is useful for embedded systems which only require one chipset support. If you load it as a module, make sure this is in /boot/loader.conf: if_ath_load="YES" This will load the HAL, all chip/RF backends and if_ath_pci. If you have if_ath_pci in /boot/loader.conf, ensure it is after if_ath or it will not load any HAL chipset support. If you want to selectively load things (eg on ye cheape ARM/MIPS platforms where RAM is at a premium) you should: * load ath_hal * load the chip modules in question * load ath_rate, ath_dfs * load ath_main * load if_ath_pci and/or if_ath_ahb depending upon your particular bus bind type - this is where probe/attach is done. For further comments/feedback, poke adrian@ . 20170523: The "ino64" 64-bit inode project has been committed, which extends a number of types to 64 bits. Upgrading in place requires care and adherence to the documented upgrade procedure. If using a custom kernel configuration ensure that the COMPAT_FREEBSD11 option is included (as during the upgrade the system will be running the ino64 kernel with the existing world). For the safest in-place upgrade begin by removing previous build artifacts via "rm -rf /usr/obj/*". Then, carefully follow the full procedure documented below under the heading "To rebuild everything and install it on the current system." Specifically, a reboot is required after installing the new kernel before installing world. While an installworld normally works by accident from multiuser after rebooting the proper kernel, there are many cases where this will fail across this upgrade and installworld from single user is required. 20170424: The NATM framework including the en(4), fatm(4), hatm(4), and patm(4) devices has been removed. Consumers should plan a migration before the end-of-life date for FreeBSD 11. 20170420: GNU diff has been replaced by a BSD licensed diff. Some features of GNU diff has not been implemented, if those are needed a newer version of GNU diff is available via the diffutils package under the gdiff name. 20170413: As of r316810 for ipfilter, keep frags is no longer assumed when keep state is specified in a rule. r316810 aligns ipfilter with documentation in man pages separating keep frags from keep state. This allows keep state to be specified without forcing keep frags and allows keep frags to be specified independently of keep state. To maintain previous behaviour, also specify keep frags with keep state (as documented in ipf.conf.5). 20170407: arm64 builds now use the base system LLD 4.0.0 linker by default, instead of requiring that the aarch64-binutils port or package be installed. To continue using aarch64-binutils, set CROSS_BINUTILS_PREFIX=/usr/local/aarch64-freebsd/bin . 20170405: The UDP optimization in entry 20160818 that added the sysctl net.inet.udp.require_l2_bcast has been reverted. L2 broadcast packets will no longer be treated as L3 broadcast packets. 20170331: Binds and sends to the loopback addresses, IPv6 and IPv4, will now use any explicitly assigned loopback address available in the jail instead of using the first assigned address of the jail. 20170329: The ctl.ko module no longer implements the iSCSI target frontend: cfiscsi.ko does instead. If building cfiscsi.ko as a kernel module, the module can be loaded via one of the following methods: - `cfiscsi_load="YES"` in loader.conf(5). - Add `cfiscsi` to `$kld_list` in rc.conf(5). - ctladm(8)/ctld(8), when compiled with iSCSI support (`WITH_ISCSI=yes` in src.conf(5)) Please see cfiscsi(4) for more details. 20170316: The mmcsd.ko module now additionally depends on geom_flashmap.ko. Also, mmc.ko and mmcsd.ko need to be a matching pair built from the same source (previously, the dependency of mmcsd.ko on mmc.ko was missing, but mmcsd.ko now will refuse to load if it is incompatible with mmc.ko). 20170315: The syntax of ipfw(8) named states was changed to avoid ambiguity. If you have used named states in the firewall rules, you need to modify them after installworld and before rebooting. Now named states must be prefixed with colon. 20170311: The old drm (sys/dev/drm/) drivers for i915 and radeon have been removed as the userland we provide cannot use them. The KMS version (sys/dev/drm2) supports the same hardware. 20170302: Clang, llvm, lldb, compiler-rt and libc++ have been upgraded to 4.0.0. Please see the 20141231 entry below for information about prerequisites and upgrading, if you are not already using clang 3.5.0 or higher. 20170221: The code that provides support for ZFS .zfs/ directory functionality has been reimplemented. It's not possible now to create a snapshot by mkdir under .zfs/snapshot/. That should be the only user visible change. 20170216: EISA bus support has been removed. The WITH_EISA option is no longer valid. 20170215: MCA bus support has been removed. 20170127: The WITH_LLD_AS_LD / WITHOUT_LLD_AS_LD build knobs have been renamed WITH_LLD_IS_LD / WITHOUT_LLD_IS_LD, for consistency with CLANG_IS_CC. 20170112: The EM_MULTIQUEUE kernel configuration option is deprecated now that the em(4) driver conforms to iflib specifications. 20170109: The igb(4), em(4) and lem(4) ethernet drivers are now implemented via IFLIB. If you have a custom kernel configuration that excludes em(4) but you use igb(4), you need to re-add em(4) to your custom configuration. 20161217: Clang, llvm, lldb, compiler-rt and libc++ have been upgraded to 3.9.1. Please see the 20141231 entry below for information about prerequisites and upgrading, if you are not already using clang 3.5.0 or higher. 20161124: Clang, llvm, lldb, compiler-rt and libc++ have been upgraded to 3.9.0. Please see the 20141231 entry below for information about prerequisites and upgrading, if you are not already using clang 3.5.0 or higher. 20161119: The layout of the pmap structure has changed for powerpc to put the pmap statistics at the front for all CPU variations. libkvm(3) and all tools that link against it need to be recompiled. 20161030: isl(4) and cyapa(4) drivers now require a new driver, chromebook_platform(4), to work properly on Chromebook-class hardware. On other types of hardware the drivers may need to be configured using device hints. Please see the corresponding manual pages for details. 20161017: The urtwn(4) driver was merged into rtwn(4) and now consists of rtwn(4) main module + rtwn_usb(4) and rtwn_pci(4) bus-specific parts. Also, firmware for RTL8188CE was renamed due to possible name conflict (rtwnrtl8192cU(B) -> rtwnrtl8192cE(B)) 20161015: GNU rcs has been removed from base. It is available as packages: - rcs: Latest GPLv3 GNU rcs version. - rcs57: Copy of the latest version of GNU rcs (GPLv2) before it was removed from base. 20161008: Use of the cc_cdg, cc_chd, cc_hd, or cc_vegas congestion control modules now requires that the kernel configuration contain the TCP_HHOOK option. (This option is included in the GENERIC kernel.) 20161003: The WITHOUT_ELFCOPY_AS_OBJCOPY src.conf(5) knob has been retired. ELF Tool Chain's elfcopy is always installed as /usr/bin/objcopy. 20160924: Relocatable object files with the extension of .So have been renamed to use an extension of .pico instead. The purpose of this change is to avoid a name clash with shared libraries on case-insensitive file systems. On those file systems, foo.So is the same file as foo.so. 20160918: GNU rcs has been turned off by default. It can (temporarily) be built again by adding WITH_RCS knob in src.conf. Otherwise, GNU rcs is available from packages: - rcs: Latest GPLv3 GNU rcs version. - rcs57: Copy of the latest version of GNU rcs (GPLv2) from base. 20160918: The backup_uses_rcs functionality has been removed from rc.subr. 20160908: The queue(3) debugging macro, QUEUE_MACRO_DEBUG, has been split into two separate components, QUEUE_MACRO_DEBUG_TRACE and QUEUE_MACRO_DEBUG_TRASH. Define both for the original QUEUE_MACRO_DEBUG behavior. 20160824: r304787 changed some ioctl interfaces between the iSCSI userspace programs and the kernel. ctladm, ctld, iscsictl, and iscsid must be rebuilt to work with new kernels. __FreeBSD_version has been bumped to 1200005. 20160818: The UDP receive code has been updated to only treat incoming UDP packets that were addressed to an L2 broadcast address as L3 broadcast packets. It is not expected that this will affect any standards-conforming UDP application. The new behaviour can be disabled by setting the sysctl net.inet.udp.require_l2_bcast to 0. 20160818: Remove the openbsd_poll system call. __FreeBSD_version has been bumped because of this. 20160708: The stable/11 branch has been created from head@r302406. 20160622: The libc stub for the pipe(2) system call has been replaced with a wrapper that calls the pipe2(2) system call and the pipe(2) system call is now only implemented by the kernels that include "options COMPAT_FREEBSD10" in their config file (this is the default). Users should ensure that this option is enabled in their kernel or upgrade userspace to r302092 before upgrading their kernel. 20160527: CAM will now strip leading spaces from SCSI disks' serial numbers. This will affect users who create UFS filesystems on SCSI disks using those disk's diskid device nodes. For example, if /etc/fstab previously contained a line like "/dev/diskid/DISK-%20%20%20%20%20%20%20ABCDEFG0123456", you should change it to "/dev/diskid/DISK-ABCDEFG0123456". Users of geom transforms like gmirror may also be affected. ZFS users should generally be fine. 20160523: The bitstring(3) API has been updated with new functionality and improved performance. But it is binary-incompatible with the old API. Objects built with the new headers may not be linked against objects built with the old headers. 20160520: The brk and sbrk functions have been removed from libc on arm64. Binutils from ports has been updated to not link to these functions and should be updated to the latest version before installing a new libc. 20160517: The armv6 port now defaults to hard float ABI. Limited support for running both hardfloat and soft float on the same system is available using the libraries installed with -DWITH_LIBSOFT. This has only been tested as an upgrade path for installworld and packages may fail or need manual intervention to run. New packages will be needed. To update an existing self-hosted armv6hf system, you must add TARGET_ARCH=armv6 on the make command line for both the build and the install steps. 20160510: Kernel modules compiled outside of a kernel build now default to installing to /boot/modules instead of /boot/kernel. Many kernel modules built this way (such as those in ports) already overrode KMODDIR explicitly to install into /boot/modules. However, manually building and installing a module from /sys/modules will now install to /boot/modules instead of /boot/kernel. 20160414: The CAM I/O scheduler has been committed to the kernel. There should be no user visible impact. This does enable NCQ Trim on ada SSDs. While the list of known rogues that claim support for this but actually corrupt data is believed to be complete, be on the lookout for data corruption. The known rogue list is believed to be complete: o Crucial MX100, M550 drives with MU01 firmware. o Micron M510 and M550 drives with MU01 firmware. o Micron M500 prior to MU07 firmware o Samsung 830, 840, and 850 all firmwares o FCCT M500 all firmwares Crucial has firmware http://www.crucial.com/usa/en/support-ssd-firmware with working NCQ TRIM. For Micron branded drives, see your sales rep for updated firmware. Black listed drives will work correctly because these drives work correctly so long as no NCQ TRIMs are sent to them. Given this list is the same as found in Linux, it's believed there are no other rogues in the market place. All other models from the above vendors work. To be safe, if you are at all concerned, you can quirk each of your drives to prevent NCQ from being sent by setting: kern.cam.ada.X.quirks="0x2" in loader.conf. If the drive requires the 4k sector quirk, set the quirks entry to 0x3. 20160330: The FAST_DEPEND build option has been removed and its functionality is now the one true way. The old mkdep(1) style of 'make depend' has been removed. See 20160311 for further details. 20160317: Resource range types have grown from unsigned long to uintmax_t. All drivers, and anything using libdevinfo, need to be recompiled. 20160311: WITH_FAST_DEPEND is now enabled by default for in-tree and out-of-tree builds. It no longer runs mkdep(1) during 'make depend', and the 'make depend' stage can safely be skipped now as it is auto ran when building 'make all' and will generate all SRCS and DPSRCS before building anything else. Dependencies are gathered at compile time with -MF flags kept in separate .depend files per object file. Users should run 'make cleandepend' once if using -DNO_CLEAN to clean out older stale .depend files. 20160306: On amd64, clang 3.8.0 can now insert sections of type AMD64_UNWIND into kernel modules. Therefore, if you load any kernel modules at boot time, please install the boot loaders after you install the kernel, but before rebooting, e.g.: make buildworld make buildkernel KERNCONF=YOUR_KERNEL_HERE make installkernel KERNCONF=YOUR_KERNEL_HERE make -C sys/boot install Then follow the usual steps, described in the General Notes section, below. 20160305: Clang, llvm, lldb and compiler-rt have been upgraded to 3.8.0. Please see the 20141231 entry below for information about prerequisites and upgrading, if you are not already using clang 3.5.0 or higher. 20160301: The AIO subsystem is now a standard part of the kernel. The VFS_AIO kernel option and aio.ko kernel module have been removed. Due to stability concerns, asynchronous I/O requests are only permitted on sockets and raw disks by default. To enable asynchronous I/O requests on all file types, set the vfs.aio.enable_unsafe sysctl to a non-zero value. 20160226: The ELF object manipulation tool objcopy is now provided by the ELF Tool Chain project rather than by GNU binutils. It should be a drop-in replacement, with the addition of arm64 support. The (temporary) src.conf knob WITHOUT_ELFCOPY_AS_OBJCOPY knob may be set to obtain the GNU version if necessary. 20160129: Building ZFS pools on top of zvols is prohibited by default. That feature has never worked safely; it's always been prone to deadlocks. Using a zvol as the backing store for a VM guest's virtual disk will still work, even if the guest is using ZFS. Legacy behavior can be restored by setting vfs.zfs.vol.recursive=1. 20160119: The NONE and HPN patches has been removed from OpenSSH. They are still available in the security/openssh-portable port. 20160113: With the addition of ypldap(8), a new _ypldap user is now required during installworld. "mergemaster -p" can be used to add the user prior to installworld, as documented in the handbook. 20151216: The tftp loader (pxeboot) now uses the option root-path directive. As a consequence it no longer looks for a pxeboot.4th file on the tftp server. Instead it uses the regular /boot infrastructure as with the other loaders. 20151211: The code to start recording plug and play data into the modules has been committed. While the old tools will properly build a new kernel, a number of warnings about "unknown metadata record 4" will be produced for an older kldxref. To avoid such warnings, make sure to rebuild the kernel toolchain (or world). Make sure that you have r292078 or later when trying to build 292077 or later before rebuilding. 20151207: Debug data files are now built by default with 'make buildworld' and installed with 'make installworld'. This facilitates debugging but requires more disk space both during the build and for the installed world. Debug files may be disabled by setting WITHOUT_DEBUG_FILES=yes in src.conf(5). 20151130: r291527 changed the internal interface between the nfsd.ko and nfscommon.ko modules. As such, they must both be upgraded to-gether. __FreeBSD_version has been bumped because of this. 20151108: Add support for unicode collation strings leads to a change of order of files listed by ls(1) for example. To get back to the old behaviour, set LC_COLLATE environment variable to "C". Databases administrators will need to reindex their databases given collation results will be different. Due to a bug in install(1) it is recommended to remove the ancient locales before running make installworld. rm -rf /usr/share/locale/* 20151030: The OpenSSL has been upgraded to 1.0.2d. Any binaries requiring libcrypto.so.7 or libssl.so.7 must be recompiled. 20151020: Qlogic 24xx/25xx firmware images were updated from 5.5.0 to 7.3.0. Kernel modules isp_2400_multi and isp_2500_multi were removed and should be replaced with isp_2400 and isp_2500 modules respectively. 20151017: The build previously allowed using 'make -n' to not recurse into sub-directories while showing what commands would be executed, and 'make -n -n' to recursively show commands. Now 'make -n' will recurse and 'make -N' will not. 20151012: If you specify SENDMAIL_MC or SENDMAIL_CF in make.conf, mergemaster and etcupdate will now use this file. A custom sendmail.cf is now updated via this mechanism rather than via installworld. If you had excluded sendmail.cf in mergemaster.rc or etcupdate.conf, you may want to remove the exclusion or change it to "always install". /etc/mail/sendmail.cf is now managed the same way regardless of whether SENDMAIL_MC/SENDMAIL_CF is used. If you are not using SENDMAIL_MC/SENDMAIL_CF there should be no change in behavior. 20151011: Compatibility shims for legacy ATA device names have been removed. It includes ATA_STATIC_ID kernel option, kern.cam.ada.legacy_aliases and kern.geom.raid.legacy_aliases loader tunables, kern.devalias.* environment variables, /dev/ad* and /dev/ar* symbolic links. 20151006: Clang, llvm, lldb, compiler-rt and libc++ have been upgraded to 3.7.0. Please see the 20141231 entry below for information about prerequisites and upgrading, if you are not already using clang 3.5.0 or higher. 20150924: Kernel debug files have been moved to /usr/lib/debug/boot/kernel/, and renamed from .symbols to .debug. This reduces the size requirements on the boot partition or file system and provides consistency with userland debug files. When using the supported kernel installation method the /usr/lib/debug/boot/kernel directory will be renamed (to kernel.old) as is done with /boot/kernel. Developers wishing to maintain the historical behavior of installing debug files in /boot/kernel/ can set KERN_DEBUGDIR="" in src.conf(5). 20150827: The wireless drivers had undergone changes that remove the 'parent interface' from the ifconfig -l output. The rc.d network scripts used to check presence of a parent interface in the list, so old scripts would fail to start wireless networking. Thus, etcupdate(3) or mergemaster(8) run is required after kernel update, to update your rc.d scripts in /etc. 20150827: pf no longer supports 'scrub fragment crop' or 'scrub fragment drop-ovl' These configurations are now automatically interpreted as 'scrub fragment reassemble'. 20150817: Kernel-loadable modules for the random(4) device are back. To use them, the kernel must have device random options RANDOM_LOADABLE kldload(8) can then be used to load random_fortuna.ko or random_yarrow.ko. Please note that due to the indirect function calls that the loadable modules need to provide, the build-in variants will be slightly more efficient. The random(4) kernel option RANDOM_DUMMY has been retired due to unpopularity. It was not all that useful anyway. 20150813: The WITHOUT_ELFTOOLCHAIN_TOOLS src.conf(5) knob has been retired. Control over building the ELF Tool Chain tools is now provided by the WITHOUT_TOOLCHAIN knob. 20150810: The polarity of Pulse Per Second (PPS) capture events with the uart(4) driver has been corrected. Prior to this change the PPS "assert" event corresponded to the trailing edge of a positive PPS pulse and the "clear" event was the leading edge of the next pulse. As the width of a PPS pulse in a typical GPS receiver is on the order of 1 millisecond, most users will not notice any significant difference with this change. Anyone who has compensated for the historical polarity reversal by configuring a negative offset equal to the pulse width will need to remove that workaround. 20150809: The default group assigned to /dev/dri entries has been changed from 'wheel' to 'video' with the id of '44'. If you want to have access to the dri devices please add yourself to the video group with: # pw groupmod video -m $USER 20150806: The menu.rc and loader.rc files will now be replaced during upgrades. Please migrate local changes to menu.rc.local and loader.rc.local instead. 20150805: GNU Binutils versions of addr2line, c++filt, nm, readelf, size, strings and strip have been removed. The src.conf(5) knob WITHOUT_ELFTOOLCHAIN_TOOLS no longer provides the binutils tools. 20150728: As ZFS requires more kernel stack pages than is the default on some architectures e.g. i386, it now warns if KSTACK_PAGES is less than ZFS_MIN_KSTACK_PAGES (which is 4 at the time of writing). Please consider using 'options KSTACK_PAGES=X' where X is greater than or equal to ZFS_MIN_KSTACK_PAGES i.e. 4 in such configurations. 20150706: sendmail has been updated to 8.15.2. Starting with FreeBSD 11.0 and sendmail 8.15, sendmail uses uncompressed IPv6 addresses by default, i.e., they will not contain "::". For example, instead of ::1, it will be 0:0:0:0:0:0:0:1. This permits a zero subnet to have a more specific match, such as different map entries for IPv6:0:0 vs IPv6:0. This change requires that configuration data (including maps, files, classes, custom ruleset, etc.) must use the same format, so make certain such configuration data is upgrading. As a very simple check search for patterns like 'IPv6:[0-9a-fA-F:]*::' and 'IPv6::'. To return to the old behavior, set the m4 option confUSE_COMPRESSED_IPV6_ADDRESSES or the cf option UseCompressedIPv6Addresses. 20150630: The default kernel entropy-processing algorithm is now Fortuna, replacing Yarrow. Assuming you have 'device random' in your kernel config file, the configurations allow a kernel option to override this default. You may choose *ONE* of: options RANDOM_YARROW # Legacy /dev/random algorithm. options RANDOM_DUMMY # Blocking-only driver. If you have neither, you get Fortuna. For most people, read no further, Fortuna will give a /dev/random that works like it always used to, and the difference will be irrelevant. If you remove 'device random', you get *NO* kernel-processed entropy at all. This may be acceptable to folks building embedded systems, but has complications. Carry on reading, and it is assumed you know what you need. *PLEASE* read random(4) and random(9) if you are in the habit of tweaking kernel configs, and/or if you are a member of the embedded community, wanting specific and not-usual behaviour from your security subsystems. NOTE!! If you use RANDOM_DUMMY and/or have no 'device random', you will NOT have a functioning /dev/random, and many cryptographic features will not work, including SSH. You may also find strange behaviour from the random(3) set of library functions, in particular sranddev(3), srandomdev(3) and arc4random(3). The reason for this is that the KERN_ARND sysctl only returns entropy if it thinks it has some to share, and with RANDOM_DUMMY or no 'device random' this will never happen. 20150623: An additional fix for the issue described in the 20150614 sendmail entry below has been committed in revision 284717. 20150616: FreeBSD's old make (fmake) has been removed from the system. It is available as the devel/fmake port or via pkg install fmake. 20150615: The fix for the issue described in the 20150614 sendmail entry below has been committed in revision 284436. The work around described in that entry is no longer needed unless the default setting is overridden by a confDH_PARAMETERS configuration setting of '5' or pointing to a 512 bit DH parameter file. 20150614: ALLOW_DEPRECATED_ATF_TOOLS/ATFFILE support has been removed from atf.test.mk (included from bsd.test.mk). Please upgrade devel/atf and devel/kyua to version 0.20+ and adjust any calling code to work with Kyuafile and kyua. 20150614: The import of openssl to address the FreeBSD-SA-15:10.openssl security advisory includes a change which rejects handshakes with DH parameters below 768 bits. sendmail releases prior to 8.15.2 (not yet released), defaulted to a 512 bit DH parameter setting for client connections. To work around this interoperability, sendmail can be configured to use a 2048 bit DH parameter by: 1. Edit /etc/mail/`hostname`.mc 2. If a setting for confDH_PARAMETERS does not exist or exists and is set to a string beginning with '5', replace it with '2'. 3. If a setting for confDH_PARAMETERS exists and is set to a file path, create a new file with: openssl dhparam -out /path/to/file 2048 4. Rebuild the .cf file: cd /etc/mail/; make; make install 5. Restart sendmail: cd /etc/mail/; make restart A sendmail patch is coming, at which time this file will be updated. 20150604: Generation of legacy formatted entries have been disabled by default in pwd_mkdb(8), as all base system consumers of the legacy formatted entries were converted to use the new format by default when the new, machine independent format have been added and supported since FreeBSD 5.x. Please see the pwd_mkdb(8) manual page for further details. 20150525: Clang and llvm have been upgraded to 3.6.1 release. Please see the 20141231 entry below for information about prerequisites and upgrading, if you are not already using 3.5.0 or higher. 20150521: TI platform code switched to using vendor DTS files and this update may break existing systems running on Beaglebone, Beaglebone Black, and Pandaboard: - dtb files should be regenerated/reinstalled. Filenames are the same but content is different now - GPIO addressing was changed, now each GPIO bank (32 pins per bank) has its own /dev/gpiocX device, e.g. pin 121 on /dev/gpioc0 in old addressing scheme is now pin 25 on /dev/gpioc3. - Pandaboard: /etc/ttys should be updated, serial console device is now /dev/ttyu2, not /dev/ttyu0 20150501: soelim(1) from gnu/usr.bin/groff has been replaced by usr.bin/soelim. If you need the GNU extension from groff soelim(1), install groff from package: pkg install groff, or via ports: textproc/groff. 20150423: chmod, chflags, chown and chgrp now affect symlinks in -R mode as defined in symlink(7); previously symlinks were silently ignored. 20150415: The const qualifier has been removed from iconv(3) to comply with POSIX. The ports tree is aware of this from r384038 onwards. 20150416: Libraries specified by LIBADD in Makefiles must have a corresponding DPADD_ variable to ensure correct dependencies. This is now enforced in src.libnames.mk. 20150324: From legacy ata(4) driver was removed support for SATA controllers supported by more functional drivers ahci(4), siis(4) and mvs(4). Kernel modules ataahci and ataadaptec were removed completely, replaced by ahci and mvs modules respectively. 20150315: Clang, llvm and lldb have been upgraded to 3.6.0 release. Please see the 20141231 entry below for information about prerequisites and upgrading, if you are not already using 3.5.0 or higher. 20150307: The 32-bit PowerPC kernel has been changed to a position-independent executable. This can only be booted with a version of loader(8) newer than January 31, 2015, so make sure to update both world and kernel before rebooting. 20150217: If you are running a -CURRENT kernel since r273872 (Oct 30th, 2014), but before r278950, the RNG was not seeded properly. Immediately upgrade the kernel to r278950 or later and regenerate any keys (e.g. ssh keys or openssl keys) that were generated w/ a kernel from that range. This does not affect programs that directly used /dev/random or /dev/urandom. All userland uses of arc4random(3) are affected. 20150210: The autofs(4) ABI was changed in order to restore binary compatibility with 10.1-RELEASE. The automountd(8) daemon needs to be rebuilt to work with the new kernel. 20150131: The powerpc64 kernel has been changed to a position-independent executable. This can only be booted with a new version of loader(8), so make sure to update both world and kernel before rebooting. 20150118: Clang and llvm have been upgraded to 3.5.1 release. This is a bugfix only release, no new features have been added. Please see the 20141231 entry below for information about prerequisites and upgrading, if you are not already using 3.5.0. 20150107: ELF tools addr2line, elfcopy (strip), nm, size, and strings are now taken from the ELF Tool Chain project rather than GNU binutils. They should be drop-in replacements, with the addition of arm64 support. The WITHOUT_ELFTOOLCHAIN_TOOLS= knob may be used to obtain the binutils tools, if necessary. See 20150805 for updated information. 20150105: The default Unbound configuration now enables remote control using a local socket. Users who have already enabled the local_unbound service should regenerate their configuration by running "service local_unbound setup" as root. 20150102: The GNU texinfo and GNU info pages have been removed. To be able to view GNU info pages please install texinfo from ports. 20141231: Clang, llvm and lldb have been upgraded to 3.5.0 release. As of this release, a prerequisite for building clang, llvm and lldb is a C++11 capable compiler and C++11 standard library. This means that to be able to successfully build the cross-tools stage of buildworld, with clang as the bootstrap compiler, your system compiler or cross compiler should either be clang 3.3 or later, or gcc 4.8 or later, and your system C++ library should be libc++, or libdstdc++ from gcc 4.8 or later. On any standard FreeBSD 10.x or 11.x installation, where clang and libc++ are on by default (that is, on x86 or arm), this should work out of the box. On 9.x installations where clang is enabled by default, e.g. on x86 and powerpc, libc++ will not be enabled by default, so libc++ should be built (with clang) and installed first. If both clang and libc++ are missing, build clang first, then use it to build libc++. On 8.x and earlier installations, upgrade to 9.x first, and then follow the instructions for 9.x above. Sparc64 and mips users are unaffected, as they still use gcc 4.2.1 by default, and do not build clang. Many embedded systems are resource constrained, and will not be able to build clang in a reasonable time, or in some cases at all. In those cases, cross building bootable systems on amd64 is a workaround. This new version of clang introduces a number of new warnings, of which the following are most likely to appear: -Wabsolute-value This warns in two cases, for both C and C++: * When the code is trying to take the absolute value of an unsigned quantity, which is effectively a no-op, and almost never what was intended. The code should be fixed, if at all possible. If you are sure that the unsigned quantity can be safely cast to signed, without loss of information or undefined behavior, you can add an explicit cast, or disable the warning. * When the code is trying to take an absolute value, but the called abs() variant is for the wrong type, which can lead to truncation. If you want to disable the warning instead of fixing the code, please make sure that truncation will not occur, or it might lead to unwanted side-effects. -Wtautological-undefined-compare and -Wundefined-bool-conversion These warn when C++ code is trying to compare 'this' against NULL, while 'this' should never be NULL in well-defined C++ code. However, there is some legacy (pre C++11) code out there, which actively abuses this feature, which was less strictly defined in previous C++ versions. Squid and openjdk do this, for example. The warning can be turned off for C++98 and earlier, but compiling the code in C++11 mode might result in unexpected behavior; for example, the parts of the program that are unreachable could be optimized away. 20141222: The old NFS client and server (kernel options NFSCLIENT, NFSSERVER) kernel sources have been removed. The .h files remain, since some utilities include them. This will need to be fixed later. If "mount -t oldnfs ..." is attempted, it will fail. If the "-o" option on mountd(8), nfsd(8) or nfsstat(1) is used, the utilities will report errors. 20141121: The handling of LOCAL_LIB_DIRS has been altered to skip addition of directories to top level SUBDIR variable when their parent directory is included in LOCAL_DIRS. Users with build systems with such hierarchies and without SUBDIR entries in the parent directory Makefiles should add them or add the directories to LOCAL_DIRS. 20141109: faith(4) and faithd(8) have been removed from the base system. Faith has been obsolete for a very long time. 20141104: vt(4), the new console driver, is enabled by default. It brings support for Unicode and double-width characters, as well as support for UEFI and integration with the KMS kernel video drivers. You may need to update your console settings in /etc/rc.conf, most probably the keymap. During boot, /etc/rc.d/syscons will indicate what you need to do. vt(4) still has issues and lacks some features compared to syscons(4). See the wiki for up-to-date information: https://wiki.freebsd.org/Newcons If you want to keep using syscons(4), you can do so by adding the following line to /boot/loader.conf: kern.vty=sc 20141102: pjdfstest has been integrated into kyua as an opt-in test suite. Please see share/doc/pjdfstest/README for more details on how to execute it. 20141009: gperf has been removed from the base system for architectures that use clang. Ports that require gperf will obtain it from the devel/gperf port. 20140923: pjdfstest has been moved from tools/regression/pjdfstest to contrib/pjdfstest . 20140922: At svn r271982, The default linux compat kernel ABI has been adjusted to 2.6.18 in support of the linux-c6 compat ports infrastructure update. If you wish to continue using the linux-f10 compat ports, add compat.linux.osrelease=2.6.16 to your local sysctl.conf. Users are encouraged to update their linux-compat packages to linux-c6 during their next update cycle. 20140729: The ofwfb driver, used to provide a graphics console on PowerPC when using vt(4), no longer allows mmap() of all physical memory. This will prevent Xorg on PowerPC with some ATI graphics cards from initializing properly unless x11-servers/xorg-server is updated to 1.12.4_8 or newer. 20140723: The xdev targets have been converted to using TARGET and TARGET_ARCH instead of XDEV and XDEV_ARCH. 20140719: The default unbound configuration has been modified to address issues with reverse lookups on networks that use private address ranges. If you use the local_unbound service, run "service local_unbound setup" as root to regenerate your configuration, then "service local_unbound reload" to load the new configuration. 20140709: The GNU texinfo and GNU info pages are not built and installed anymore, WITH_INFO knob has been added to allow to built and install them again. UPDATE: see 20150102 entry on texinfo's removal 20140708: The GNU readline library is now an INTERNALLIB - that is, it is statically linked into consumers (GDB and variants) in the base system, and the shared library is no longer installed. The devel/readline port is available for third party software that requires readline. 20140702: The Itanium architecture (ia64) has been removed from the list of known architectures. This is the first step in the removal of the architecture. 20140701: Commit r268115 has added NFSv4.1 server support, merged from projects/nfsv4.1-server. Since this includes changes to the internal interfaces between the NFS related modules, a full build of the kernel and modules will be necessary. __FreeBSD_version has been bumped. 20140629: The WITHOUT_VT_SUPPORT kernel config knob has been renamed WITHOUT_VT. (The other _SUPPORT knobs have a consistent meaning which differs from the behaviour controlled by this knob.) 20140619: Maximal length of the serial number in CTL was increased from 16 to 64 chars, that breaks ABI. All CTL-related tools, such as ctladm and ctld, need to be rebuilt to work with a new kernel. 20140606: The libatf-c and libatf-c++ major versions were downgraded to 0 and 1 respectively to match the upstream numbers. They were out of sync because, when they were originally added to FreeBSD, the upstream versions were not respected. These libraries are private and not yet built by default, so renumbering them should be a non-issue. However, unclean source trees will yield broken test programs once the operator executes "make delete-old-libs" after a "make installworld". Additionally, the atf-sh binary was made private by moving it into /usr/libexec/. Already-built shell test programs will keep the path to the old binary so they will break after "make delete-old" is run. If you are using WITH_TESTS=yes (not the default), wipe the object tree and rebuild from scratch to prevent spurious test failures. This is only needed once: the misnumbered libraries and misplaced binaries have been added to OptionalObsoleteFiles.inc so they will be removed during a clean upgrade. 20140512: Clang and llvm have been upgraded to 3.4.1 release. 20140508: We bogusly installed src.opts.mk in /usr/share/mk. This file should be removed to avoid issues in the future (and has been added to ObsoleteFiles.inc). 20140505: /etc/src.conf now affects only builds of the FreeBSD src tree. In the past, it affected all builds that used the bsd.*.mk files. The old behavior was a bug, but people may have relied upon it. To get this behavior back, you can .include /etc/src.conf from /etc/make.conf (which is still global and isn't changed). This also changes the behavior of incremental builds inside the tree of individual directories. Set MAKESYSPATH to ".../share/mk" to do that. Although this has survived make universe and some upgrade scenarios, other upgrade scenarios may have broken. At least one form of temporary breakage was fixed with MAKESYSPATH settings for buildworld as well... In cases where MAKESYSPATH isn't working with this setting, you'll need to set it to the full path to your tree. One side effect of all this cleaning up is that bsd.compiler.mk is no longer implicitly included by bsd.own.mk. If you wish to use COMPILER_TYPE, you must now explicitly include bsd.compiler.mk as well. 20140430: The lindev device has been removed since /dev/full has been made a standard device. __FreeBSD_version has been bumped. 20140424: The knob WITHOUT_VI was added to the base system, which controls building ex(1), vi(1), etc. Older releases of FreeBSD required ex(1) in order to reorder files share/termcap and didn't build ex(1) as a build tool, so building/installing with WITH_VI is highly advised for build hosts for older releases. This issue has been fixed in stable/9 and stable/10 in r277022 and r276991, respectively. 20140418: The YES_HESIOD knob has been removed. It has been obsolete for a decade. Please move to using WITH_HESIOD instead or your builds will silently lack HESIOD. 20140405: The uart(4) driver has been changed with respect to its handling of the low-level console. Previously the uart(4) driver prevented any process from changing the baudrate or the CLOCAL and HUPCL control flags. By removing the restrictions, operators can make changes to the serial console port without having to reboot. However, when getty(8) is started on the serial device that is associated with the low-level console, a misconfigured terminal line in /etc/ttys will now have a real impact. Before upgrading the kernel, make sure that /etc/ttys has the serial console device configured as 3wire without baudrate to preserve the previous behaviour. E.g: ttyu0 "/usr/libexec/getty 3wire" vt100 on secure 20140306: Support for libwrap (TCP wrappers) in rpcbind was disabled by default to improve performance. To re-enable it, if needed, run rpcbind with command line option -W. 20140226: Switched back to the GPL dtc compiler due to updates in the upstream dts files not being supported by the BSDL dtc compiler. You will need to rebuild your kernel toolchain to pick up the new compiler. Core dumps may result while building dtb files during a kernel build if you fail to do so. Set WITHOUT_GPL_DTC if you require the BSDL compiler. 20140216: Clang and llvm have been upgraded to 3.4 release. 20140216: The nve(4) driver has been removed. Please use the nfe(4) driver for NVIDIA nForce MCP Ethernet adapters instead. 20140212: An ABI incompatibility crept into the libc++ 3.4 import in r261283. This could cause certain C++ applications using shared libraries built against the previous version of libc++ to crash. The incompatibility has now been fixed, but any C++ applications or shared libraries built between r261283 and r261801 should be recompiled. 20140204: OpenSSH will now ignore errors caused by kernel lacking of Capsicum capability mode support. Please note that enabling the feature in kernel is still highly recommended. 20140131: OpenSSH is now built with sandbox support, and will use sandbox as the default privilege separation method. This requires Capsicum capability mode support in kernel. 20140128: The libelf and libdwarf libraries have been updated to newer versions from upstream. Shared library version numbers for these two libraries were bumped. Any ports or binaries requiring these two libraries should be recompiled. __FreeBSD_version is bumped to 1100006. 20140110: If a Makefile in a tests/ directory was auto-generating a Kyuafile instead of providing an explicit one, this would prevent such Makefile from providing its own Kyuafile in the future during NO_CLEAN builds. This has been fixed in the Makefiles but manual intervention is needed to clean an objdir if you use NO_CLEAN: # find /usr/obj -name Kyuafile | xargs rm -f 20131213: The behavior of gss_pseudo_random() for the krb5 mechanism has changed, for applications requesting a longer random string than produced by the underlying enctype's pseudo-random() function. In particular, the random string produced from a session key of enctype aes256-cts-hmac-sha1-96 or aes256-cts-hmac-sha1-96 will be different at the 17th octet and later, after this change. The counter used in the PRF+ construction is now encoded as a big-endian integer in accordance with RFC 4402. __FreeBSD_version is bumped to 1100004. 20131108: The WITHOUT_ATF build knob has been removed and its functionality has been subsumed into the more generic WITHOUT_TESTS. If you were using the former to disable the build of the ATF libraries, you should change your settings to use the latter. 20131025: The default version of mtree is nmtree which is obtained from NetBSD. The output is generally the same, but may vary slightly. If you found you need identical output adding "-F freebsd9" to the command line should do the trick. For the time being, the old mtree is available as fmtree. 20131014: libbsdyml has been renamed to libyaml and moved to /usr/lib/private. This will break ports-mgmt/pkg. Rebuild the port, or upgrade to pkg 1.1.4_8 and verify bsdyml not linked in, before running "make delete-old-libs": # make -C /usr/ports/ports-mgmt/pkg build deinstall install clean or # pkg install pkg; ldd /usr/local/sbin/pkg | grep bsdyml 20131010: The stable/10 branch has been created in subversion from head revision r256279. COMMON ITEMS: General Notes ------------- Avoid using make -j when upgrading. While generally safe, there are sometimes problems using -j to upgrade. If your upgrade fails with -j, please try again without -j. From time to time in the past there have been problems using -j with buildworld and/or installworld. This is especially true when upgrading between "distant" versions (eg one that cross a major release boundary or several minor releases, or when several months have passed on the -current branch). Sometimes, obscure build problems are the result of environment poisoning. This can happen because the make utility reads its environment when searching for values for global variables. To run your build attempts in an "environmental clean room", prefix all make commands with 'env -i '. See the env(1) manual page for more details. When upgrading from one major version to another it is generally best to upgrade to the latest code in the currently installed branch first, then do an upgrade to the new branch. This is the best-tested upgrade path, and has the highest probability of being successful. Please try this approach if you encounter problems with a major version upgrade. Since the stable 4.x branch point, one has generally been able to upgrade from anywhere in the most recent stable branch to head / current (or even the last couple of stable branches). See the top of this file when there's an exception. When upgrading a live system, having a root shell around before installing anything can help undo problems. Not having a root shell around can lead to problems if pam has changed too much from your starting point to allow continued authentication after the upgrade. This file should be read as a log of events. When a later event changes information of a prior event, the prior event should not be deleted. Instead, a pointer to the entry with the new information should be placed in the old entry. Readers of this file should also sanity check older entries before relying on them blindly. Authors of new entries should write them with this in mind. ZFS notes --------- When upgrading the boot ZFS pool to a new version, always follow these two steps: 1.) recompile and reinstall the ZFS boot loader and boot block (this is part of "make buildworld" and "make installworld") 2.) update the ZFS boot block on your boot drive The following example updates the ZFS boot block on the first partition (freebsd-boot) of a GPT partitioned drive ada0: "gpart bootcode -p /boot/gptzfsboot -i 1 ada0" Non-boot pools do not need these updates. To build a kernel ----------------- If you are updating from a prior version of FreeBSD (even one just a few days old), you should follow this procedure. It is the most failsafe as it uses a /usr/obj tree with a fresh mini-buildworld, make kernel-toolchain make -DALWAYS_CHECK_MAKE buildkernel KERNCONF=YOUR_KERNEL_HERE make -DALWAYS_CHECK_MAKE installkernel KERNCONF=YOUR_KERNEL_HERE To test a kernel once --------------------- If you just want to boot a kernel once (because you are not sure if it works, or if you want to boot a known bad kernel to provide debugging information) run make installkernel KERNCONF=YOUR_KERNEL_HERE KODIR=/boot/testkernel nextboot -k testkernel To rebuild everything and install it on the current system. ----------------------------------------------------------- # Note: sometimes if you are running current you gotta do more than # is listed here if you are upgrading from a really old current. make buildworld make buildkernel KERNCONF=YOUR_KERNEL_HERE make installkernel KERNCONF=YOUR_KERNEL_HERE [1] [3] mergemaster -Fp [5] make installworld mergemaster -Fi [4] make delete-old [6] To cross-install current onto a separate partition -------------------------------------------------- # In this approach we use a separate partition to hold # current's root, 'usr', and 'var' directories. A partition # holding "/", "/usr" and "/var" should be about 2GB in # size. make buildworld make buildkernel KERNCONF=YOUR_KERNEL_HERE make installworld DESTDIR=${CURRENT_ROOT} -DDB_FROM_SRC make distribution DESTDIR=${CURRENT_ROOT} # if newfs'd make installkernel KERNCONF=YOUR_KERNEL_HERE DESTDIR=${CURRENT_ROOT} cp /etc/fstab ${CURRENT_ROOT}/etc/fstab # if newfs'd To upgrade in-place from stable to current ---------------------------------------------- make buildworld [9] make buildkernel KERNCONF=YOUR_KERNEL_HERE [8] make installkernel KERNCONF=YOUR_KERNEL_HERE [1] [3] mergemaster -Fp [5] make installworld mergemaster -Fi [4] make delete-old [6] Make sure that you've read the UPDATING file to understand the tweaks to various things you need. At this point in the life cycle of current, things change often and you are on your own to cope. The defaults can also change, so please read ALL of the UPDATING entries. Also, if you are tracking -current, you must be subscribed to freebsd-current@freebsd.org. Make sure that before you update your sources that you have read and understood all the recent messages there. If in doubt, please track -stable which has much fewer pitfalls. [1] If you have third party modules, such as vmware, you should disable them at this point so they don't crash your system on reboot. [3] From the bootblocks, boot -s, and then do fsck -p mount -u / mount -a sh /etc/rc.d/zfs start # mount zfs filesystem, if needed cd src # full path to source adjkerntz -i # if CMOS is wall time Also, when doing a major release upgrade, it is required that you boot into single user mode to do the installworld. [4] Note: This step is non-optional. Failure to do this step can result in a significant reduction in the functionality of the system. Attempting to do it by hand is not recommended and those that pursue this avenue should read this file carefully, as well as the archives of freebsd-current and freebsd-hackers mailing lists for potential gotchas. The -U option is also useful to consider. See mergemaster(8) for more information. [5] Usually this step is a no-op. However, from time to time you may need to do this if you get unknown user in the following step. It never hurts to do it all the time. You may need to install a new mergemaster (cd src/usr.sbin/mergemaster && make install) after the buildworld before this step if you last updated from current before 20130425 or from -stable before 20130430. [6] This only deletes old files and directories. Old libraries can be deleted by "make delete-old-libs", but you have to make sure that no program is using those libraries anymore. [8] The new kernel must be able to run existing binaries used by an installworld. When upgrading across major versions, the new kernel's configuration must include the correct COMPAT_FREEBSD option for existing binaries (e.g. COMPAT_FREEBSD11 to run 11.x binaries). Failure to do so may leave you with a system that is hard to boot to recover. A GENERIC kernel will include suitable compatibility options to run binaries from older branches. Note that the ability to run binaries from unsupported branches is not guaranteed. Make sure that you merge any new devices from GENERIC since the last time you updated your kernel config file. Options also change over time, so you may need to adjust your custom kernels for these as well. [9] If CPUTYPE is defined in your /etc/make.conf, make sure to use the "?=" instead of the "=" assignment operator, so that buildworld can override the CPUTYPE if it needs to. MAKEOBJDIRPREFIX must be defined in an environment variable, and not on the command line, or in /etc/make.conf. buildworld will warn if it is improperly defined. FORMAT: This file contains a list, in reverse chronological order, of major breakages in tracking -current. It is not guaranteed to be a complete list of such breakages, and only contains entries since September 23, 2011. If you need to see UPDATING entries from before that date, you will need to fetch an UPDATING file from an older FreeBSD release. Copyright information: -Copyright 1998-2009 M. Warner Losh. +Copyright 1998-2009 M. Warner Losh Redistribution, publication, translation and use, with or without modification, in full or in part, in any form or format of this document are permitted without further permission from the author. THIS DOCUMENT IS PROVIDED BY WARNER LOSH ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WARNER LOSH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Contact Warner Losh if you have any questions about your use of this document. $FreeBSD$ Index: head/lib/libc/stdlib/reallocf.c =================================================================== --- head/lib/libc/stdlib/reallocf.c (revision 355393) +++ head/lib/libc/stdlib/reallocf.c (revision 355394) @@ -1,50 +1,49 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 1998, M. Warner Losh - * All rights reserved. + * Copyright (c) 1998 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include void * reallocf(void *ptr, size_t size) { void *nptr; nptr = realloc(ptr, size); /* * When the System V compatibility option (malloc "V" flag) is * in effect, realloc(ptr, 0) frees the memory and returns NULL. * So, to avoid double free, call free() only when size != 0. * realloc(ptr, 0) can't fail when ptr != NULL. */ if (!nptr && ptr && size != 0) free(ptr); return (nptr); } Index: head/lib/libc/sys/compat-ino64.h =================================================================== --- head/lib/libc/sys/compat-ino64.h (revision 355393) +++ head/lib/libc/sys/compat-ino64.h (revision 355394) @@ -1,102 +1,101 @@ /*- * Copyright (c) 2017 M. Warner Losh - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ /* * Forward compatibility shim to convert old stat buffer to * new so we can call the old system call, but return data in * the new system call's format. */ #define _WANT_FREEBSD11_STATFS #include #include #define _WANT_FREEBSD11_STAT #include #include #define INO64_FIRST 1200031 static __inline void __stat11_to_stat(const struct freebsd11_stat *sb11, struct stat *sb) { sb->st_dev = sb11->st_dev; sb->st_ino = sb11->st_ino; sb->st_nlink = sb11->st_nlink; sb->st_mode = sb11->st_mode; sb->st_uid = sb11->st_uid; sb->st_gid = sb11->st_gid; sb->st_rdev = sb11->st_rdev; sb->st_atim = sb11->st_atim; sb->st_mtim = sb11->st_mtim; sb->st_ctim = sb11->st_ctim; #ifdef __STAT_TIME_T_EXT sb->st_atim_ext = 0; sb->st_mtim_ext = 0; sb->st_ctim_ext = 0; sb->st_btim_ext = 0; #endif sb->st_birthtim = sb11->st_birthtim; sb->st_size = sb11->st_size; sb->st_blocks = sb11->st_blocks; sb->st_blksize = sb11->st_blksize; sb->st_flags = sb11->st_flags; sb->st_gen = sb11->st_gen; sb->st_padding0 = 0; sb->st_padding1 = 0; memset(sb->st_spare, 0, sizeof(sb->st_spare)); } static __inline void __statfs11_to_statfs(const struct freebsd11_statfs *sf11, struct statfs *sf) { sf->f_version = STATFS_VERSION; sf->f_type = sf11->f_type; sf->f_flags = sf11->f_flags; sf->f_bsize = sf11->f_bsize; sf->f_iosize = sf11->f_iosize; sf->f_blocks = sf11->f_blocks; sf->f_bfree = sf11->f_bfree; sf->f_bavail = sf11->f_bavail; sf->f_files = sf11->f_files; sf->f_ffree = sf11->f_ffree; sf->f_syncwrites = sf11->f_syncwrites; sf->f_asyncwrites = sf11->f_asyncwrites; sf->f_syncreads = sf11->f_syncreads; sf->f_asyncreads = sf11->f_asyncreads; sf->f_namemax = sf11->f_namemax; sf->f_owner = sf11->f_owner; sf->f_fsid = sf11->f_fsid; memset(sf->f_spare, 0, sizeof(sf->f_spare)); memset(sf->f_charspare, 0, sizeof(sf->f_charspare)); strlcpy(sf->f_fstypename, sf11->f_fstypename, sizeof(sf->f_fstypename)); strlcpy(sf->f_mntfromname, sf11->f_mntfromname, sizeof(sf->f_mntfromname)); strlcpy(sf->f_mntonname, sf11->f_mntonname, sizeof(sf->f_mntonname)); } Index: head/lib/libc/sys/fstat.c =================================================================== --- head/lib/libc/sys/fstat.c (revision 355393) +++ head/lib/libc/sys/fstat.c (revision 355394) @@ -1,54 +1,53 @@ /*- * Copyright (c) 2017 M. Warner Losh - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include "namespace.h" #include #include #include "compat-ino64.h" #include #include "libc_private.h" #undef fstat __weak_reference(_fstat, fstat); #pragma weak _fstat int _fstat(int fd, struct stat *sb) { struct freebsd11_stat stat11; int rv; if (__getosreldate() >= INO64_FIRST) return (__sys_fstat(fd, sb)); rv = syscall(SYS_freebsd11_fstat, fd, &stat11); if (rv == 0) __stat11_to_stat(&stat11, sb); return (rv); } Index: head/lib/libc/sys/fstatat.c =================================================================== --- head/lib/libc/sys/fstatat.c (revision 355393) +++ head/lib/libc/sys/fstatat.c (revision 355394) @@ -1,50 +1,49 @@ /*- * Copyright (c) 2017 M. Warner Losh - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include "namespace.h" #include #include #include "compat-ino64.h" #include #include "libc_private.h" int fstatat(int fd, const char *path, struct stat *sb, int flag) { struct freebsd11_stat stat11; int rv; if (__getosreldate() >= INO64_FIRST) return (__sys_fstatat(fd, path, sb, flag)); rv = syscall(SYS_freebsd11_fstatat, fd, path, &stat11, flag); if (rv == 0) __stat11_to_stat(&stat11, sb); return (rv); } Index: head/lib/libc/sys/fstatfs.c =================================================================== --- head/lib/libc/sys/fstatfs.c (revision 355393) +++ head/lib/libc/sys/fstatfs.c (revision 355394) @@ -1,54 +1,53 @@ /*- * Copyright (c) 2017 M. Warner Losh - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include "namespace.h" #include #include #include "compat-ino64.h" #include #include "libc_private.h" #undef fstatfs __weak_reference(_fstatfs, fstatfs); #pragma weak _fstatfs int _fstatfs(int fd, struct statfs *buf) { struct freebsd11_statfs statfs11; int rv; if (__getosreldate() >= INO64_FIRST) return (__sys_fstatfs(fd, buf)); rv = syscall(SYS_freebsd11_fstatfs, fd, &statfs11); if (rv == 0) __statfs11_to_statfs(&statfs11, buf); return (rv); } Index: head/lib/libc/sys/getdirentries.c =================================================================== --- head/lib/libc/sys/getdirentries.c (revision 355393) +++ head/lib/libc/sys/getdirentries.c (revision 355394) @@ -1,117 +1,116 @@ /*- * Copyright (c) 2017 M. Warner Losh - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #define _WANT_FREEBSD11_DIRENT #include "namespace.h" #include #include #include "compat-ino64.h" #include #include #include #include #include #include #include #include "libc_private.h" static ssize_t __cvt_dirents_from11(const char *de11, ssize_t len11, char *de, ssize_t len) { struct dirent *dst; const struct freebsd11_dirent *src; const char *edst, *esrc; ssize_t rlen; src = (const struct freebsd11_dirent *)de11; dst = (struct dirent *)de; esrc = de11 + len11; edst = de + len; while ((const char *)src < esrc && (const char *)dst < edst) { rlen = roundup(offsetof(struct dirent, d_name) + src->d_namlen + 1, 8); if ((const char *)dst + rlen >= edst) break; dst->d_fileno = src->d_fileno; dst->d_off = 0; /* nothing uses it yet, so safe for now */ dst->d_reclen = rlen; dst->d_type = src->d_type; dst->d_pad0 = 0; dst->d_namlen = src->d_namlen; dst->d_pad1 = 0; memset(dst->d_name, 0, roundup(src->d_namlen + 1, 8)); memcpy(dst->d_name, src->d_name, src->d_namlen); dst = (struct dirent *)((char *)dst + rlen); src = (const struct freebsd11_dirent *)((const char *)src + src->d_reclen); } return ((char *)dst - de); } #undef getdirentries __weak_reference(_getdirentries, getdirentries); #pragma weak _getdirentries ssize_t _getdirentries(int fd, char *buf, size_t nbytes, off_t *basep) { char *oldbuf; size_t len; ssize_t rv; if (__getosreldate() >= INO64_FIRST) return (__sys_getdirentries(fd, buf, nbytes, basep)); /* * Because the old system call returns entries that are smaller than the * new, we could wind up in a situation where we have too many to fit in * the buffer with the new encoding. So sacrifice a small bit of * efficiency to ensure that never happens. We pick 1/4 the size round * up to the next DIRBLKSIZ. This will guarnatee enough room exists in * the dst buffer due to changes in efficiency in packing dirent * entries. We don't check against minimum block size to avoid a lot of * stat calls, we'll see if that's wise or not. * TBD: Will this difference matter to lseek? */ len = roundup(nbytes / 4, DIRBLKSIZ); oldbuf = malloc(len); if (oldbuf == NULL) { errno = EINVAL; /* ENOMEM not in possible list */ return (-1); } rv = syscall(SYS_freebsd11_getdirentries, fd, oldbuf, len, basep); if (rv == -1) { free(oldbuf); return (rv); } if (rv > 0) rv = __cvt_dirents_from11(oldbuf, rv, buf, nbytes); free(oldbuf); return (rv); } Index: head/lib/libc/sys/getfsstat.c =================================================================== --- head/lib/libc/sys/getfsstat.c (revision 355393) +++ head/lib/libc/sys/getfsstat.c (revision 355394) @@ -1,65 +1,64 @@ /*- * Copyright (c) 2017 M. Warner Losh - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include "namespace.h" #include #include "compat-ino64.h" #include #include #include #include #include "libc_private.h" int getfsstat(struct statfs *buf, long bufsize, int flags) { struct freebsd11_statfs *statfs11 = NULL; ssize_t len = 0; int rv, i; if (__getosreldate() >= INO64_FIRST) return (__sys_getfsstat(buf, bufsize, flags)); if (buf != NULL) { len = sizeof(struct freebsd11_statfs) * /* Round down on purpose to avoid */ (bufsize / sizeof(struct statfs)); /* overflow on translation. */ statfs11 = malloc(len); if (statfs11 == NULL) { errno = ENOMEM; return (-1); } } rv = syscall(SYS_freebsd11_getfsstat, statfs11, len, flags); if (rv != -1 && buf != NULL) { for (i = 0; i < rv; i++) __statfs11_to_statfs(&statfs11[i], &buf[i]); } free(statfs11); return (rv); } Index: head/lib/libc/sys/lstat.c =================================================================== --- head/lib/libc/sys/lstat.c (revision 355393) +++ head/lib/libc/sys/lstat.c (revision 355394) @@ -1,51 +1,50 @@ /*- + * Copyright (c) 2012 Gleb Kurtsou All rights reserved. * Copyright (c) 2017 M. Warner Losh - * Copyright (c) 2012 Gleb Kurtsou - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include "namespace.h" #include #include #include "compat-ino64.h" #include #include "libc_private.h" int lstat(const char *path, struct stat *sb) { struct freebsd11_stat stat11; int rv; if (__getosreldate() >= INO64_FIRST) return (__sys_fstatat(AT_FDCWD, path, sb, AT_SYMLINK_NOFOLLOW)); rv = syscall(SYS_freebsd11_lstat, path, &stat11); if (rv == 0) __stat11_to_stat(&stat11, sb); return (rv); } Index: head/lib/libc/sys/stat.c =================================================================== --- head/lib/libc/sys/stat.c (revision 355393) +++ head/lib/libc/sys/stat.c (revision 355394) @@ -1,51 +1,50 @@ /*- + * Copyright (c) 2012 Gleb Kurtsou All rights reserved. * Copyright (c) 2017 M. Warner Losh - * Copyright (c) 2012 Gleb Kurtsou - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include "namespace.h" #include #include #include "compat-ino64.h" #include #include "libc_private.h" int stat(const char *path, struct stat *sb) { struct freebsd11_stat stat11; int rv; if (__getosreldate() >= INO64_FIRST) return (__sys_fstatat(AT_FDCWD, path, sb, 0)); rv = syscall(SYS_freebsd11_stat, path, &stat11); if (rv == 0) __stat11_to_stat(&stat11, sb); return (rv); } Index: head/lib/libc/sys/statfs.c =================================================================== --- head/lib/libc/sys/statfs.c (revision 355393) +++ head/lib/libc/sys/statfs.c (revision 355394) @@ -1,50 +1,49 @@ /*- * Copyright (c) 2017 M. Warner Losh - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include "namespace.h" #include #include #include "compat-ino64.h" #include #include "libc_private.h" int statfs(const char *path, struct statfs *buf) { struct freebsd11_statfs statfs11; int rv; if (__getosreldate() >= INO64_FIRST) return (__sys_statfs(path, buf)); rv = syscall(SYS_freebsd11_statfs, path, &statfs11); if (rv == 0) __statfs11_to_statfs(&statfs11, buf); return (rv); } Index: head/libexec/rc/rc.d/devmatch =================================================================== --- head/libexec/rc/rc.d/devmatch (revision 355393) +++ head/libexec/rc/rc.d/devmatch (revision 355394) @@ -1,75 +1,75 @@ #!/bin/sh -# Copyright (c) 2018 M. Warner Losh +# Copyright (c) 2018 M. Warner Losh # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # $FreeBSD$ # # PROVIDE: devmatch # REQUIRE: kldxref # KEYWORD: nojail . /etc/rc.subr name="devmatch" desc="Use devmatch(8) to load kernel modules" rcvar="${name}_enable" start_cmd="${name}_start" stop_cmd=':' one_nomatch="$2" devmatch_start() { local x m list if [ -n "$one_nomatch" ]; then list=$(devmatch -p "${one_nomatch}" | sort -u) else list=$(devmatch | sort -u) fi [ -n "$list" ] || return # While kldload can accept multiple modules # on the line at once, we loop here in case # there's some weird error with one of them. # We also optimize against the false positives # or drivers that have symbolic links that # confuse devmatch by running it -n. # Finally, we filter out all items in the # devmactch_blacklist. devctl freeze x=$(echo ${devmatch_blacklist} | tr ' ' '#') for m in ${list}; do case "#${x}#" in *"#${m}#"*) continue ;; esac echo "Autoloading module: ${m}" kldload -n ${m} done devctl thaw } load_rc_config $name run_rc_command "$1" Index: head/libexec/talkd/extern.h =================================================================== --- head/libexec/talkd/extern.h (revision 355393) +++ head/libexec/talkd/extern.h (revision 355394) @@ -1,45 +1,45 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2002 M. Warner Losh. + * Copyright (c) 2002 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ extern int debug; extern char hostname[]; int announce(CTL_MSG *, const char *); int delete_invite(u_int32_t); void do_announce(CTL_MSG *, CTL_RESPONSE *); CTL_MSG *find_match(CTL_MSG *request); CTL_MSG *find_request(CTL_MSG *request); int find_user(const char *name, char *tty); void insert_table(CTL_MSG *, CTL_RESPONSE *); int new_id(void); int print_mesg(const char *, CTL_MSG *, const char *); void print_request(const char *, CTL_MSG *); void print_response(const char *, CTL_RESPONSE *); void process_request(CTL_MSG *mp, CTL_RESPONSE *rp); void timeout(int sig); Index: head/sbin/devd/devd.8 =================================================================== --- head/sbin/devd/devd.8 (revision 355393) +++ head/sbin/devd/devd.8 (revision 355394) @@ -1,163 +1,162 @@ .\" -.\" Copyright (c) 2002 M. Warner Losh. -.\" All rights reserved. +.\" Copyright (c) 2002 M. Warner Losh .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" $FreeBSD$ .\" .Dd October 5, 2016 .Dt DEVD 8 .Os .Sh NAME .Nm devd .Nd "device state change daemon" .Sh SYNOPSIS .Nm .Op Fl dnq .Op Fl f Ar file .Op Fl l Ar num .Sh DESCRIPTION The .Nm daemon provides a way to have userland programs run when certain kernel events happen. .Pp The following options are accepted. .Bl -tag -width ".Fl f Ar file" .It Fl d Run in the foreground instead of becoming a daemon and log additional information for debugging. .It Fl f Ar file Use configuration file .Ar file instead of the default .Pa /etc/devd.conf . If option .Fl f is specified more than once, the last file specified is used. .It Fl l Ar num Limit concurrent socket connections to .Ar num . The default connection limit is 10. .It Fl n Do not process all pending events before becoming a daemon. Instead, call daemon right away. .It Fl q Quiet mode. Only log messages at priority LOG_WARNING or above. .El .Sh IMPLEMENTATION NOTES The .Nm utility is a system daemon that runs in the background all the time. Whenever a device is added to or removed from the device tree, .Nm will execute actions specified in .Xr devd.conf 5 . For example, .Nm might execute .Xr dhclient 8 when an Ethernet adapter is added to the system, and kill the .Xr dhclient 8 instance when the same adapter is removed. Another example would be for .Nm to use a table to locate and load via .Xr kldload 8 the proper driver for an unrecognized device that is added to the system. .Pp The .Nm utility hooks into the .Xr devctl 4 device driver. This device driver has hooks into the device configuration system. When nodes are added or deleted from the tree, this device will deliver information about the event to .Nm . Once .Nm has parsed the message, it will search its action list for that kind of event and perform the action with the highest matching value. For most mundane uses, the default handlers are adequate. However, for more advanced users, the power is present to tweak every aspect of what happens. .Pp The .Nm utility reads .Pa /etc/devd.conf or the alternate configuration file specified with a .Fl f option and uses that file to drive the rest of the process. While the format of this file is described in .Xr devd.conf 5 , some basics are covered here. In the .Ic options section, one can define multiple directories to search for config files. All files in these directories whose names match the pattern .Pa *.conf are parsed. These files are intended to be installed by third party vendors that wish to hook into the .Nm system without modifying the user's other config files. .Pp Since .Xr devctl 4 allows only one active reader, .Nm multiplexes it, forwarding all events to any number of connected clients. Clients connect by opening the SOCK_SEQPACKET .Ux domain socket at .Pa /var/run/devd.seqpacket.pipe . .Sh FILES .Bl -tag -width ".Pa /var/run/devd.seqpacket.pipe" -compact .It Pa /etc/devd.conf The default .Nm configuration file. .It Pa /var/run/devd.seqpacket.pipe The socket used by .Nm to communicate with its clients. .It Pa /var/run/devd.pipe A deprecated socket retained for use with old clients. .El .Sh SEE ALSO .Xr devctl 4 , .Xr devd.conf 5 .Sh HISTORY The .Nm utility first appeared in .Fx 5.0 . .Sh AUTHORS .An M. Warner Losh Index: head/sbin/devd/devd.cc =================================================================== --- head/sbin/devd/devd.cc (revision 355393) +++ head/sbin/devd/devd.cc (revision 355394) @@ -1,1332 +1,1331 @@ /*- * SPDX-License-Identifier: BSD-3-Clause AND BSD-2-Clause-FreeBSD * - * Copyright (c) 2002-2010 M. Warner Losh. - * All rights reserved. + * Copyright (c) 2002-2010 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * my_system is a variation on lib/libc/stdlib/system.c: * * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * DEVD control daemon. */ // TODO list: // o devd.conf and devd man pages need a lot of help: // - devd needs to document the unix domain socket // - devd.conf needs more details on the supported statements. #include __FBSDID("$FreeBSD$"); #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 "devd.h" /* C compatible definitions */ #include "devd.hh" /* C++ class definitions */ #define STREAMPIPE "/var/run/devd.pipe" #define SEQPACKETPIPE "/var/run/devd.seqpacket.pipe" #define CF "/etc/devd.conf" #define SYSCTL "hw.bus.devctl_queue" /* * Since the client socket is nonblocking, we must increase its send buffer to * handle brief event storms. On FreeBSD, AF_UNIX sockets don't have a receive * buffer, so the client can't increase the buffersize by itself. * * For example, when creating a ZFS pool, devd emits one 165 character * resource.fs.zfs.statechange message for each vdev in the pool. The kernel * allocates a 4608B mbuf for each message. Modern technology places a limit of * roughly 450 drives/rack, and it's unlikely that a zpool will ever be larger * than that. * * 450 drives * 165 bytes / drive = 74250B of data in the sockbuf * 450 drives * 4608B / drive = 2073600B of mbufs in the sockbuf * * We can't directly set the sockbuf's mbuf limit, but we can do it indirectly. * The kernel sets it to the minimum of a hard-coded maximum value and sbcc * * kern.ipc.sockbuf_waste_factor, where sbcc is the socket buffer size set by * the user. The default value of kern.ipc.sockbuf_waste_factor is 8. If we * set the bufsize to 256k and use the kern.ipc.sockbuf_waste_factor, then the * kernel will set the mbuf limit to 2MB, which is just large enough for 450 * drives. It also happens to be the same as the hardcoded maximum value. */ #define CLIENT_BUFSIZE 262144 using namespace std; typedef struct client { int fd; int socktype; } client_t; extern FILE *yyin; static const char notify = '!'; static const char nomatch = '?'; static const char attach = '+'; static const char detach = '-'; static struct pidfh *pfh; static int no_daemon = 0; static int daemonize_quick = 0; static int quiet_mode = 0; static unsigned total_events = 0; static volatile sig_atomic_t got_siginfo = 0; static volatile sig_atomic_t romeo_must_die = 0; static const char *configfile = CF; static void devdlog(int priority, const char* message, ...) __printflike(2, 3); static void event_loop(void); static void usage(void) __dead2; template void delete_and_clear(vector &v) { typename vector::const_iterator i; for (i = v.begin(); i != v.end(); ++i) delete *i; v.clear(); } static config cfg; event_proc::event_proc() : _prio(-1) { _epsvec.reserve(4); } event_proc::~event_proc() { delete_and_clear(_epsvec); } void event_proc::add(eps *eps) { _epsvec.push_back(eps); } bool event_proc::matches(config &c) const { vector::const_iterator i; for (i = _epsvec.begin(); i != _epsvec.end(); ++i) if (!(*i)->do_match(c)) return (false); return (true); } bool event_proc::run(config &c) const { vector::const_iterator i; for (i = _epsvec.begin(); i != _epsvec.end(); ++i) if (!(*i)->do_action(c)) return (false); return (true); } action::action(const char *cmd) : _cmd(cmd) { // nothing } action::~action() { // nothing } static int my_system(const char *command) { pid_t pid, savedpid; int pstat; struct sigaction ign, intact, quitact; sigset_t newsigblock, oldsigblock; if (!command) /* just checking... */ return (1); /* * Ignore SIGINT and SIGQUIT, block SIGCHLD. Remember to save * existing signal dispositions. */ ign.sa_handler = SIG_IGN; ::sigemptyset(&ign.sa_mask); ign.sa_flags = 0; ::sigaction(SIGINT, &ign, &intact); ::sigaction(SIGQUIT, &ign, &quitact); ::sigemptyset(&newsigblock); ::sigaddset(&newsigblock, SIGCHLD); ::sigprocmask(SIG_BLOCK, &newsigblock, &oldsigblock); switch (pid = ::fork()) { case -1: /* error */ break; case 0: /* child */ /* * Restore original signal dispositions and exec the command. */ ::sigaction(SIGINT, &intact, NULL); ::sigaction(SIGQUIT, &quitact, NULL); ::sigprocmask(SIG_SETMASK, &oldsigblock, NULL); /* * Close the PID file, and all other open descriptors. * Inherit std{in,out,err} only. */ cfg.close_pidfile(); ::closefrom(3); ::execl(_PATH_BSHELL, "sh", "-c", command, (char *)NULL); ::_exit(127); default: /* parent */ savedpid = pid; do { pid = ::wait4(savedpid, &pstat, 0, (struct rusage *)0); } while (pid == -1 && errno == EINTR); break; } ::sigaction(SIGINT, &intact, NULL); ::sigaction(SIGQUIT, &quitact, NULL); ::sigprocmask(SIG_SETMASK, &oldsigblock, NULL); return (pid == -1 ? -1 : pstat); } bool action::do_action(config &c) { string s = c.expand_string(_cmd.c_str()); devdlog(LOG_INFO, "Executing '%s'\n", s.c_str()); my_system(s.c_str()); return (true); } match::match(config &c, const char *var, const char *re) : _inv(re[0] == '!'), _var(var), _re(c.expand_string(_inv ? re + 1 : re, "^", "$")) { regcomp(&_regex, _re.c_str(), REG_EXTENDED | REG_NOSUB | REG_ICASE); } match::~match() { regfree(&_regex); } bool match::do_match(config &c) { const string &value = c.get_variable(_var); bool retval; /* * This function gets called WAY too often to justify calling syslog() * each time, even at LOG_DEBUG. Because if syslogd isn't running, it * can consume excessive amounts of systime inside of connect(). Only * log when we're in -d mode. */ if (no_daemon) { devdlog(LOG_DEBUG, "Testing %s=%s against %s, invert=%d\n", _var.c_str(), value.c_str(), _re.c_str(), _inv); } retval = (regexec(&_regex, value.c_str(), 0, NULL, 0) == 0); if (_inv == 1) retval = (retval == 0) ? 1 : 0; return (retval); } #include #include #include media::media(config &, const char *var, const char *type) : _var(var), _type(-1) { static struct ifmedia_description media_types[] = { { IFM_ETHER, "Ethernet" }, { IFM_IEEE80211, "802.11" }, { IFM_ATM, "ATM" }, { -1, "unknown" }, { 0, NULL }, }; for (int i = 0; media_types[i].ifmt_string != NULL; ++i) if (strcasecmp(type, media_types[i].ifmt_string) == 0) { _type = media_types[i].ifmt_word; break; } } media::~media() { } bool media::do_match(config &c) { string value; struct ifmediareq ifmr; bool retval; int s; // Since we can be called from both a device attach/detach // context where device-name is defined and what we want, // as well as from a link status context, where subsystem is // the name of interest, first try device-name and fall back // to subsystem if none exists. value = c.get_variable("device-name"); if (value.empty()) value = c.get_variable("subsystem"); devdlog(LOG_DEBUG, "Testing media type of %s against 0x%x\n", value.c_str(), _type); retval = false; s = socket(PF_INET, SOCK_DGRAM, 0); if (s >= 0) { memset(&ifmr, 0, sizeof(ifmr)); strlcpy(ifmr.ifm_name, value.c_str(), sizeof(ifmr.ifm_name)); if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0 && ifmr.ifm_status & IFM_AVALID) { devdlog(LOG_DEBUG, "%s has media type 0x%x\n", value.c_str(), IFM_TYPE(ifmr.ifm_active)); retval = (IFM_TYPE(ifmr.ifm_active) == _type); } else if (_type == -1) { devdlog(LOG_DEBUG, "%s has unknown media type\n", value.c_str()); retval = true; } close(s); } return (retval); } const string var_list::bogus = "_$_$_$_$_B_O_G_U_S_$_$_$_$_"; const string var_list::nothing = ""; const string & var_list::get_variable(const string &var) const { map::const_iterator i; i = _vars.find(var); if (i == _vars.end()) return (var_list::bogus); return (i->second); } bool var_list::is_set(const string &var) const { return (_vars.find(var) != _vars.end()); } /** fix_value * * Removes quoted characters that have made it this far. \" are * converted to ". For all other characters, both \ and following * character. So the string 'fre\:\"' is translated to 'fred\:"'. */ std::string var_list::fix_value(const std::string &val) const { std::string rv(val); std::string::size_type pos(0); while ((pos = rv.find("\\\"", pos)) != rv.npos) { rv.erase(pos, 1); } return (rv); } void var_list::set_variable(const string &var, const string &val) { /* * This function gets called WAY too often to justify calling syslog() * each time, even at LOG_DEBUG. Because if syslogd isn't running, it * can consume excessive amounts of systime inside of connect(). Only * log when we're in -d mode. */ _vars[var] = fix_value(val); if (no_daemon) devdlog(LOG_DEBUG, "setting %s=%s\n", var.c_str(), val.c_str()); } void config::reset(void) { _dir_list.clear(); delete_and_clear(_var_list_table); delete_and_clear(_attach_list); delete_and_clear(_detach_list); delete_and_clear(_nomatch_list); delete_and_clear(_notify_list); } void config::parse_one_file(const char *fn) { devdlog(LOG_DEBUG, "Parsing %s\n", fn); yyin = fopen(fn, "r"); if (yyin == NULL) err(1, "Cannot open config file %s", fn); lineno = 1; if (yyparse() != 0) errx(1, "Cannot parse %s at line %d", fn, lineno); fclose(yyin); } void config::parse_files_in_dir(const char *dirname) { DIR *dirp; struct dirent *dp; char path[PATH_MAX]; devdlog(LOG_DEBUG, "Parsing files in %s\n", dirname); dirp = opendir(dirname); if (dirp == NULL) return; readdir(dirp); /* Skip . */ readdir(dirp); /* Skip .. */ while ((dp = readdir(dirp)) != NULL) { if (strcmp(dp->d_name + dp->d_namlen - 5, ".conf") == 0) { snprintf(path, sizeof(path), "%s/%s", dirname, dp->d_name); parse_one_file(path); } } closedir(dirp); } class epv_greater { public: int operator()(event_proc *const&l1, event_proc *const&l2) const { return (l1->get_priority() > l2->get_priority()); } }; void config::sort_vector(vector &v) { stable_sort(v.begin(), v.end(), epv_greater()); } void config::parse(void) { vector::const_iterator i; parse_one_file(configfile); for (i = _dir_list.begin(); i != _dir_list.end(); ++i) parse_files_in_dir((*i).c_str()); sort_vector(_attach_list); sort_vector(_detach_list); sort_vector(_nomatch_list); sort_vector(_notify_list); } void config::open_pidfile() { pid_t otherpid; if (_pidfile.empty()) return; pfh = pidfile_open(_pidfile.c_str(), 0600, &otherpid); if (pfh == NULL) { if (errno == EEXIST) errx(1, "devd already running, pid: %d", (int)otherpid); warn("cannot open pid file"); } } void config::write_pidfile() { pidfile_write(pfh); } void config::close_pidfile() { pidfile_close(pfh); } void config::remove_pidfile() { pidfile_remove(pfh); } void config::add_attach(int prio, event_proc *p) { p->set_priority(prio); _attach_list.push_back(p); } void config::add_detach(int prio, event_proc *p) { p->set_priority(prio); _detach_list.push_back(p); } void config::add_directory(const char *dir) { _dir_list.push_back(string(dir)); } void config::add_nomatch(int prio, event_proc *p) { p->set_priority(prio); _nomatch_list.push_back(p); } void config::add_notify(int prio, event_proc *p) { p->set_priority(prio); _notify_list.push_back(p); } void config::set_pidfile(const char *fn) { _pidfile = fn; } void config::push_var_table() { var_list *vl; vl = new var_list(); _var_list_table.push_back(vl); devdlog(LOG_DEBUG, "Pushing table\n"); } void config::pop_var_table() { delete _var_list_table.back(); _var_list_table.pop_back(); devdlog(LOG_DEBUG, "Popping table\n"); } void config::set_variable(const char *var, const char *val) { _var_list_table.back()->set_variable(var, val); } const string & config::get_variable(const string &var) { vector::reverse_iterator i; for (i = _var_list_table.rbegin(); i != _var_list_table.rend(); ++i) { if ((*i)->is_set(var)) return ((*i)->get_variable(var)); } return (var_list::nothing); } bool config::is_id_char(char ch) const { return (ch != '\0' && (isalpha(ch) || isdigit(ch) || ch == '_' || ch == '-')); } string config::shell_quote(const string &s) { string buffer; const char *cs, *ce; char c; /* * Enclose the string in $' ' with escapes for ' and / characters making * it one argument and ensuring the shell won't be affected by its * usual list of candidates. */ buffer.reserve(s.length() * 3 / 2); buffer += '$'; buffer += '\''; cs = s.c_str(); ce = cs + strlen(cs); for (; cs < ce; cs++) { c = *cs; if (c == '\'' || c == '\\') { buffer += '\\'; } buffer += c; } buffer += '\''; return buffer; } void config::expand_one(const char *&src, string &dst, bool is_shell) { int count; string buffer; src++; // $$ -> $ if (*src == '$') { dst += *src++; return; } // $(foo) -> $(foo) // This is the escape hatch for passing down shell subcommands if (*src == '(') { dst += '$'; count = 1; /* If the string ends before ) is matched , return. */ while (count > 0 && *src) { if (*src == ')') count--; else if (*src == '(') count++; dst += *src++; } return; } // $[^-A-Za-z_*] -> $\1 if (!isalpha(*src) && *src != '_' && *src != '-' && *src != '*') { dst += '$'; dst += *src++; return; } // $var -> replace with value do { buffer += *src++; } while (is_id_char(*src)); dst.append(is_shell ? shell_quote(get_variable(buffer)) : get_variable(buffer)); } const string config::expand_string(const char *src, const char *prepend, const char *append) { const char *var_at; string dst; /* * 128 bytes is enough for 2427 of 2438 expansions that happen * while parsing config files, as tested on 2013-01-30. */ dst.reserve(128); if (prepend != NULL) dst = prepend; for (;;) { var_at = strchr(src, '$'); if (var_at == NULL) { dst.append(src); break; } dst.append(src, var_at - src); src = var_at; expand_one(src, dst, prepend == NULL); } if (append != NULL) dst.append(append); return (dst); } bool config::chop_var(char *&buffer, char *&lhs, char *&rhs) const { char *walker; if (*buffer == '\0') return (false); walker = lhs = buffer; while (is_id_char(*walker)) walker++; if (*walker != '=') return (false); walker++; // skip = if (*walker == '"') { walker++; // skip " rhs = walker; while (*walker && *walker != '"') { // Skip \" ... We leave it in the string and strip the \ later. // due to the super simplistic parser that we have here. if (*walker == '\\' && walker[1] == '"') walker++; walker++; } if (*walker != '"') return (false); rhs[-2] = '\0'; *walker++ = '\0'; } else { rhs = walker; while (*walker && !isspace(*walker)) walker++; if (*walker != '\0') *walker++ = '\0'; rhs[-1] = '\0'; } while (isspace(*walker)) walker++; buffer = walker; return (true); } char * config::set_vars(char *buffer) { char *lhs; char *rhs; while (1) { if (!chop_var(buffer, lhs, rhs)) break; set_variable(lhs, rhs); } return (buffer); } void config::find_and_execute(char type) { vector *l; vector::const_iterator i; const char *s; switch (type) { default: return; case notify: l = &_notify_list; s = "notify"; break; case nomatch: l = &_nomatch_list; s = "nomatch"; break; case attach: l = &_attach_list; s = "attach"; break; case detach: l = &_detach_list; s = "detach"; break; } devdlog(LOG_DEBUG, "Processing %s event\n", s); for (i = l->begin(); i != l->end(); ++i) { if ((*i)->matches(*this)) { (*i)->run(*this); break; } } } static void process_event(char *buffer) { char type; char *sp; struct timeval tv; char *timestr; sp = buffer + 1; devdlog(LOG_INFO, "Processing event '%s'\n", buffer); type = *buffer++; cfg.push_var_table(); // $* is the entire line cfg.set_variable("*", buffer - 1); // $_ is the entire line without the initial character cfg.set_variable("_", buffer); // Save the time this happened (as approximated by when we got // around to processing it). gettimeofday(&tv, NULL); asprintf(×tr, "%jd.%06ld", (uintmax_t)tv.tv_sec, tv.tv_usec); cfg.set_variable("timestamp", timestr); free(timestr); // Match doesn't have a device, and the format is a little // different, so handle it separately. switch (type) { case notify: //! (k=v)* sp = cfg.set_vars(sp); break; case nomatch: //? at location pnp-info on bus sp = strchr(sp, ' '); if (sp == NULL) return; /* Can't happen? */ *sp++ = '\0'; while (isspace(*sp)) sp++; if (strncmp(sp, "at ", 3) == 0) sp += 3; sp = cfg.set_vars(sp); while (isspace(*sp)) sp++; if (strncmp(sp, "on ", 3) == 0) cfg.set_variable("bus", sp + 3); break; case attach: /*FALLTHROUGH*/ case detach: sp = strchr(sp, ' '); if (sp == NULL) return; /* Can't happen? */ *sp++ = '\0'; cfg.set_variable("device-name", buffer); while (isspace(*sp)) sp++; if (strncmp(sp, "at ", 3) == 0) sp += 3; sp = cfg.set_vars(sp); while (isspace(*sp)) sp++; if (strncmp(sp, "on ", 3) == 0) cfg.set_variable("bus", sp + 3); break; } cfg.find_and_execute(type); cfg.pop_var_table(); } static int create_socket(const char *name, int socktype) { int fd, slen; struct sockaddr_un sun; if ((fd = socket(PF_LOCAL, socktype, 0)) < 0) err(1, "socket"); bzero(&sun, sizeof(sun)); sun.sun_family = AF_UNIX; strlcpy(sun.sun_path, name, sizeof(sun.sun_path)); slen = SUN_LEN(&sun); unlink(name); if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) err(1, "fcntl"); if (::bind(fd, (struct sockaddr *) & sun, slen) < 0) err(1, "bind"); listen(fd, 4); if (chown(name, 0, 0)) /* XXX - root.wheel */ err(1, "chown"); if (chmod(name, 0666)) err(1, "chmod"); return (fd); } static unsigned int max_clients = 10; /* Default, can be overridden on cmdline. */ static unsigned int num_clients; static list clients; static void notify_clients(const char *data, int len) { list::iterator i; /* * Deliver the data to all clients. Throw clients overboard at the * first sign of trouble. This reaps clients who've died or closed * their sockets, and also clients who are alive but failing to keep up * (or who are maliciously not reading, to consume buffer space in * kernel memory or tie up the limited number of available connections). */ for (i = clients.begin(); i != clients.end(); ) { int flags; if (i->socktype == SOCK_SEQPACKET) flags = MSG_EOR; else flags = 0; if (send(i->fd, data, len, flags) != len) { --num_clients; close(i->fd); i = clients.erase(i); devdlog(LOG_WARNING, "notify_clients: send() failed; " "dropping unresponsive client\n"); } else ++i; } } static void check_clients(void) { int s; struct pollfd pfd; list::iterator i; /* * Check all existing clients to see if any of them have disappeared. * Normally we reap clients when we get an error trying to send them an * event. This check eliminates the problem of an ever-growing list of * zombie clients because we're never writing to them on a system * without frequent device-change activity. */ pfd.events = 0; for (i = clients.begin(); i != clients.end(); ) { pfd.fd = i->fd; s = poll(&pfd, 1, 0); if ((s < 0 && s != EINTR ) || (s > 0 && (pfd.revents & POLLHUP))) { --num_clients; close(i->fd); i = clients.erase(i); devdlog(LOG_NOTICE, "check_clients: " "dropping disconnected client\n"); } else ++i; } } static void new_client(int fd, int socktype) { client_t s; int sndbuf_size; /* * First go reap any zombie clients, then accept the connection, and * shut down the read side to stop clients from consuming kernel memory * by sending large buffers full of data we'll never read. */ check_clients(); s.socktype = socktype; s.fd = accept(fd, NULL, NULL); if (s.fd != -1) { sndbuf_size = CLIENT_BUFSIZE; if (setsockopt(s.fd, SOL_SOCKET, SO_SNDBUF, &sndbuf_size, sizeof(sndbuf_size))) err(1, "setsockopt"); shutdown(s.fd, SHUT_RD); clients.push_back(s); ++num_clients; } else err(1, "accept"); } static void event_loop(void) { int rv; int fd; char buffer[DEVCTL_MAXBUF]; int once = 0; int stream_fd, seqpacket_fd, max_fd; int accepting; timeval tv; fd_set fds; fd = open(PATH_DEVCTL, O_RDONLY | O_CLOEXEC); if (fd == -1) err(1, "Can't open devctl device %s", PATH_DEVCTL); stream_fd = create_socket(STREAMPIPE, SOCK_STREAM); seqpacket_fd = create_socket(SEQPACKETPIPE, SOCK_SEQPACKET); accepting = 1; max_fd = max(fd, max(stream_fd, seqpacket_fd)) + 1; while (!romeo_must_die) { if (!once && !no_daemon && !daemonize_quick) { // Check to see if we have any events pending. tv.tv_sec = 0; tv.tv_usec = 0; FD_ZERO(&fds); FD_SET(fd, &fds); rv = select(fd + 1, &fds, NULL, NULL, &tv); // No events -> we've processed all pending events if (rv == 0) { devdlog(LOG_DEBUG, "Calling daemon\n"); cfg.remove_pidfile(); cfg.open_pidfile(); daemon(0, 0); cfg.write_pidfile(); once++; } } /* * When we've already got the max number of clients, stop * accepting new connections (don't put the listening sockets in * the set), shrink the accept() queue to reject connections * quickly, and poll the existing clients more often, so that we * notice more quickly when any of them disappear to free up * client slots. */ FD_ZERO(&fds); FD_SET(fd, &fds); if (num_clients < max_clients) { if (!accepting) { listen(stream_fd, max_clients); listen(seqpacket_fd, max_clients); accepting = 1; } FD_SET(stream_fd, &fds); FD_SET(seqpacket_fd, &fds); tv.tv_sec = 60; tv.tv_usec = 0; } else { if (accepting) { listen(stream_fd, 0); listen(seqpacket_fd, 0); accepting = 0; } tv.tv_sec = 2; tv.tv_usec = 0; } rv = select(max_fd, &fds, NULL, NULL, &tv); if (got_siginfo) { devdlog(LOG_NOTICE, "Events received so far=%u\n", total_events); got_siginfo = 0; } if (rv == -1) { if (errno == EINTR) continue; err(1, "select"); } else if (rv == 0) check_clients(); if (FD_ISSET(fd, &fds)) { rv = read(fd, buffer, sizeof(buffer) - 1); if (rv > 0) { total_events++; if (rv == sizeof(buffer) - 1) { devdlog(LOG_WARNING, "Warning: " "available event data exceeded " "buffer space\n"); } notify_clients(buffer, rv); buffer[rv] = '\0'; while (buffer[--rv] == '\n') buffer[rv] = '\0'; try { process_event(buffer); } catch (const std::length_error& e) { devdlog(LOG_ERR, "Dropping event %s " "due to low memory", buffer); } } else if (rv < 0) { if (errno != EINTR) break; } else { /* EOF */ break; } } if (FD_ISSET(stream_fd, &fds)) new_client(stream_fd, SOCK_STREAM); /* * Aside from the socket type, both sockets use the same * protocol, so we can process clients the same way. */ if (FD_ISSET(seqpacket_fd, &fds)) new_client(seqpacket_fd, SOCK_SEQPACKET); } cfg.remove_pidfile(); close(seqpacket_fd); close(stream_fd); close(fd); } /* * functions that the parser uses. */ void add_attach(int prio, event_proc *p) { cfg.add_attach(prio, p); } void add_detach(int prio, event_proc *p) { cfg.add_detach(prio, p); } void add_directory(const char *dir) { cfg.add_directory(dir); free(const_cast(dir)); } void add_nomatch(int prio, event_proc *p) { cfg.add_nomatch(prio, p); } void add_notify(int prio, event_proc *p) { cfg.add_notify(prio, p); } event_proc * add_to_event_proc(event_proc *ep, eps *eps) { if (ep == NULL) ep = new event_proc(); ep->add(eps); return (ep); } eps * new_action(const char *cmd) { eps *e = new action(cmd); free(const_cast(cmd)); return (e); } eps * new_match(const char *var, const char *re) { eps *e = new match(cfg, var, re); free(const_cast(var)); free(const_cast(re)); return (e); } eps * new_media(const char *var, const char *re) { eps *e = new media(cfg, var, re); free(const_cast(var)); free(const_cast(re)); return (e); } void set_pidfile(const char *name) { cfg.set_pidfile(name); free(const_cast(name)); } void set_variable(const char *var, const char *val) { cfg.set_variable(var, val); free(const_cast(var)); free(const_cast(val)); } static void gensighand(int) { romeo_must_die = 1; } /* * SIGINFO handler. Will print useful statistics to the syslog or stderr * as appropriate */ static void siginfohand(int) { got_siginfo = 1; } /* * Local logging function. Prints to syslog if we're daemonized; stderr * otherwise. */ static void devdlog(int priority, const char* fmt, ...) { va_list argp; va_start(argp, fmt); if (no_daemon) vfprintf(stderr, fmt, argp); else if (quiet_mode == 0 || priority <= LOG_WARNING) vsyslog(priority, fmt, argp); va_end(argp); } static void usage() { fprintf(stderr, "usage: %s [-dnq] [-l connlimit] [-f file]\n", getprogname()); exit(1); } static void check_devd_enabled() { int val = 0; size_t len; len = sizeof(val); if (sysctlbyname(SYSCTL, &val, &len, NULL, 0) != 0) errx(1, "devctl sysctl missing from kernel!"); if (val == 0) { warnx("Setting " SYSCTL " to 1000"); val = 1000; if (sysctlbyname(SYSCTL, NULL, NULL, &val, sizeof(val))) err(1, "sysctlbyname"); } } /* * main */ int main(int argc, char **argv) { int ch; check_devd_enabled(); while ((ch = getopt(argc, argv, "df:l:nq")) != -1) { switch (ch) { case 'd': no_daemon = 1; break; case 'f': configfile = optarg; break; case 'l': max_clients = MAX(1, strtoul(optarg, NULL, 0)); break; case 'n': daemonize_quick = 1; break; case 'q': quiet_mode = 1; break; default: usage(); } } cfg.parse(); if (!no_daemon && daemonize_quick) { cfg.open_pidfile(); daemon(0, 0); cfg.write_pidfile(); } signal(SIGPIPE, SIG_IGN); signal(SIGHUP, gensighand); signal(SIGINT, gensighand); signal(SIGTERM, gensighand); signal(SIGINFO, siginfohand); event_loop(); return (0); } Index: head/sbin/devd/devd.conf.5 =================================================================== --- head/sbin/devd/devd.conf.5 (revision 355393) +++ head/sbin/devd/devd.conf.5 (revision 355394) @@ -1,674 +1,673 @@ .\" -.\" Copyright (c) 2002 M. Warner Losh -.\" All rights reserved. +.\" Copyright (c) 2002 M. Warner Losh .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. The name of the author may not be used to endorse or promote products .\" derived from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" $FreeBSD$ .\" .\" The section on comments was taken from named.conf.5, which has the .\" following copyright: .\" Copyright (c) 1999-2000 by Internet Software Consortium .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above .\" copyright notice and this permission notice appear in all copies. .\" .\" THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS .\" ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES .\" OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE .\" CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL .\" DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR .\" PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS .\" ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS .\" SOFTWARE. .\" .Dd May 31, 2019 .Dt DEVD.CONF 5 .Os .Sh NAME .Nm devd.conf .Nd configuration file for .Xr devd 8 .Sh DESCRIPTION .Ss General Syntax A .Xr devd 8 configuration consists of two general features, statements and comments. All statements end with a semicolon. Many statements can contain substatements, which are also terminated with a semicolon. .Pp The following statements are supported: .Bl -tag -width ".Ic options" .It Ic attach Specifies various matching criteria and actions to perform when a newly attached device matches said criteria. .It Ic detach Specifies various matching criteria and actions to perform when a newly detached device matches said criteria. .It Ic nomatch Specifies various matching criteria and actions to perform when no device driver currently loaded in the kernel claims a (new) device. .It Ic notify Specifies various matching criteria and actions to perform when the kernel sends an event notification to userland. .It Ic options Specifies various options and parameters for the operation of .Xr devd 8 . .El .Pp Statements may occur in any order in the configuration file, and may be repeated as often as required. Further details on the syntax and meaning of each statement and their substatements are explained below. .Pp Each statement, except .Ic options has a priority (an arbitrary number) associated with it, where .Ql 0 is defined as the lowest priority. If two statements match the same event, only the action of the statement with highest priority will be executed. In this way generic statements can be overridden for devices or notifications that require special attention. .Pp The general syntax of a statement is: .Bd -literal -offset indent statement priority { substatement "value"; ... substatement "value"; }; .Ed .Ss Sub-statements The following sub-statements are supported within the .Ic options statement. .Bl -tag -width ".Ic directory" .It Ic directory Qq Ar /some/path ; Adds the given directory to the list of directories from which .Xr devd 8 will read all files named "*.conf" as further configuration files. Any number of .Ic directory statements can be used. .It Ic pid-file Qq Pa /var/run/devd.pid ; Specifies PID file. .It Ic set Ar regexp-name Qq Ar (some|regexp) ; Creates a regular expression and assigns it to the variable .Ar regexp-name . The variable is available throughout the rest of the configuration file. If the string begins with .Ql \&! , it matches if the regular expression formed by the rest of the string does not match. All regular expressions have an implicit .Ql ^$ around them. .El .Pp The following sub-statements are supported within the .Ic attach and .Ic detach statements. .Bl -tag -width ".Ic directory" .It Ic action Qq Ar command ; Command to execute upon a successful match. Example .Dq Li "/etc/pccard_ether $device-name start" . .It Ic class Qq Ar string ; This is shorthand for .Dq Ic match Qo Li class Qc Qq Ar string . .It Ic device-name Qq string ; This is shorthand for .Dq Ic match Qo Li device-name Qc Qq Ar string . This matches a device named .Ar string , which is allowed to be a regular expression or a variable previously created containing a regular expression. The .Dq Li device-name variable is available for later use with the .Ic action statement. .It Ic match Qo Ar variable Qc Qq Ar value ; Matches the content of .Ar value against .Ar variable ; the content of .Ar value may be a regular expression. Not required during .Ic attach nor .Ic detach events since the .Ic device-name statement takes care of all device matching. For a partial list of variables, see below. .It Ic media-type Qq Ar string ; For network devices, .Ic media-type will match devices that have the given media type. Valid media types are: .Dq Li Ethernet , .Dq Li Tokenring , .Dq Li FDDI , .Dq Li 802.11 , and .Dq Li ATM . .It Ic subdevice Qq Ar string ; This is shorthand for .Dq Ic match Qo Li subdevice Qc Qq Ar string . .El .Pp The following sub-statements are supported within the .Ic nomatch statement. .Bl -tag -width ".Ic directory" .It Ic action Qq Ar command ; Same as above. .It Ic match Qo Ar variable Qc Qq Ar value ; Matches the content of .Ar value against .Ar variable ; the content of .Ar value may be a regular expression. For a partial list of variables, see below. .El .Pp The following sub-statements are supported within the .Ic notify statement. The .Dq Li notify variable is available inside this statement and contains, a value, depending on which system and subsystem that delivered the event. .Bl -tag -width ".Ic directory" .It Ic action Qq Ar command ; Command to execute upon a successful match. Example .Dq Li "/etc/rc.d/power_profile $notify" . .It Ic match Qo Ar system | subsystem | type | notify Qc Qq Ar value ; Any number of .Ic match statements can exist within a .Ic notify statement; .Ar value can be either a fixed string or a regular expression. Below is a list of available systems, subsystems, and types. .It Ic media-type Qq Ar string ; See above. .El .Ss Variables that can be used with the match statement A partial list of variables and their possible values that can be used together with the .Ic match statement. The variables are published by the bus based on characteristics of the device that generated the event (for device events). Variables for other classes of events are dependent on those events. .Pp .Bl -tag -width ".Li manufacturer" -compact .It Ic Variable .Ic Description .It Li * The entire message from the current event. .It Li _ The entire message from the current event, after the initial type character. .It Li timestamp The time this event was processed, in seconds since 1970 dot fraction. .It Li bus Device name of parent bus. .It Li cdev Device node path if one is created by the .Xr devfs 5 filesystem. .It Li cisproduct CIS-product. .It Li cisvendor CIS-vendor. .It Li class Device class. .It Li comm Executable name (kernel). .It Li core Path to core file (kernel). .It Li device Device ID. .It Li devclass Device Class (USB). .It Li devsubclass Device Sub-class (USB). .It Li device-name Name of attached/detached device. .It Li endpoints Endpoint count (USB). .It Li function Card functions. .It Li interface Interface ID (USB). .It Li intclass Interface Class (USB). .It Li intprotocol Interface Protocol (USB). .It Li intsubclass Interface Sub-class (USB). .It Li jail Jail name for the process triggering the rule (RCTL). .It Li manufacturer Manufacturer ID (pccard). .It Li mode Peripheral mode (USB). .It Li notify Match the value of the .Dq Li notify variable. .It Li parent Parent device. .It Li pid PID of the process triggering the rule (RCTL). .It Li port Hub port number (USB). .It Li product Product ID (pccard/USB). .It Li release Hardware revision (USB). .It Li ruid Real UID of the process triggering the rule (RCTL). .It Li rule Rule (RCTL). .It Li sernum Serial Number (USB). .It Li slot Card slot. .It Li subvendor Sub-vendor ID. .It Li subdevice Sub-device ID. .It Li subsystem Matches a subsystem of a system, see below. .It Li system Matches a system type, see below. .It Li type Type of notification, see below. .It Li vendor Vendor ID. .El .Ss Notify matching A partial list of systems, subsystems, and types used within the .Ic notify mechanism. .Pp .Bl -tag -width ".Li coretemp" -compact .It Sy System .It Li ACPI Events related to the ACPI subsystem. .Bl -tag -width ".Sy Subsystem" -compact .It Sy Subsystem .It Li ACAD AC line state ($notify=0x00 is offline, 0x01 is online). .It Li Button Button state ($notify=0x00 is power, 0x01 is sleep). .It Li CMBAT Battery events. .It Li Dock Dock state ($notify=0x00 is undocked, 0x01 is docked). .It Li Lid Lid state ($notify=0x00 is closed, 0x01 is open). .It Li PROCESSOR Processor state/configuration ($notify=0x81 is a change in available Cx states). .It Li Resume Resume notification. .It Li Suspend Suspend notification. .It Li Thermal Thermal zone events. .El .Pp .It Li CARP Events related to the .Xr carp 4 protocol. .Bl -tag -width ".Sy Subsystem" -compact .It Sy Subsystem .It Ar vhid@interface The .Dq subsystem contains the actual CARP vhid and the name of the network interface on which the event took place. .Bl -tag -width ".Li MASTER" -compact .It Sy Type .It Li MASTER Node become the master for a virtual host. .It Li BACKUP Node become the backup for a virtual host. .El .El .Pp .It Li IFNET Events related to the network subsystem. .Bl -tag -width ".Sy Subsystem" -compact .It Sy Subsystem .It Ar interface The .Dq subsystem is the actual name of the network interface on which the event took place. .Bl -tag -width ".Li LINK_DOWN" -compact .It Sy Type .It Li LINK_UP Carrier status changed to UP. .It Li LINK_DOWN Carrier status changed to DOWN. .It Li ATTACH The network interface is attached to the system. .It Li DETACH The network interface is detached from the system. .El .El .Pp .It Li DEVFS Events related to the .Xr devfs 5 filesystem. .Bl -tag -width ".Sy Subsystem" -compact .It Sy Subsystem .It Li CDEV .Bl -tag -width ".Li DESTROY" -compact .It Sy Type .It Li CREATE The .Xr devfs 5 node is created. .It Li DESTROY The .Xr devfs 5 node is destroyed. .El .El .Pp .It Li GEOM Events related to the .Xr geom 4 framework. The difference compared to .Li DEVFS is that .Li GEOM only includes disk-like devices. .Bl -tag -width ".Sy Subsystem" -compact .It Sy Subsystem .It Li DEV .Bl -tag -width ".Li MEDIACHANGE" -compact .It Sy Type .It Li CREATE A .Xr geom 4 provider is created. .It Li DESTROY A .Xr geom 4 provider is destroyed. .It Li GEOM::physpath The physical path of a device has changed. .It Li MEDIACHANGE Physical media has changed. .It Li SIZECHANGE A .Xr geom 4 provider size has changed. .El .El .Pp .It Li RCTL Events related to the .Xr rctl 8 framework. .Bl -tag -width ".Sy Subsystem" -compact .It Sy Subsystem .It Li rule .Bl -tag -width ".Li matched" -compact .It Sy Type .It Li matched A rule with action specified as "devctl" was triggered. .El .El .Pp .It Li USB Events related to the USB subsystem. .Bl -tag -width ".Sy Subsystem" -compact .It Sy Subsystem .It Li DEVICE .Bl -tag -width ".Li DETACH" -compact .It Sy Type .It Li ATTACH USB device is attached to the system. .It Li DETACH USB device is detached from the system. .El .It Li INTERFACE .Bl -tag -width ".Li DETACH" -compact .It Sy Type .It Li ATTACH USB interface is attached to a device. .It Li DETACH USB interface is detached from a device. .El .El .Pp .It Li coretemp Events related to the .Xr coretemp 4 device. .Bl -tag -width ".Sy Subsystem" -compact .It Sy Subsystem .It Li Thermal Notification that the CPU core has reached critical temperature. .Bl -tag -width ".Ar temperature" -compact .It Sy Type .It Ar temperature String containing the temperature of the core that has become too hot. .El .El .Pp .It Li kern Events related to the kernel. .Bl -tag -width ".Sy Subsystem" -compact .It Sy Subsystem .It Li power .Bl -tag -width ".li resume" -compact .It Sy Type .It Li resume Notification that the system has woken from the suspended state. .El .El .Pp .It Li kernel More events related to the kernel. .Bl -tag -width ".Sy Subsystem" -compact .It Sy Subsystem .It Li signal .Bl -tag -width ".li resume" -compact .It Sy Type .It Li coredump Notification that a process has crashed and dumped core. .El .El .Pp .It Li CAM Events related to the .Xr cam 4 system. .Bl -tag -width ".Sy Subsystem" -compact .It Sy Subsystem .It Li periph Events related to peripheral devices. .Bl -tag -width ".li timeout" -compact .It Sy Type .It Li error Generic errors. .It Li timeout Command timeouts. .El .El .El .Pp A link state change to UP on the interface .Dq Li fxp0 would result in the following notify event: .Bd -literal -offset indent system=IFNET, subsystem=fxp0, type=LINK_UP .Ed .Pp An AC line state change to .Dq offline would result in the following event: .Bd -literal -offset indent system=ACPI, subsystem=ACAD, notify=0x00 .Ed .Ss Comments Comments may appear anywhere that whitespace may appear in a configuration file. To appeal to programmers of all kinds, they can be written in C, C++, or shell/Perl constructs. .Pp C-style comments start with the two characters .Ql /* (slash, star) and end with .Ql */ (star, slash). Because they are completely delimited with these characters, they can be used to comment only a portion of a line or to span multiple lines. .Pp C-style comments cannot be nested. For example, the following is not valid because the entire comment ends with the first .Ql */ : .Bd -literal -offset indent /* This is the start of a comment. This is still part of the comment. /* This is an incorrect attempt at nesting a comment. */ This is no longer in any comment. */ .Ed .Pp C++-style comments start with the two characters .Ql // (slash, slash) and continue to the end of the physical line. They cannot be continued across multiple physical lines; to have one logical comment span multiple lines, each line must use the .Ql // pair. For example: .Bd -literal -offset indent // This is the start of a comment. The next line // is a new comment, even though it is logically // part of the previous comment. .Ed .Sh FILES .Bl -tag -width ".Pa /etc/devd.conf" -compact .It Pa /etc/devd.conf The .Xr devd 8 configuration file. .El .Sh EXAMPLES .Bd -literal # # This will catch link down events on the interfaces fxp0 and ath0 # notify 0 { match "system" "IFNET"; match "subsystem" "(fxp0|ath0)"; match "type" "LINK_DOWN"; action "logger $subsystem is DOWN"; }; # # Match lid open/close events # These can be combined to a single event, by passing the # value of $notify to the external script. # notify 0 { match "system" "ACPI"; match "subsystem" "Lid"; match "notify" "0x00"; action "logger Lid closed, we can sleep now!"; }; notify 0 { match "system" "ACPI"; match "subsystem" "Lid"; match "notify" "0x01"; action "logger Lid opened, the sleeper must awaken!"; }; # # Match a USB device type # notify 0 { match "system" "USB"; match "subsystem" "INTERFACE"; match "type" "ATTACH"; match "intclass" "0x0e"; action "logger USB video device attached"; }; # # Try to configure ath and wi devices with pccard_ether # as they are attached. # attach 0 { device-name "(ath|wi)[0-9]+"; action "/etc/pccard_ether $device-name start"; }; # # Stop ath and wi devices as they are detached from # the system. # detach 0 { device-name "(ath|wi)[0-9]+"; action "/etc/pccard_ether $device-name stop"; }; .Ed .Pp The installed .Pa /etc/devd.conf has many additional examples. .Sh SEE ALSO .Xr cam 4 , .Xr coretemp 4 , .Xr devfs 5 , .Xr re_format 7 , .Xr devd 8 Index: head/sbin/devd/devd.h =================================================================== --- head/sbin/devd/devd.h (revision 355393) +++ head/sbin/devd/devd.h (revision 355394) @@ -1,61 +1,60 @@ /*- * DEVD (Device action daemon) * * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2002 M. Warner Losh . - * All rights reserved. + * Copyright (c) 2002 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef DEVD_H #define DEVD_H /** @warning This file needs to be purely 'C' compatible. */ struct event_proc; struct eps; __BEGIN_DECLS void add_attach(int, struct event_proc *); void add_detach(int, struct event_proc *); void add_directory(const char *); void add_nomatch(int, struct event_proc *); void add_notify(int, struct event_proc *); struct event_proc *add_to_event_proc(struct event_proc *, struct eps *); struct eps *new_match(const char *, const char *); struct eps *new_media(const char *, const char *); struct eps *new_action(const char *); void set_pidfile(const char *); void set_variable(const char *, const char *); void yyerror(const char *s); int yylex(void); int yyparse(void); extern int lineno; __END_DECLS #define PATH_DEVCTL "/dev/devctl" #define DEVCTL_MAXBUF 8192 #endif /* DEVD_H */ Index: head/sbin/devd/devd.hh =================================================================== --- head/sbin/devd/devd.hh (revision 355393) +++ head/sbin/devd/devd.hh (revision 355394) @@ -1,189 +1,188 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2002-2003 M. Warner Losh. - * All rights reserved. + * Copyright (c) 2002-2003 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef DEVD_HH #define DEVD_HH class config; /** * var_list is a collection of variables. These collections of variables * are stacked up and popped down for each event that we have to process. * We have multiple levels so that we can push variables that are unique * to the event in question, in addition to having global variables. This * allows for future flexibility. */ class var_list { public: /** Set a variable in this var list. */ void set_variable(const std::string &var, const std::string &val); /** Get the variable out of this, and no other, var_list. If * no variable of %var is set, then %bogus will be returned. */ const std::string &get_variable(const std::string &var) const; /** Is there a variable of %var set in this table? */ bool is_set(const std::string &var) const; /** A completely bogus string. */ static const std::string bogus; static const std::string nothing; private: std::string fix_value(const std::string &val) const; std::map _vars; }; /** * eps is short for event_proc_single. It is a single entry in an * event_proc. Each keyword needs its own subclass from eps. */ struct eps { public: virtual ~eps() {} /** Does this eps match the current config? */ virtual bool do_match(config &) = 0; /** Perform some action for this eps. */ virtual bool do_action(config &) = 0; }; /** * match is the subclass used to match an individual variable. Its * actions are nops. */ class match : public eps { public: match(config &, const char *var, const char *re); virtual ~match(); virtual bool do_match(config &); virtual bool do_action(config &) { return true; } private: bool _inv; std::string _var; std::string _re; regex_t _regex; }; /** * media is the subclass used to match an individual variable. Its * actions are nops. */ class media : public eps { public: media(config &, const char *var, const char *type); virtual ~media(); virtual bool do_match(config &); virtual bool do_action(config &) { return true; } private: std::string _var; int _type; }; /** * action is used to fork a process. It matches everything. */ class action : public eps { public: action(const char *cmd); virtual ~action(); virtual bool do_match(config &) { return true; } virtual bool do_action(config &); private: std::string _cmd; }; struct event_proc { public: event_proc(); virtual ~event_proc(); int get_priority() const { return (_prio); } void set_priority(int prio) { _prio = prio; } void add(eps *); bool matches(config &) const; bool run(config &) const; private: int _prio; std::vector _epsvec; }; class config { public: config() { push_var_table(); } virtual ~config() { reset(); } void add_attach(int, event_proc *); void add_detach(int, event_proc *); void add_directory(const char *); void add_nomatch(int, event_proc *); void add_notify(int, event_proc *); void set_pidfile(const char *); void reset(); void parse(); void close_pidfile(); void open_pidfile(); void write_pidfile(); void remove_pidfile(); void push_var_table(); void pop_var_table(); void set_variable(const char *var, const char *val); const std::string &get_variable(const std::string &var); const std::string expand_string(const char * var, const char * prepend = NULL, const char * append = NULL); char *set_vars(char *); void find_and_execute(char); protected: void sort_vector(std::vector &); void parse_one_file(const char *fn); void parse_files_in_dir(const char *dirname); void expand_one(const char *&src, std::string &dst, bool is_shell); std::string shell_quote(const std::string &s); bool is_id_char(char) const; bool chop_var(char *&buffer, char *&lhs, char *&rhs) const; private: std::vector _dir_list; std::string _pidfile; std::vector _var_list_table; std::vector _attach_list; std::vector _detach_list; std::vector _nomatch_list; std::vector _notify_list; }; #endif /* DEVD_HH */ Index: head/sbin/devd/parse.y =================================================================== --- head/sbin/devd/parse.y (revision 355393) +++ head/sbin/devd/parse.y (revision 355394) @@ -1,155 +1,154 @@ %{ /*- * DEVD (Device action daemon) * * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2002 M. Warner Losh . - * All rights reserved. + * Copyright (c) 2002 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include #include "devd.h" #include #include %} %union { char *str; int i; struct eps *eps; /* EventProcStatement */ struct event_proc *eventproc; } %token SEMICOLON BEGINBLOCK ENDBLOCK COMMA %token NUMBER %token STRING %token ID %token OPTIONS SET DIRECTORY PID_FILE DEVICE_NAME ACTION MATCH %token ATTACH DETACH NOMATCH NOTIFY MEDIA_TYPE CLASS SUBDEVICE %type match_or_action_list %type match_or_action match action %% config_file : config_list | ; config_list : config | config_list config ; config : option_block | attach_block | detach_block | nomatch_block | notify_block ; option_block : OPTIONS BEGINBLOCK options ENDBLOCK SEMICOLON ; options : option | options option option : directory_option | pid_file_option | set_option ; directory_option : DIRECTORY STRING SEMICOLON { add_directory($2); } ; pid_file_option : PID_FILE STRING SEMICOLON { set_pidfile($2); } ; set_option : SET ID STRING SEMICOLON { set_variable($2, $3); } ; attach_block : ATTACH NUMBER BEGINBLOCK match_or_action_list ENDBLOCK SEMICOLON { add_attach($2, $4); } | ATTACH NUMBER BEGINBLOCK ENDBLOCK SEMICOLON ; detach_block : DETACH NUMBER BEGINBLOCK match_or_action_list ENDBLOCK SEMICOLON { add_detach($2, $4); } | DETACH NUMBER BEGINBLOCK ENDBLOCK SEMICOLON ; nomatch_block : NOMATCH NUMBER BEGINBLOCK match_or_action_list ENDBLOCK SEMICOLON { add_nomatch($2, $4); } | NOMATCH NUMBER BEGINBLOCK ENDBLOCK SEMICOLON ; notify_block : NOTIFY NUMBER BEGINBLOCK match_or_action_list ENDBLOCK SEMICOLON { add_notify($2, $4); } | NOTIFY NUMBER BEGINBLOCK ENDBLOCK SEMICOLON ; match_or_action_list : match_or_action { $$ = add_to_event_proc( NULL, $1); } | match_or_action_list match_or_action { $$ = add_to_event_proc($1, $2); } ; match_or_action : match | action ; match : MATCH STRING STRING SEMICOLON { $$ = new_match($2, $3); } | DEVICE_NAME STRING SEMICOLON { $$ = new_match(strdup("device-name"), $2); } | MEDIA_TYPE STRING SEMICOLON { $$ = new_media(strdup("media-type"), $2); } | CLASS STRING SEMICOLON { $$ = new_match(strdup("class"), $2); } | SUBDEVICE STRING SEMICOLON { $$ = new_match(strdup("subdevice"), $2); } ; action : ACTION STRING SEMICOLON { $$ = new_action($2); } ; %% Index: head/sbin/devd/token.l =================================================================== --- head/sbin/devd/token.l (revision 355393) +++ head/sbin/devd/token.l (revision 355394) @@ -1,115 +1,114 @@ %{ /*- * DEVD (Device action daemon) * * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2002 M. Warner Losh . - * All rights reserved. + * Copyright (c) 2002 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include #include #include #include #include "devd.h" #include "y.tab.h" int lineno = 1; static void update_lineno(const char *cp) { while (*cp) if (*cp++ == '\n') lineno++; } %} %option noyywrap %option nounput %option noinput %% [ \t]+ ; \n lineno++; ; { return SEMICOLON; } #.*$ ; \/\/.*$ ; \/\*([^*]|(\*+([^*\/])))*\*+\/ { update_lineno(yytext); } \{ { return BEGINBLOCK; } \} { return ENDBLOCK; } [0-9]+ { yylval.i = atoi(yytext); return NUMBER; } \"[^"]+\" { int len = strlen(yytext) - 2; char *walker; int i; update_lineno(yytext); if ((yylval.str = (char *) malloc(len + 1)) == NULL) goto out; walker = yylval.str; for (i = 1; i <= len; i++) { if (yytext[i] == '\\' && yytext[i + 1] == '\n') { i += 2; while(isspace(yytext[i])) i++; } *walker++ = yytext[i]; } *walker++ = '\0'; out:; return STRING; } options { return OPTIONS; } set { return SET; } directory { return DIRECTORY; } pid-file { return PID_FILE; } attach { return ATTACH; } detach { return DETACH; } device-name { return DEVICE_NAME; } media-type { return MEDIA_TYPE; } class { return CLASS; } subdevice { return SUBDEVICE; } action { return ACTION; } match { return MATCH; } nomatch { return NOMATCH; } notify { return NOTIFY; } [A-Za-z][A-Za-z0-9_-]* { yylval.str = strdup(yytext); return ID; } %% void yyerror(const char *s) { syslog(LOG_ERR, "line %d: %s%s %s.\n", lineno, yytext, yytext?":":"", s); } Index: head/share/man/man4/cardbus.4 =================================================================== --- head/share/man/man4/cardbus.4 (revision 355393) +++ head/share/man/man4/cardbus.4 (revision 355394) @@ -1,59 +1,58 @@ .\" -.\" Copyright (c) 2002 M. Warner Losh -.\" All rights reserved. +.\" Copyright (c) 2002 M. Warner Losh .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. The name of the author may not be used to endorse or promote products .\" derived from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" $FreeBSD$ .\" .Dd July 9, 2002 .Dt CARDBUS 4 .Os .Sh NAME .Nm cardbus .Nd CardBus bus driver .Sh SYNOPSIS .Cd device cardbus .Sh DESCRIPTION The .Nm driver implements the CardBus bus. The .Nm driver supports all cardbus bridges in the system. .Sh TUNABLES The driver supports the following tunable parameters, which may be added to .Pa /boot/loader.conf or set via the .Xr sysctl 8 command: .Bl -tag -width ".Cm hw.cardbus.cis_debug" -compact .It Cm hw.cardbus.debug Non-zero values cause more verbose information to be printed when a 32-bit CardBus card is inserted or removed. .It Cm hw.cardbus.cis_debug Non-zero value causes the CIS parsing of the 32-bit CardBus card to be much more verbose and include a complete CIS dump. .El .Sh SEE ALSO .Xr pccard 4 , .Xr pccbb 4 Index: head/share/man/man4/devctl.4 =================================================================== --- head/share/man/man4/devctl.4 (revision 355393) +++ head/share/man/man4/devctl.4 (revision 355394) @@ -1,129 +1,128 @@ .\" -.\" Copyright (c) 2002 M. Warner Losh -.\" All rights reserved. +.\" Copyright (c) 2002 M. Warner Losh .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. The name of the author may not be used to endorse or promote products .\" derived from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" $FreeBSD$ .\" .Dd March 26, 2014 .Dt DEVCTL 4 .Os .Sh NAME .Nm devctl .Nd "device event reporting and device control interface" .Sh DESCRIPTION The .Nm device is used to report device events from the kernel. Future versions will allow for some device control as well. .Sh IMPLEMENTATION NOTES This design allows only one reader for .Pa /dev/devctl . This is not desirable in the long run, but will get a lot of hair out of this implementation. Maybe we should make this device a clonable device. .Pp Also note: we specifically do not attach a device to the .Vt device_t tree to avoid potential chicken and egg problems. One could argue that all of this belongs to the root node. One could also further argue that the .Xr sysctl 3 interface that we have now might more properly be an .Xr ioctl 2 interface. .Pp .Dv SIGIO support is included in the driver. However, the author is not sure that the .Dv SIGIO support is done correctly. It was copied from a driver that had .Dv SIGIO support that likely has not been tested since .Fx 3.4 or .Fx 2.2.8 ! .Pp The read channel for this device is used to report changes to userland in realtime. We return one record at a time. If you try to read this device a character at a time, you will lose the rest of the data. Listening programs are expected to cope. .Pp The sysctl .Va hw.bus.devctl_queue can be used to control queue length. It is set to 0 to disable .Nm when no .Xr devd 8 is running. .Sh PROTOCOL The .Nm device uses an .Tn ASCII protocol. The driver returns one record at a time to its readers. Each record is terminated with a newline. The first character of the record is the event type. .Pp .Bl -column -compact "Type" "Description" .Em "Type Description" ! A notify event, such as a link state change. + Device node in tree attached. - Device node in tree detached. ? Unknown device detected. .El .Ss Message Formats Except for the first character in the record, attach and detach messages have the same format. .Pp .D1 Ar T Ns Ar dev Li at Ar parent Li on Ar location .Pp .Bl -column -compact "location" "Description" .Em "Part Description" .It Ar T Ta "+ or -" .It Ar dev Ta "The device name that was attached/detached." .It Ar parent Ta "The device name of the parent bus that attached the device." .It Ar location Ta "Bus specific location information." .El .Pp The nomatch messages can be used to load devices driver. If you load a device driver, then one of two things can happen. If the device driver attaches to something, you will get a device attached message. If it does not, then nothing will happen. .Pp The attach and detach messages arrive after the event. This means one cannot use the attach message to load an alternate driver. The attach message driver has already claimed this device. One cannot use the detach messages to flush data to the device. The device is already gone. .Sh SEE ALSO .Xr devd 8 Index: head/share/man/man4/exca.4 =================================================================== --- head/share/man/man4/exca.4 (revision 355393) +++ head/share/man/man4/exca.4 (revision 355394) @@ -1,40 +1,39 @@ .\" -.\" Copyright (c) 2003 M. Warner Losh -.\" All rights reserved. +.\" Copyright (c) 2003 M. Warner Losh .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. The name of the author may not be used to endorse or promote products .\" derived from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" $FreeBSD$ .\" .Dd February 23, 2003 .Dt EXCA 4 .Os .Sh NAME .Nm exca .Nd helper module for PC Card and CardBus systems .Sh DESCRIPTION The .Nm module is used to implement the Intel ExCA interface to PC Cards. .Sh SEE ALSO .Xr pccbb 4 , .Xr pcic 4 Index: head/share/man/man4/iic.4 =================================================================== --- head/share/man/man4/iic.4 (revision 355393) +++ head/share/man/man4/iic.4 (revision 355394) @@ -1,260 +1,259 @@ -.\" Copyright (c) 2006, M. Warner Losh -.\" Copyright (c) 1998, Nicolas Souchu -.\" All rights reserved. +.\" Copyright (c) 1998, Nicolas Souchu All rights reserved. +.\" Copyright (c) 2006 M. Warner Losh .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" $FreeBSD$ .\" .Dd May 15, 2015 .Dt IIC 4 .Os .Sh NAME .Nm iic .Nd I2C generic I/O device driver .Sh SYNOPSIS .Cd "device iic" .Pp .In dev/iicbus/iic.h .Sh DESCRIPTION The .Nm device driver provides generic I/O to any .Xr iicbus 4 instance. In order to control I2C devices, use .Pa /dev/iic? with the following ioctls: .Bl -tag -width ".Dv I2CRPTSTART" .It Dv I2CSTART .Pq Vt "struct iiccmd" Sends the start condition to the slave specified by the .Va slave element to the bus. The .Va slave element consists of a 7-bit address and a read/write bit (that is, a 7-bit address << 1 | r/w). A read operation is initiated when the read/write bit is set, or a write operation when it is cleared. All other elements are ignored. If successful, the file descriptor receives exclusive ownership of the underlying iicbus instance. .It Dv I2CRPTSTART .Pq Vt "struct iiccmd" Sends the repeated start condition to the slave specified by the .Va slave element to the bus. The slave address should be specified as in .Dv I2CSTART . All other elements are ignored. .Dv I2CSTART must have previously been issued on the same file descriptor. .It Dv I2CSTOP No argument is passed. Sends the stop condition to the bus. If .Dv I2CSTART was previously issued on the file descriptor, the current transaction is terminated and exclusive ownership of the underlying iicbus instance is released. Otherwise, no action is performed. .It Dv I2CRSTCARD .Pq Vt "struct iiccmd" Resets the bus. The argument is completely ignored. This command does not require .Dv I2CSTART to have been previously issued on the file descriptor. If it was previously issued, exclusive ownership of the underlying iicbus instance is released. .It Dv I2CWRITE .Pq Vt "struct iiccmd" Writes data to the .Xr iicbus 4 . The bus must already be started by a previous .Dv I2CSTART on the file descriptor. The .Va slave element is ignored. The .Va count element is the number of bytes to write. The .Va last element is a boolean flag. It must be zero when additional read commands will follow, or non-zero if this is the last command. The .Va buf element is a pointer to the data to write to the bus. .It Dv I2CREAD .Pq Vt "struct iiccmd" Reads data from the .Xr iicbus 4 . The bus must already be started by a previous .Dv I2CSTART on the file descriptor. The .Va slave element is ignored. The .Va count element is the number of bytes to read. The .Va last element is a boolean flag. It must be zero when additional read commands will follow, or non-zero if this is the last command. The .Va buf element is a pointer to where to store the data read from the bus. Short reads on the bus produce undefined results. .It Dv I2CRDWR .Pq Vt "struct iic_rdwr_data" Generic read/write interface. Allows for an arbitrary number of commands to be sent to an arbitrary number of devices on the bus. Any previous transaction started by .Dv I2CSTART must be terminated by .Dv I2CSTOP or .Dv I2CRSTCARD before .Dv I2CRDWR can be issued on the same file descriptor. A read transfer is specified if .Dv IIC_M_RD is set in .Va flags . Otherwise the transfer is a write transfer. The .Va slave element specifies the 7-bit address with the read/write bit for the transfer. The read/write bit will be handled by the iicbus stack based on the specified transfer operation. The .Va len element is the number of .Pq Vt "struct iic_msg" messages encoded on .Pq Vt "struct iic_rdwr_data" . The .Va buf element is a buffer for that data. This ioctl is intended to be .Tn Linux compatible. .It Dv I2CSADDR .Pq Vt "uint8_t" Associate the specified address with the file descriptor for use by subsequent .Xr read 2 or .Xr write 2 calls. The argument is an 8-bit address (that is, a 7-bit address << 1). The read/write bit in the least-significant position is ignored. Any subsequent read or write operation will set or clear that bit as needed. .El .Pp The following data structures are defined in .In dev/iicbus/iic.h and referenced above: .Bd -literal -offset indent struct iiccmd { u_char slave; int count; int last; char *buf; }; /* Designed to be compatible with linux's struct i2c_msg */ struct iic_msg { uint16_t slave; uint16_t flags; #define IIC_M_WR 0 /* Fake flag for write */ #define IIC_M_RD 0x0001 /* read vs write */ #define IIC_M_NOSTOP 0x0002 /* do not send a I2C stop after message */ #define IIC_M_NOSTART 0x0004 /* do not send a I2C start before message */ uint16_t len; /* msg length */ uint8_t * buf; }; struct iic_rdwr_data { struct iic_msg *msgs; uint32_t nmsgs; }; .Ed .Pp It is also possible to use .Xr read 2 or .Xr write 2 , in which case the I2C start/stop handshake is managed by .Xr iicbus 4 . The address used for the read/write operation is the one passed to the most recent .Dv I2CSTART .Xr ioctl 2 or .Dv I2CSADDR .Xr ioctl 2 on the open .Pa /dev/iic? file descriptor. Closing the file descriptor clears any addressing state established by a previous .Dv I2CSTART or .Dv I2CSADDR , stops any transaction established by a not-yet-terminated .Dv I2CSTART , and releases iicbus ownership. Because addressing state is stored on a per-file-descriptor basis, it is permissible for multiple file descriptors to be simultaneously open on the same .Pa /dev/iic? device. Concurrent transactions on those descriptors are synchronized by the exclusive-ownership requests issued to the underlying iicbus instance. .Sh SEE ALSO .Xr ioctl 2 , .Xr read 2 , .Xr write 2 , .Xr iicbus 4 .Sh HISTORY The .Nm manual page first appeared in .Fx 3.0 . .Sh AUTHORS .An -nosplit This manual page was written by .An Nicolas Souchu and .An M. Warner Losh . Index: head/share/man/man4/mmc.4 =================================================================== --- head/share/man/man4/mmc.4 (revision 355393) +++ head/share/man/man4/mmc.4 (revision 355394) @@ -1,60 +1,59 @@ .\" -.\" Copyright (c) 2007 M. Warner Losh -.\" All rights reserved. +.\" Copyright (c) 2007 M. Warner Losh .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. The name of the author may not be used to endorse or promote products .\" derived from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" $FreeBSD$ .\" .Dd October 8, 2008 .Dt MMC 4 .Os .Sh NAME .Nm mmc .Nd MultiMediaCard and SD Card bus driver .Sh SYNOPSIS .Cd device mmc .Sh DESCRIPTION The .Nm driver implements the MMC and SD Card bus. The .Nm driver supports all MMC and SD bridges in the system. All SD or MMC cards in the system attach to an instance of .Nm . The .Nm bus typically has only one slot, and only memory cards. MultiMediaCards exist only in memory. SD Cards exist as memory, I/O, or combination cards. .Sh SEE ALSO .Xr at91_mci 4 , .Xr mmcsd 4 , .Xr sdhci 4 .Rs .%T "SD Specifications, Part 1, Physical Layer, Simplified Specification" .Re .Rs .%T "The MultiMediaCard System Specification" .Re .Sh BUGS SDIO cards currently do not work. Index: head/share/man/man4/mmcsd.4 =================================================================== --- head/share/man/man4/mmcsd.4 (revision 355393) +++ head/share/man/man4/mmcsd.4 (revision 355394) @@ -1,48 +1,47 @@ .\" -.\" Copyright (c) 2007 M. Warner Losh -.\" All rights reserved. +.\" Copyright (c) 2007 M. Warner Losh .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. The name of the author may not be used to endorse or promote products .\" derived from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" $FreeBSD$ .\" .Dd October 22, 2008 .Dt MMCSD 4 .Os .Sh NAME .Nm mmcsd .Nd MMC and SD memory card driver .Sh SYNOPSIS .Cd device mmcsd .Sh DESCRIPTION The .Nm driver implements direct access block device for MMC and SD memory cards. .Sh SEE ALSO .Xr at91_mci 4 , .Xr mmc 4 , .Xr sdhci 4 .Rs .%T "SD Specifications, Part 1, Physical Layer, Simplified Specification" .Re .Rs .%T "The MultiMediaCard System Specification" .Re Index: head/share/man/man4/ow.4 =================================================================== --- head/share/man/man4/ow.4 (revision 355393) +++ head/share/man/man4/ow.4 (revision 355394) @@ -1,60 +1,59 @@ .\" -.\" Copyright (c) 2015 M. Warner Losh -.\" All rights reserved. +.\" Copyright (c) 2015 M. Warner Losh .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. The name of the author may not be used to endorse or promote products .\" derived from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" $FreeBSD$ .\" .Dd July 20, 2015 .Dt OW 4 .Os .Sh NAME .Nm ow .Nd Dallas Semiconductor 1-Wire bus .Sh SYNOPSIS .Cd device ow .Sh DESCRIPTION The .Nm module implements the Dallas Semiconductor 1-Wire bus. It attaches to the .Xr owc 4 driver, which implements the low-level signaling of the 1-Wire bus. .Sh SEE ALSO .Xr ow_temp 4 , .Xr owc 4 , .Xr owll 9 , .Xr own 9 .Sh LEGAL .Tn 1-Wire is a registered trademark of Maxim Integrated Products, Inc. .Sh HISTORY The .Nm driver first appeared in .Fx 11.0 . .Sh AUTHORS The .Nm device driver and this manual page were written by .An Warner Losh . Index: head/share/man/man4/ow_temp.4 =================================================================== --- head/share/man/man4/ow_temp.4 (revision 355393) +++ head/share/man/man4/ow_temp.4 (revision 355394) @@ -1,155 +1,154 @@ .\" -.\" Copyright (c) 2015 M. Warner Losh -.\" All rights reserved. +.\" Copyright (c) 2015 M. Warner Losh .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. The name of the author may not be used to endorse or promote products .\" derived from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" $FreeBSD$ .\" .Dd July 20, 2015 .Dt OW_TEMP 4 .Os .Sh NAME .Nm ow_temp .Nd Dallas Semiconductor 1-Wire Temperature sensor .Sh SYNOPSIS .Cd device ow_temp .Sh DESCRIPTION The .Nm module supports many of the 1-Wire temperature sensors. .Pp The sensor is read periodically and the results returned via a .Xr sysctl 3 as described below. .Sh HARDWARE These temperature sensors are supported by the .Nm driver: .Bl -tag -width MAX31820 -compact .It DS1820 1-Wire Digital Thermometer .It DS18S20 High-Precision 1-Wire Digital Thermometer .It DS18B20 Programmable Resolution 1-Wire Digital Thermometer .It DS1822 Econo 1-Wire Digital Thermometer .It DS1825 Programmable Resolution 1-Wire Digital Thermometer with 4-bit ID .It MAX31820 1-Wire, Parasite-Power, Ambient Temperature Sensor .El .Pp The driver supports Family codes 0x10, 0x22, 0x28, and 0x3b. .Sh SYSCTL The .Nm driver reports data via .Xr sysctl 8 entries in the device's node in the .Xr sysctl 8 tree: .Bl -tag -width xxxxxxxxxx .It temperature The last temperature read, in milli-Kelvin. .It badcrc The number of CRC errors in reading the temperature form the device. Some CRC errors are to be expected. High rates of CRC errors, however, generally indicate a noisy environment, cabling issues, or too many devices on the bus. .It badread The number of times a non-CRC error was encountered reading the temperature from the card. This type of error is very rare. .It reading_interval The time, in ticks, between successive reads of the sensor. .It parasite This item is non-zero when the device is connected using its parasitic power mode. It can also indicate a wiring error. .El .Pp Temperatures are reported in milli-Kelvin, even though the absolute accuracy is around 0.2 degrees for the good devices and around 1 degree for cheaper devices. The devices report in steps of 0.0625 degrees. The driver preserves the precision of the device's measurements in its .Xr sysctl 8 reports. These devices often have a much higher relative accuracy and repeatability than their absolute accuracy. This makes them well suited for control loops that strive for stability and become possible if the full precision is preserved. .Sh SEE ALSO .Xr ow 4 , .Xr owc 4 , .Xr sysctl 8 , .Xr owll 9 , .Xr own 9 .Sh LEGAL .Tn 1-Wire is a registered trademark of Maxim Integrated Products, Inc. .Sh HISTORY The .Nm driver first appeared in .Fx 11.0 . .Sh AUTHORS The .Nm device driver and this manual page were written by .An Warner Losh . .Sh BUGS The parasitic mode of the devices does not work. It requires support from the .Xr owc 4 driver that is unimplemented. .Pp The ID bits from the .Em DS1825 are not recognized or reported. .Pp The type of the device is not reported via .Xr sysctl 8 . .Pp Alarm mode is not supported. It is not possible to set the low and high alarm temperatures. .Pp There is no way to write to the EEPROM. .Pp .Dq Convert Temperature requests are sent directly to the device. There is no way to use the broadcast ability of the 1-Wire bus to do all the conversions in parallel. .Pp It is not possible to set the precision on those devices that support it. .Pp The time to convert is fixed at 1 second, even though some devices are faster. .Pp There is no character device to supply a stream of readings to a program. Programs interested in the temperature must poll the sysctl to get the temperature. Index: head/share/man/man4/owc.4 =================================================================== --- head/share/man/man4/owc.4 (revision 355393) +++ head/share/man/man4/owc.4 (revision 355394) @@ -1,113 +1,112 @@ .\" -.\" Copyright (c) 2015 M. Warner Losh -.\" All rights reserved. +.\" Copyright (c) 2015 M. Warner Losh .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. The name of the author may not be used to endorse or promote products .\" derived from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" $FreeBSD$ .\" .Dd June 26, 2019 .Dt OWC 4 .Os .Sh NAME .Nm owc .Nd Dallas Semiconductor 1-Wire Controller .Sh SYNOPSIS .Cd device owc .Sh DESCRIPTION The .Nm module implements Dallas Semiconductor 1-Wire signaling. It attaches the .Xr ow 4 driver 1-Wire bus protocol. The .Nm device implements the Link Layer of the 1-Wire bus protocol stack. .Pp Bit banging a pin on a .Xr gpiobus 4 is the only supported controller. Both standard and overdrive transfer timings are implemented. Strong pull-up functionality needed to support parasitic mode is not implemented. .Pp To enable 1-Wire for FDT systems requires modifying the DTS for your board to add something like: .Bd -literal / { ... onewire { compatible = "w1-gpio"; gpios = <&gpio 4 1>; }; ... }; .Ed .Pp The gpios property describes the GPIO pin the 1-Wire bus is connected to. For more details about the .Va gpios property, please consult .Pa /usr/src/sys/dts/bindings-gpio.txt . .Pp On a .Xr device.hints 5 based system these values are required for the .Nm : .Bl -tag -width ".Va hint.owc.%d.atXXX" .It Va hint.owc.%d.at The .Nm gpiobus you are attaching to. .It Va hint.owc.%d.pins This is a bitmask that defines a pin on the .Nm gpiobus that is to be used for the 1-Wire bus. For instance, to configure pin 10, use the bitmask of 0x400. Please note that this mask should have only one bit set (any other bits - i.e., pins - will be ignored). .El .Sh SEE ALSO .Xr gpiobus 4 , .Xr ow 4 , .Xr ow_temp 4 , .Xr owll 9 , .Xr own 9 .Sh LEGAL .Tn 1-Wire is a registered trademark of Maxim Integrated Products, Inc. .Sh HISTORY The .Nm driver first appeared in .Fx 11.0 . .Sh AUTHORS The .Nm device driver and this manual page were written by .An Warner Losh . .Sh CAVEATS The gpio driver implements timing by busy waiting, which can cause a high load on slower systems. .Sh BUGS Overdrive mode has not actually been tested. Index: head/share/man/man4/pccard.4 =================================================================== --- head/share/man/man4/pccard.4 (revision 355393) +++ head/share/man/man4/pccard.4 (revision 355394) @@ -1,78 +1,77 @@ .\" -.\" Copyright (c) 2002 M. Warner Losh -.\" All rights reserved. +.\" Copyright (c) 2002 M. Warner Losh .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. The name of the author may not be used to endorse or promote products .\" derived from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" $FreeBSD$ .\" .Dd July 9, 2002 .Dt PCCARD 4 .Os .Sh NAME .Nm pccard .Nd PC Card bus driver .Sh SYNOPSIS .Cd device pccard .Sh DESCRIPTION The .Nm driver implements the PC Card bus. The .Nm driver supports all PC Card bridges in the system. .Sh TUNABLES The driver supports the following tunable parameters, which may be added to .Pa /boot/loader.conf or set via the .Xr sysctl 8 command: .Bl -tag -width ".Cm hw.pccard.cis_debug" -compact .It Cm hw.pccard.debug Non-zero values cause more verbose information to be printed when a 16-bit PC Card is inserted or removed. .It Cm hw.pccard.cis_debug Non-zero value causes the CIS parsing of the 16-bit PC Card to be much more verbose and include a complete CIS dump. .El .Sh FILES .Bl -tag -width ".Pa /dev/pccard0.cis" -compact .It Pa /dev/pccard0.cis This exclusive-use device will report all the CIS chains present in a PC Card, if a 16-bit PC Card is inserted in the slot. Only one user at a time may access the CIS. The CIS is presented as the relevant byte stream from the PC Card. For CIS tuples in Attribute Memory (the default), only the even locations are presented (the ODD locations are undefined per the standard). For CIS tuples in Common Memory, every byte is presented to the user. Decoding of the CIS tuples is done via a userland program. All tuples are presented to the user. .El .Sh SEE ALSO .Xr cardbus 4 , .\" .Xr mecia 4 , .Xr pccbb 4 .\" .Xr tcic 4 .Rs .%T "PC Card Standard, Release 8" .Re Index: head/share/man/man4/pccbb.4 =================================================================== --- head/share/man/man4/pccbb.4 (revision 355393) +++ head/share/man/man4/pccbb.4 (revision 355394) @@ -1,183 +1,182 @@ .\" -.\" Copyright (c) 2002-2003 M. Warner Losh -.\" All rights reserved. +.\" Copyright (c) 2002-2003 M. Warner Losh .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. The name of the author may not be used to endorse or promote products .\" derived from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" $FreeBSD$ .\" .Dd July 21, 2004 .Dt PCCBB 4 .Os .Sh NAME .Nm pccbb .Nd cardbus bridge driver .Sh SYNOPSIS .Cd device cbb .Cd device pccard .Cd device cardbus .Cd device exca .Sh DESCRIPTION The .Nm driver implements the Yenta specification for CardBus bridges. .Pp The following PCI cardbus and pcmcia bridges are supported: .Pp .Bl -item -compact .It Cirrus Logic PD6832 .It Cirrus Logic PD6833 .It Cirrus Logic PD6834 .Pp .It O2micro OZ6812 .It O2micro OZ6832 .It O2micro OZ6833 .It O2micro OZ6836 .It O2micro OZ6860 .It O2micro OZ6872 .It O2micro OZ6912 .It O2micro OZ6922 .It O2micro OZ6933 .It O2micro OZ6972 .It O2Micro OZ711E1 .It O2Micro OZ711M1 .El .Bl -item -compact .It Ricoh RL4C475 .It Ricoh RL4C476 .It Ricoh RL4C477 .It Ricoh RL4C478 .Pp .It TI PCI-1031 .It TI PCI-1130 .It TI PCI-1131 .It TI PCI-1210 .It TI PCI-1211 .It TI PCI-1220 .It TI PCI-1221 .It TI PCI-1225 .It TI PCI-1250 .It TI PCI-1251 .It TI PCI-1251B .It TI PCI-1260 .It TI PCI-1260B .It TI PCI-1410 .It TI PCI-1420 .It TI PCI-1450 .It TI PCI-1451 .It TI PCI-1510 .It TI PCI-1515 .It TI PCI-1520 .It TI PCI-1530 .It TI PCI-1620 .It TI PCI-4410 .It TI PCI-4450 .It TI PCI-4451 .It TI PCI-4510 .It TI PCI-4520 .It TI PCI-[67]x[12]1 .It TI PCI-[67]x20 .It ENE CB710 .It ENE CB720 .It ENE CB1211 .It ENE CB1255 .It ENE CB1410 .It ENE CB1420 .Pp .It Toshiba ToPIC95 .It Toshiba ToPIC95B .It Toshiba ToPIC97 .It Toshiba ToPIC100 .El .Sh TUNABLES The driver supports the following tunable parameters, which may be added to .Pa /boot/loader.conf or set via the .Xr sysctl 8 command: .Bl -tag -width ".Cm hw.cbb.debug" -compact .It Cm hw.cbb.debug Non-zero values cause more verbose information to be printed to aid in debugging problems with the bridge chipset. .El .Sh SEE ALSO .Xr cardbus 4 , .Xr exca 4 , .Xr pccard 4 Index: head/share/man/man4/pcib.4 =================================================================== --- head/share/man/man4/pcib.4 (revision 355393) +++ head/share/man/man4/pcib.4 (revision 355394) @@ -1,49 +1,48 @@ .\" -.\" Copyright (c) 2008 M. Warner Losh -.\" All rights reserved. +.\" Copyright (c) 2008 M. Warner Losh .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. The name of the author may not be used to endorse or promote products .\" derived from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" $FreeBSD$ .\" .Dd January 18, 2008 .Dt PCIB 4 .Os .Sh NAME .Nm pcib .Nd PCI bridge driver .Sh SYNOPSIS To compile this driver into the kernel, place the following line in your kernel configuration file: .Bd -ragged -offset indent .Cd "device pci" .Ed .Sh DESCRIPTION The .Nm driver provides for host and .Tn PCI bridges in a .Tn PCI system. .Sh BUGS This man page is too short. Index: head/share/man/man4/pcic.4 =================================================================== --- head/share/man/man4/pcic.4 (revision 355393) +++ head/share/man/man4/pcic.4 (revision 355394) @@ -1,103 +1,102 @@ .\" -.\" Copyright (c) 2001, 2002 M. Warner Losh -.\" All rights reserved. +.\" Copyright (c) 2001-2002 M. Warner Losh .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. The name of the author may not be used to endorse or promote products .\" derived from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" $FreeBSD$ .\" .Dd July 9, 2002 .Dt PCIC 4 .Os .Sh NAME .Nm pcic .Nd PC Card bridge driver .Sh SYNOPSIS .Cd device pcic .Cd device pccard .Sh DESCRIPTION The .Nm driver provides support for older ISA and non-Yenta PCI PC Card bridges. The .Nm driver supports most .Tn ExCA devices attached to the .Tn ISA bus or .Tn PCI devices that do not conform to the Yenta specification. .Pp The following .Tn ISA devices, or true clones, are supported in the current code. .Pp .Bl -tag -width "Intel i82365SL Step A" -compact .It Intel i82365SL Step A .It Intel i82365SL Step B .It Intel i82365SL Step C .Tn Intel Ns 's original 16-bit PC Card controller. .It Intel i82365SL-DF .Tn Intel Ns 's last version of this device. 3.3V support was added. .It VLSI 82C146 An older VLSI part with some issues on some machines. .It Cirrus Logic PD-6710 .It Cirrus Logic PD-6720 .It Cirrus Logic PD-6722 Cirrus Logic's pcic controller. Compatible with the i82365SL Step C with the addition of a different 3.3V control. .It Ricoh RF5C296 .It Ricoh RF5C396 Ricoh's PC Card bridge chips. These are compatible with the i82365SL Step C, but with yet another different 3.3V control. .It Vadem 365 .It Vadem 465 Compatible with i82365SL Step C. .It Vadem 468 .It Vadem 469 Like the earlier Vadem models, but with Vadem's own, incompatible, 3.3V control system. .It IBM PCIC .Tn IBM clone of the original i82365SL part, with its own ID register value. Has no 3.3V ability. .El .Pp Many other vendors made parts in this arena, but most of them were compatible with one of the above chipsets. .Pp The following PCI pcmcia bridges are supported: .Pp .Bl -tag -width "Intel i82365SL Step A" -compact .It Cirrus Logic PD6729 .It Cirrus Logic PD6730 .Pp .It O2micro OZ6729 .It O2micro OZ6730 .El .Sh BUGS This does not work at all at the moment. Index: head/share/man/man4/ufm.4 =================================================================== --- head/share/man/man4/ufm.4 (revision 355393) +++ head/share/man/man4/ufm.4 (revision 355394) @@ -1,85 +1,84 @@ -.\" Copyright (c) 2003 M. Warner Losh -.\" . All rights reserved. +.\" Copyright (c) 2003 M. Warner Losh .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" $FreeBSD$ .\" .Dd November 22, 2006 .Dt UFM 4 .Os .Sh NAME .Nm ufm .Nd USB driver for Cypress Semiconductor FM Radio .Sh SYNOPSIS To compile this driver into the kernel, place the following line in your kernel configuration file: .Bd -ragged -offset indent .Cd "device ufm" .Ed .Pp Alternatively, to load the driver as a module at boot time, place the following line in .Xr loader.conf 5 : .Bd -literal -offset indent ufm_load="YES" .Ed .Sh DESCRIPTION The .Nm driver provides support for the D-Link/GEMTEK FM tuner. The USB interface chip is the common Cypress 63001, and the tuner is a Philips TEA5757 radio chip that uses a serial interface to set the tuner parameters. This design is used in the D-Link DSB-R100 USB Radio. .Pp The .Nm device must be configured in the kernel, along with .Xr usb 4 and one of the .Xr uhci 4 or .Xr ohci 4 controllers. .Pp Subsequently, the .Pa /dev/ufm0 device can be used by userland applications. .Sh FILES .Bl -tag -width ".Pa /dev/ufm0" -compact .It Pa /dev/ufm0 blocking device node .El .Sh SEE ALSO .Xr ohci 4 , .Xr uhci 4 , .Xr usb 4 .Sh AUTHORS .An -nosplit The .Nm driver was written by .An M. Warner Losh Aq Mt imp@FreeBSD.org for .Fx . Index: head/share/man/man5/os-release.5 =================================================================== --- head/share/man/man5/os-release.5 (revision 355393) +++ head/share/man/man5/os-release.5 (revision 355394) @@ -1,130 +1,131 @@ -.\" Copyright (c) 2019 M. Warner Losh. +.\" +.\" Copyright (c) 2019 M. Warner Losh .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" $FreeBSD$ .\" .Dd November 9, 2019 .Dt OS-RELEASE 5 .Os .Sh NAME .Nm os-release .Nd file describing the current OS and some of its attributes .Sh DESCRIPTION The .Nm file is a new-line separated list of key value pairs. The syntax of this file is a reduced .Xr sh 1 variable assignment with the following restrictions: .Bl -bullet .It Strings cannot be concatenated together .It No variable expansion is done .It All shell special characters must be quoted as documented in .Xr sh 1 .It Variable assignments must be included inside of double quotes if they contain characters outside of A-Z, a-z and 0-9 .It All strings should be UTF-8 format .It Non-printable characters should not be used in the strings .El .Pp Lines starting with the character .Ql # are ignored as comments. .Sh VARIABLES The following variables are defined by the standard. .Bl -tag -width XXXXXXXXXX -compact .It Dv NAME A string describing the preferred OS name. .It Dv VERSION Version string for the OS, in its usual and customary format. .It Dv ID Lower case version of the name with only a-z, 0-9, .Ql . , .Ql - , and .Ql _ . .It Dv VERSION_ID Lower case version of the version with only a-z, 0-9, .Ql . , .Ql - , and .Ql _ . .It Dv PRETTY_NAME A pretty version of the name presented to the user. May contain release information. .It Dv ANSI_COLOR Suggested color presentation for the OS. This string should be suitable for inclusion within an ESC [ m ANSI/ECMA-48 escape sequence to render the OS in its preferred color. This variable is optional. .It Dv CPE_NAME A CPE name for the operating system. This field shall follow the NIST Common Platform Enumeration specification. .It Dv HOME_URL .It Dv SUPPORT_URL .It Dv BUG_REPORT_URL .It Dv PRIVACY_POLICY_URL Links on the internet, in RFC 3986 format for different aspects of this OS. These variables are optional. .It Dv BUILD_ID A string identifying the build. This variable is optional. .It Dv VARIANT A string describing the variant of this operating system. This variable is optional. .It Dv VARIANT_ID Lower case version of the variant with only a-z, 0-9, .Ql . , .Ql - , and .Ql _ . This variable is optional. .El .Pp All other variables have no standard-defined meaning. .Sh FILES .Bl -tag -width XXXXXXXXXX -compact .It Pa /etc/os-release Symbolic link to actual .Pa os-release file. .It Pa /var/run/os-release Generated os-release file describing the currently running system. .Sh SEE ALSO .Bl -tag -width XXXXXXXXXX -compact .It CPE Specification .Lk https://csrc.nist.gov/projects/security-content-automation-protocol/scap-specifications/cpe .It RFC 3986 .Lk https://tools.ietf.org/html/rfc3986 .It os-release Specification .Lk https://www.linux.org/docs/man5/os-release.html .Sh HISTORY This file first appeared in .Fx 13.0 . Index: head/stand/common/paths.h =================================================================== --- head/stand/common/paths.h (revision 355393) +++ head/stand/common/paths.h (revision 355394) @@ -1,42 +1,41 @@ /*- - * Copyright (c) 2016 M. Warner Losh - * All rights reserved. + * Copyright (c) 2016 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _PATHS_H_ #define _PATHS_H_ #include /* To get kernel path */ #define PATH_DOTCONFIG "/boot.config" #define PATH_CONFIG "/boot/config" #define PATH_LOADER "/boot/loader" #define PATH_LOADER_EFI "/boot/loader.efi" #define PATH_LOADER_ZFS "/boot/zfsloader" #define PATH_LOADER_CONF "/boot/loader.conf" #define PATH_DEFAULTS_LOADER_CONF "/boot/defaults/loader.conf" #endif /* _PATHS_H_ */ Index: head/stand/common/zfs_cmd.c =================================================================== --- head/stand/common/zfs_cmd.c (revision 355393) +++ head/stand/common/zfs_cmd.c (revision 355394) @@ -1,107 +1,107 @@ /*- - * Copyright (c) 2018 M. Warner Losh + * Copyright (c) 2018 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /* * MD bootstrap main() and assorted miscellaneous * commands. */ #include #include #include #include #include "bootstrap.h" #ifdef LOADER_ZFS_SUPPORT #include "libzfs.h" #endif COMMAND_SET(lszfs, "lszfs", "list child datasets of a zfs dataset", command_lszfs); static int command_lszfs(int argc, char *argv[]) { int err; if (argc != 2) { command_errmsg = "a single dataset must be supplied"; return (CMD_ERROR); } err = zfs_list(argv[1]); if (err != 0) { command_errmsg = strerror(err); return (CMD_ERROR); } return (CMD_OK); } COMMAND_SET(reloadbe, "reloadbe", "refresh the list of ZFS Boot Environments", command_reloadbe); static int command_reloadbe(int argc, char *argv[]) { int err; char *root; if (argc > 2) { command_errmsg = "wrong number of arguments"; return (CMD_ERROR); } if (argc == 2) { err = zfs_bootenv(argv[1]); } else { root = getenv("zfs_be_root"); if (root == NULL) { /* There does not appear to be a ZFS pool here, exit without error */ return (CMD_OK); } err = zfs_bootenv(root); } if (err != 0) { command_errmsg = strerror(err); return (CMD_ERROR); } return (CMD_OK); } uint64_t ldi_get_size(void *priv) { int fd = (uintptr_t) priv; uint64_t size; ioctl(fd, DIOCGMEDIASIZE, &size); return (size); } Index: head/stand/liblua/float.h =================================================================== --- head/stand/liblua/float.h (revision 355393) +++ head/stand/liblua/float.h (revision 355394) @@ -1,31 +1,31 @@ /*- - * Copyright (c) 2018 M. Warner Losh + * Copyright (c) 2018 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ /* * Empty file to keep lua build happy. Lua expects to have to include float.h * but the int64_t number implementation doesn't need it. */ Index: head/stand/liblua/locale.h =================================================================== --- head/stand/liblua/locale.h (revision 355393) +++ head/stand/liblua/locale.h (revision 355394) @@ -1,26 +1,26 @@ /*- - * Copyright (c) 2018 M. Warner Losh + * Copyright (c) 2018 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ Index: head/stand/liblua/math.h =================================================================== --- head/stand/liblua/math.h (revision 355393) +++ head/stand/liblua/math.h (revision 355394) @@ -1,37 +1,37 @@ /*- - * Copyright (c) 2018 M. Warner Losh + * Copyright (c) 2018 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ /* * A replacement for math.h that's sufficient to pretend that we * actually have one to keep the un-modified lua happy. */ #include int64_t lstd_pow(int64_t x, int64_t y); int64_t lstd_floor(int64_t); int64_t lstd_fmod(int64_t a, int64_t b); int64_t lstd_frexp(int64_t a, int *); Index: head/stand/libsa/uuid_from_string.c =================================================================== --- head/stand/libsa/uuid_from_string.c (revision 355393) +++ head/stand/libsa/uuid_from_string.c (revision 355394) @@ -1,132 +1,131 @@ /*- - * Copyright (c) 2015 M. Warner Losh - * All rights reserved. + * Copyright (c) 2015 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ /* * Note: some comments taken from lib/libc/uuid/uuid_from_string.c * Copyright (c) 2002 Marcel Moolenaar * Copyright (c) 2002 Hiten Mahesh Pandya */ #include #include static int hex2int(int ch) { if (ch >= '0' && ch <= '9') return ch - '0'; if (ch >= 'a' && ch <= 'f') return 10 + ch - 'a'; if (ch >= 'A' && ch <= 'F') return 10 + ch - 'A'; return 16; } static uint32_t fromhex(const char *s, int len, int *ok) { uint32_t v; int i, h; if (!*ok) return 0; v = 0; for (i = 0; i < len; i++) { h = hex2int(s[i]); if (h == 16) { *ok = 0; return v; } v = (v << 4) | h; } return v; } /* * uuid_from_string() - convert a string representation of an UUID into * a binary representation. * See also: * http://www.opengroup.org/onlinepubs/009629399/uuid_from_string.htm * * NOTE: The sequence field is in big-endian, while the time fields are in * native byte order. * * 01234567-89ab-cdef-0123-456789abcdef * 000000000011111111112222222222333333 * 012345678901234567890123456789012345 * - - - - * hhhhhhhh-hhhh-hhhh-bbbb-bbbbbbbbbbbb * */ void uuid_from_string(const char *s, uuid_t *u, uint32_t *status) { int ok = 1; int n; if (s == NULL || *s == '\0') { uuid_create_nil(u, status); return; } if (status != NULL) *status = uuid_s_invalid_string_uuid; if (strlen(s) != 36) return; /* Only support new format, check for all the right dashes */ if (s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-') return; /* native byte order */ u->time_low = fromhex(s , 8, &ok); u->time_mid = fromhex(s + 9, 4, &ok); u->time_hi_and_version = fromhex(s + 14, 4, &ok); /* Big endian, but presented as a whole number so decode as such */ u->clock_seq_hi_and_reserved = fromhex(s + 19, 2, &ok); u->clock_seq_low = fromhex(s + 21, 2, &ok); u->node[0] = fromhex(s + 24, 2, &ok); u->node[1] = fromhex(s + 26, 2, &ok); u->node[2] = fromhex(s + 28, 2, &ok); u->node[3] = fromhex(s + 30, 2, &ok); u->node[4] = fromhex(s + 32, 2, &ok); u->node[5] = fromhex(s + 34, 2, &ok); if (!ok) return; /* We have a successful scan. Check semantics... */ n = u->clock_seq_hi_and_reserved; if ((n & 0x80) != 0x00 && /* variant 0? */ (n & 0xc0) != 0x80 && /* variant 1? */ (n & 0xe0) != 0xc0) { /* variant 2? */ if (status != NULL) *status = uuid_s_bad_version; } else { if (status != NULL) *status = uuid_s_ok; } } Index: head/stand/libsa/uuid_to_string.c =================================================================== --- head/stand/libsa/uuid_to_string.c (revision 355393) +++ head/stand/libsa/uuid_to_string.c (revision 355394) @@ -1,111 +1,110 @@ /*- - * Copyright (c) 2015 M. Warner Losh - * All rights reserved. + * Copyright (c) 2015 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ /* * Note: some comments taken from lib/libc/uuid/uuid_to_string.c * Copyright (c) 2002,2005 Marcel Moolenaar * Copyright (c) 2002 Hiten Mahesh Pandya */ #include #include /* * Dump len characters into *buf from val as hex and update *buf */ static void tohex(char **buf, int len, uint32_t val) { static const char *hexstr = "0123456789abcdef"; char *walker = *buf; int i; for (i = len - 1; i >= 0; i--) { walker[i] = hexstr[val & 0xf]; val >>= 4; } *buf = walker + len; } /* * uuid_to_string() - Convert a binary UUID into a string representation. * See also: * http://www.opengroup.org/onlinepubs/009629399/uuid_to_string.htm * * NOTE: The references given above do not have a status code for when * the string could not be allocated. The status code has been * taken from the Hewlett-Packard implementation. * * NOTE: we don't support u == NULL for a nil UUID, sorry. * * NOTE: The sequence field is in big-endian, while the time fields are in * native byte order. * * hhhhhhhh-hhhh-hhhh-bbbb-bbbbbbbbbbbb * 01234567-89ab-cdef-0123-456789abcdef */ void uuid_to_string(const uuid_t *u, char **s, uint32_t *status) { uuid_t nil; char *w; if (status != NULL) *status = uuid_s_ok; if (s == NULL) /* Regular version does this odd-ball behavior too */ return; w = *s = malloc(37); if (*s == NULL) { if (status != NULL) *status = uuid_s_no_memory; return; } if (u == NULL) { u = &nil; uuid_create_nil(&nil, NULL); } /* native */ tohex(&w, 8, u->time_low); *w++ = '-'; tohex(&w, 4, u->time_mid); *w++ = '-'; tohex(&w, 4, u->time_hi_and_version); *w++ = '-'; /* Big endian, so do a byte at a time */ tohex(&w, 2, u->clock_seq_hi_and_reserved); tohex(&w, 2, u->clock_seq_low); *w++ = '-'; tohex(&w, 2, u->node[0]); tohex(&w, 2, u->node[1]); tohex(&w, 2, u->node[2]); tohex(&w, 2, u->node[3]); tohex(&w, 2, u->node[4]); tohex(&w, 2, u->node[5]); *w++ = '\0'; } Index: head/sys/amd64/include/_bus.h =================================================================== --- head/sys/amd64/include/_bus.h (revision 355393) +++ head/sys/amd64/include/_bus.h (revision 355394) @@ -1,48 +1,47 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2005 M. Warner Losh. - * All rights reserved. + * Copyright (c) 2005 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions, and the following disclaimer, * without modification, immediately at the beginning of the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef AMD64_INCLUDE__BUS_H #define AMD64_INCLUDE__BUS_H /* * Bus address and size types */ typedef uint64_t bus_addr_t; typedef uint64_t bus_size_t; /* * Access methods for bus resources and address space. */ typedef uint64_t bus_space_tag_t; typedef uint64_t bus_space_handle_t; #endif /* AMD64_INCLUDE__BUS_H */ Index: head/sys/arm/allwinner/a10_ahci.c =================================================================== --- head/sys/arm/allwinner/a10_ahci.c (revision 355393) +++ head/sys/arm/allwinner/a10_ahci.c (revision 355394) @@ -1,395 +1,394 @@ /*- - * Copyright (c) 2014-2015 M. Warner Losh - * Copyright (c) 2015 Luiz Otavio O Souza - * All rights reserved. + * Copyright (c) 2015 Luiz Otavio O Souza All rights reserved. + * Copyright (c) 2014-2015 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * The magic-bit-bang sequence used in this code may be based on a linux * platform driver in the Allwinner SDK from Allwinner Technology Co., Ltd. * www.allwinnertech.com, by Daniel Wang * though none of the original code was copied. */ #include "opt_bus.h" #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include /* * Allwinner a1x/a2x/a8x SATA attachment. This is just the AHCI register * set with a few extra implementation-specific registers that need to * be accounted for. There's only one PHY in the system, and it needs * to be trained to bring the link up. In addition, there's some DMA * specific things that need to be done as well. These things are also * just about completely undocumented, except in ugly code in the Linux * SDK Allwinner releases. */ /* BITx -- Unknown bit that needs to be set/cleared at position x */ /* UFx -- Uknown multi-bit field frobbed during init */ #define AHCI_BISTAFR 0x00A0 #define AHCI_BISTCR 0x00A4 #define AHCI_BISTFCTR 0x00A8 #define AHCI_BISTSR 0x00AC #define AHCI_BISTDECR 0x00B0 #define AHCI_DIAGNR 0x00B4 #define AHCI_DIAGNR1 0x00B8 #define AHCI_OOBR 0x00BC #define AHCI_PHYCS0R 0x00C0 /* Bits 0..17 are a mystery */ #define PHYCS0R_BIT18 (1 << 18) #define PHYCS0R_POWER_ENABLE (1 << 19) #define PHYCS0R_UF1_MASK (7 << 20) /* Unknown Field 1 */ #define PHYCS0R_UF1_INIT (3 << 20) #define PHYCS0R_BIT23 (1 << 23) #define PHYCS0R_UF2_MASK (7 << 24) /* Uknown Field 2 */ #define PHYCS0R_UF2_INIT (5 << 24) /* Bit 27 mystery */ #define PHYCS0R_POWER_STATUS_MASK (7 << 28) #define PHYCS0R_PS_GOOD (2 << 28) /* Bit 31 mystery */ #define AHCI_PHYCS1R 0x00C4 /* Bits 0..5 are a mystery */ #define PHYCS1R_UF1_MASK (3 << 6) #define PHYCS1R_UF1_INIT (2 << 6) #define PHYCS1R_UF2_MASK (0x1f << 8) #define PHYCS1R_UF2_INIT (6 << 8) /* Bits 13..14 are a mystery */ #define PHYCS1R_BIT15 (1 << 15) #define PHYCS1R_UF3_MASK (3 << 16) #define PHYCS1R_UF3_INIT (2 << 16) /* Bit 18 mystery */ #define PHYCS1R_HIGHZ (1 << 19) /* Bits 20..27 mystery */ #define PHYCS1R_BIT28 (1 << 28) /* Bits 29..31 mystery */ #define AHCI_PHYCS2R 0x00C8 /* bits 0..4 mystery */ #define PHYCS2R_UF1_MASK (0x1f << 5) #define PHYCS2R_UF1_INIT (0x19 << 5) /* Bits 10..23 mystery */ #define PHYCS2R_CALIBRATE (1 << 24) /* Bits 25..31 mystery */ #define AHCI_TIMER1MS 0x00E0 #define AHCI_GPARAM1R 0x00E8 #define AHCI_GPARAM2R 0x00EC #define AHCI_PPARAMR 0x00F0 #define AHCI_TESTR 0x00F4 #define AHCI_VERSIONR 0x00F8 #define AHCI_IDR 0x00FC #define AHCI_RWCR 0x00FC #define AHCI_P0DMACR 0x0070 #define AHCI_P0PHYCR 0x0078 #define AHCI_P0PHYSR 0x007C #define PLL_FREQ 100000000 static void inline ahci_set(struct resource *m, bus_size_t off, uint32_t set) { uint32_t val = ATA_INL(m, off); val |= set; ATA_OUTL(m, off, val); } static void inline ahci_clr(struct resource *m, bus_size_t off, uint32_t clr) { uint32_t val = ATA_INL(m, off); val &= ~clr; ATA_OUTL(m, off, val); } static void inline ahci_mask_set(struct resource *m, bus_size_t off, uint32_t mask, uint32_t set) { uint32_t val = ATA_INL(m, off); val &= mask; val |= set; ATA_OUTL(m, off, val); } /* * Should this be phy_reset or phy_init */ #define PHY_RESET_TIMEOUT 1000 static void ahci_a10_phy_reset(device_t dev) { uint32_t to, val; struct ahci_controller *ctlr = device_get_softc(dev); /* * Here starts the magic -- most of the comments are based * on guesswork, names of routines and printf error * messages. The code works, but it will do that even if the * comments are 100% BS. */ /* * Lock out other access while we initialize. Or at least that * seems to be the case based on Linux SDK #defines. Maybe this * put things into reset? */ ATA_OUTL(ctlr->r_mem, AHCI_RWCR, 0); DELAY(100); /* * Set bit 19 in PHYCS1R. Guessing this disables driving the PHY * port for a bit while we reset things. */ ahci_set(ctlr->r_mem, AHCI_PHYCS1R, PHYCS1R_HIGHZ); /* * Frob PHYCS0R... */ ahci_mask_set(ctlr->r_mem, AHCI_PHYCS0R, ~PHYCS0R_UF2_MASK, PHYCS0R_UF2_INIT | PHYCS0R_BIT23 | PHYCS0R_BIT18); /* * Set three fields in PHYCS1R */ ahci_mask_set(ctlr->r_mem, AHCI_PHYCS1R, ~(PHYCS1R_UF1_MASK | PHYCS1R_UF2_MASK | PHYCS1R_UF3_MASK), PHYCS1R_UF1_INIT | PHYCS1R_UF2_INIT | PHYCS1R_UF3_INIT); /* * Two more mystery bits in PHYCS1R. -- can these be combined above? */ ahci_set(ctlr->r_mem, AHCI_PHYCS1R, PHYCS1R_BIT15 | PHYCS1R_BIT28); /* * Now clear that first mysery bit. Perhaps this starts * driving the PHY again so we can power it up and start * talking to the SATA drive, if any below. */ ahci_clr(ctlr->r_mem, AHCI_PHYCS1R, PHYCS1R_HIGHZ); /* * Frob PHYCS0R again... */ ahci_mask_set(ctlr->r_mem, AHCI_PHYCS0R, ~PHYCS0R_UF1_MASK, PHYCS0R_UF1_INIT); /* * Frob PHYCS2R, because 25 means something? */ ahci_mask_set(ctlr->r_mem, AHCI_PHYCS2R, ~PHYCS2R_UF1_MASK, PHYCS2R_UF1_INIT); DELAY(100); /* WAG */ /* * Turn on the power to the PHY and wait for it to report back * good? */ ahci_set(ctlr->r_mem, AHCI_PHYCS0R, PHYCS0R_POWER_ENABLE); for (to = PHY_RESET_TIMEOUT; to > 0; to--) { val = ATA_INL(ctlr->r_mem, AHCI_PHYCS0R); if ((val & PHYCS0R_POWER_STATUS_MASK) == PHYCS0R_PS_GOOD) break; DELAY(10); } if (to == 0 && bootverbose) device_printf(dev, "PHY Power Failed PHYCS0R = %#x\n", val); /* * Calibrate the clocks between the device and the host. This appears * to be an automated process that clears the bit when it is done. */ ahci_set(ctlr->r_mem, AHCI_PHYCS2R, PHYCS2R_CALIBRATE); for (to = PHY_RESET_TIMEOUT; to > 0; to--) { val = ATA_INL(ctlr->r_mem, AHCI_PHYCS2R); if ((val & PHYCS2R_CALIBRATE) == 0) break; DELAY(10); } if (to == 0 && bootverbose) device_printf(dev, "PHY Cal Failed PHYCS2R %#x\n", val); /* * OK, let things settle down a bit. */ DELAY(1000); /* * Go back into normal mode now that we've calibrated the PHY. */ ATA_OUTL(ctlr->r_mem, AHCI_RWCR, 7); } static void ahci_a10_ch_start(struct ahci_channel *ch) { uint32_t reg; /* * Magical values from Allwinner SDK, setup the DMA before start * operations on this channel. */ reg = ATA_INL(ch->r_mem, AHCI_P0DMACR); reg &= ~0xff00; reg |= 0x4400; ATA_OUTL(ch->r_mem, AHCI_P0DMACR, reg); } static int ahci_a10_ctlr_reset(device_t dev) { ahci_a10_phy_reset(dev); return (ahci_ctlr_reset(dev)); } static int ahci_a10_probe(device_t dev) { if (!ofw_bus_is_compatible(dev, "allwinner,sun4i-a10-ahci")) return (ENXIO); device_set_desc(dev, "Allwinner Integrated AHCI controller"); return (BUS_PROBE_DEFAULT); } static int ahci_a10_attach(device_t dev) { int error; struct ahci_controller *ctlr; clk_t clk_pll, clk_gate; ctlr = device_get_softc(dev); clk_pll = clk_gate = NULL; ctlr->quirks = AHCI_Q_NOPMP; ctlr->vendorid = 0; ctlr->deviceid = 0; ctlr->subvendorid = 0; ctlr->subdeviceid = 0; ctlr->r_rid = 0; if (!(ctlr->r_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &ctlr->r_rid, RF_ACTIVE))) return (ENXIO); /* Enable clocks */ error = clk_get_by_ofw_index(dev, 0, 0, &clk_gate); if (error != 0) { device_printf(dev, "Cannot get gate clock\n"); goto fail; } error = clk_get_by_ofw_index(dev, 0, 1, &clk_pll); if (error != 0) { device_printf(dev, "Cannot get PLL clock\n"); goto fail; } error = clk_set_freq(clk_pll, PLL_FREQ, CLK_SET_ROUND_DOWN); if (error != 0) { device_printf(dev, "Cannot set PLL frequency\n"); goto fail; } error = clk_enable(clk_pll); if (error != 0) { device_printf(dev, "Cannot enable PLL\n"); goto fail; } error = clk_enable(clk_gate); if (error != 0) { device_printf(dev, "Cannot enable clk gate\n"); goto fail; } /* Reset controller */ if ((error = ahci_a10_ctlr_reset(dev)) != 0) goto fail; /* * No MSI registers on this platform. */ ctlr->msi = 0; ctlr->numirqs = 1; /* Channel start callback(). */ ctlr->ch_start = ahci_a10_ch_start; /* * Note: ahci_attach will release ctlr->r_mem on errors automatically */ return (ahci_attach(dev)); fail: if (clk_gate != NULL) clk_release(clk_gate); if (clk_pll != NULL) clk_release(clk_pll); bus_release_resource(dev, SYS_RES_MEMORY, ctlr->r_rid, ctlr->r_mem); return (error); } static int ahci_a10_detach(device_t dev) { return (ahci_detach(dev)); } static device_method_t ahci_ata_methods[] = { DEVMETHOD(device_probe, ahci_a10_probe), DEVMETHOD(device_attach, ahci_a10_attach), DEVMETHOD(device_detach, ahci_a10_detach), DEVMETHOD(bus_print_child, ahci_print_child), DEVMETHOD(bus_alloc_resource, ahci_alloc_resource), DEVMETHOD(bus_release_resource, ahci_release_resource), DEVMETHOD(bus_setup_intr, ahci_setup_intr), DEVMETHOD(bus_teardown_intr,ahci_teardown_intr), DEVMETHOD(bus_child_location_str, ahci_child_location_str), DEVMETHOD_END }; static driver_t ahci_ata_driver = { "ahci", ahci_ata_methods, sizeof(struct ahci_controller) }; DRIVER_MODULE(a10_ahci, simplebus, ahci_ata_driver, ahci_devclass, 0, 0); Index: head/sys/arm/conf/genboardid.awk =================================================================== --- head/sys/arm/conf/genboardid.awk (revision 355393) +++ head/sys/arm/conf/genboardid.awk (revision 355394) @@ -1,57 +1,57 @@ #!/bin/awk # $FreeBSD$ #- # SPDX-License-Identifier: BSD-2-Clause-FreeBSD # -# Copyright (c) 2012 M. Warner Losh. +# Copyright (c) 2012 M. Warner Losh # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # # Generate FreeBSD's board ID's defines from Linux's # arm board list. # # You can grab a new copy any time with: # fetch -o sys/arm/conf/mach-types http://www.arm.linux.org.uk/developer/machines/download.php # BEGIN { nr = 0; boardid[nr] = "ARM_BOARD_ID_NONE"; num[nr++] = 0; } /^#/ { next; } /^[ ]*$/ { next; } NF == 4 { boardid[nr] = "ARM_BOARD_ID_"$3; num[nr] = $4; nr++ } END { printf("/* Arm board ID file generated automatically from Linux's mach-types file. */\n\n"); printf("#ifndef _SYS_ARM_ARM_BOARDID_H\n"); printf("#define _SYS_ARM_ARM_BOARDID_H\n\n"); for (i = 0; i < nr; i++) { printf("#define %-30s %d\n", boardid[i], num[i]); } printf("\n#endif /* _SYS_ARM_ARM_BOARDID_H */\n"); } Index: head/sys/arm/include/_bus.h =================================================================== --- head/sys/arm/include/_bus.h (revision 355393) +++ head/sys/arm/include/_bus.h (revision 355394) @@ -1,47 +1,47 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2005 M. Warner Losh. + * Copyright (c) 2005 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions, and the following disclaimer, * without modification, immediately at the beginning of the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef ARM_INCLUDE__BUS_H #define ARM_INCLUDE__BUS_H /* * Addresses (in bus space). */ typedef u_long bus_addr_t; typedef u_long bus_size_t; /* * Access methods for bus space. */ typedef struct bus_space *bus_space_tag_t; typedef u_long bus_space_handle_t; #endif /* ARM_INCLUDE__BUS_H */ Index: head/sys/arm/include/atags.h =================================================================== --- head/sys/arm/include/atags.h (revision 355393) +++ head/sys/arm/include/atags.h (revision 355394) @@ -1,130 +1,130 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2012 M. Warner Losh. + * Copyright (c) 2012 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef __MACHINE_ATAGS_H__ #define __MACHINE_ATAGS_H__ /* * Linux boot ABI compatable ATAG definitions. All these structures * assume tight packing, but since they are all uint32_t's, I've not * bothered to do the usual alignment dance. */ #define LBABI_MAX_COMMAND_LINE 1024 struct arm_lbabi_header { uint32_t size; /* Size of this node, including header */ uint32_t tag; /* Node type */ }; #define ATAG_NONE 0x00000000 /* End of atags list */ #define ATAG_CORE 0x54410001 /* List must start with ATAG_CORE */ #define ATAG_MEM 0x54410002 /* Multiple ATAG_MEM nodes possible */ #define ATAG_VIDEOTEXT 0x54410003 /* Video parameters */ #define ATAG_RAMDISK 0x54410004 /* Describes the ramdisk parameters */ #define ATAG_INITRD 0x54410005 /* Deprecated ramdisk -- used va not pa */ #define ATAG_INITRD2 0x54420005 /* compressed ramdisk image */ #define ATAG_SERIAL 0x54410006 /* 64-bits of serial number */ #define ATAG_REVISION 0x54410007 /* Board revision */ #define ATAG_VIDEOLFB 0x54410008 /* vesafb framebuffer */ #define ATAG_CMDLINE 0x54410009 /* Command line */ /* * ATAG_CORE data */ struct arm_lbabi_core { uint32_t flags; /* bit 0 == read-only */ uint32_t pagesize; uint32_t rootdev; }; /* * ATAG_MEM data -- Can be more than one to describe different * banks. */ struct arm_lbabi_mem32 { uint32_t size; uint32_t start; /* start of physical memory */ }; /* * ATAG_INITRD2 - Compressed ramdisk image details */ struct arm_lbabi_initrd { uint32_t start; /* pa of start */ uint32_t size; /* How big the ram disk is */ }; /* * ATAG_SERIAL - serial number */ struct arm_lbabi_serial_number { uint32_t low; uint32_t high; }; /* * ATAG_REVISION - board revision */ struct arm_lbabi_revision { uint32_t rev; }; /* * ATAG_CMDLINE - Command line from uboot */ struct arm_lbabi_command_line { char command[1]; /* Minimum command length */ }; struct arm_lbabi_tag { struct arm_lbabi_header tag_hdr; union { struct arm_lbabi_core tag_core; struct arm_lbabi_mem32 tag_mem; struct arm_lbabi_initrd tag_initrd; struct arm_lbabi_serial_number tag_sn; struct arm_lbabi_revision tag_rev; struct arm_lbabi_command_line tag_cmd; } u; }; #define ATAG_TAG(a) (a)->tag_hdr.tag #define ATAG_SIZE(a) ((a)->tag_hdr.size * sizeof(uint32_t)) #define ATAG_NEXT(a) (struct arm_lbabi_tag *)((char *)(a) + ATAG_SIZE(a)) #endif /* __MACHINE_ATAGS_H__ */ Index: head/sys/arm/include/board.h =================================================================== --- head/sys/arm/include/board.h (revision 355393) +++ head/sys/arm/include/board.h (revision 355394) @@ -1,64 +1,64 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2012 M. Warner Losh. + * Copyright (c) 2012 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* $FreeBSD$ */ #ifndef _ARM_INCLUDE_BOARD_H_ #define _ARM_INCLUDE_BOARD_H_ #include typedef long (arm_board_init_fn)(void); struct arm_board { int board_id; /* Board ID from the boot loader */ const char *board_name; /* Human readable name */ arm_board_init_fn *board_init; /* Board initialize code */ }; #if defined(ARM_MANY_BOARD) #include "board_id.h" #define ARM_BOARD(id, name) \ static struct arm_board this_board = { \ .board_id = ARM_BOARD_ID_ ## id, \ .board_name = name, \ .board_init = board_init, \ }; \ DATA_SET(arm_boards, this_board); #define BOARD_INIT static #else /* !ARM_MANY_BOARD */ #define ARM_BOARD(id, name) extern arm_board_init_fn board_init; #define BOARD_INIT #endif /* ARM_MANY_BOARD */ #endif /* _ARM_INCLUDE_BOARD_H_ */ Index: head/sys/arm/xilinx/uart_dev_cdnc.c =================================================================== --- head/sys/arm/xilinx/uart_dev_cdnc.c (revision 355393) +++ head/sys/arm/xilinx/uart_dev_cdnc.c (revision 355394) @@ -1,717 +1,716 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2005 M. Warner Losh - * Copyright (c) 2005 Olivier Houchard - * Copyright (c) 2012 Thomas Skibo - * All rights reserved. + * Copyright (c) 2005 Olivier Houchard All rights reserved. + * Copyright (c) 2012 Thomas Skibo All rights reserved. + * Copyright (c) 2005 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* A driver for the Cadence AMBA UART as used by the Xilinx Zynq-7000. * * Reference: Zynq-7000 All Programmable SoC Technical Reference Manual. * (v1.4) November 16, 2012. Xilinx doc UG585. UART is covered in Ch. 19 * and register definitions are in appendix B.33. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include "uart_if.h" #define UART_FIFO_SIZE 64 #define RD4(bas, reg) \ bus_space_read_4((bas)->bst, (bas)->bsh, uart_regofs((bas), (reg))) #define WR4(bas, reg, value) \ bus_space_write_4((bas)->bst, (bas)->bsh, uart_regofs((bas), (reg)), \ (value)) /* Register definitions for Cadence UART Controller. */ #define CDNC_UART_CTRL_REG 0x00 /* Control Register. */ #define CDNC_UART_CTRL_REG_STOPBRK (1<<8) #define CDNC_UART_CTRL_REG_STARTBRK (1<<7) #define CDNC_UART_CTRL_REG_TORST (1<<6) #define CDNC_UART_CTRL_REG_TX_DIS (1<<5) #define CDNC_UART_CTRL_REG_TX_EN (1<<4) #define CDNC_UART_CTRL_REG_RX_DIS (1<<3) #define CDNC_UART_CTRL_REG_RX_EN (1<<2) #define CDNC_UART_CTRL_REG_TXRST (1<<1) #define CDNC_UART_CTRL_REG_RXRST (1<<0) #define CDNC_UART_MODE_REG 0x04 /* Mode Register. */ #define CDNC_UART_MODE_REG_CHMOD_R_LOOP (3<<8) /* [9:8] - channel mode */ #define CDNC_UART_MODE_REG_CHMOD_L_LOOP (2<<8) #define CDNC_UART_MODE_REG_CHMOD_AUTECHO (1<<8) #define CDNC_UART_MODE_REG_STOP2 (2<<6) /* [7:6] - stop bits */ #define CDNC_UART_MODE_REG_PAR_NONE (4<<3) /* [5:3] - parity type */ #define CDNC_UART_MODE_REG_PAR_MARK (3<<3) #define CDNC_UART_MODE_REG_PAR_SPACE (2<<3) #define CDNC_UART_MODE_REG_PAR_ODD (1<<3) #define CDNC_UART_MODE_REG_PAR_EVEN (0<<3) #define CDNC_UART_MODE_REG_6BIT (3<<1) /* [2:1] - character len */ #define CDNC_UART_MODE_REG_7BIT (2<<1) #define CDNC_UART_MODE_REG_8BIT (0<<1) #define CDNC_UART_MODE_REG_CLKSEL (1<<0) #define CDNC_UART_IEN_REG 0x08 /* Interrupt registers. */ #define CDNC_UART_IDIS_REG 0x0C #define CDNC_UART_IMASK_REG 0x10 #define CDNC_UART_ISTAT_REG 0x14 #define CDNC_UART_INT_TXOVR (1<<12) #define CDNC_UART_INT_TXNRLYFUL (1<<11) /* tx "nearly" full */ #define CDNC_UART_INT_TXTRIG (1<<10) #define CDNC_UART_INT_DMSI (1<<9) /* delta modem status */ #define CDNC_UART_INT_RXTMOUT (1<<8) #define CDNC_UART_INT_PARITY (1<<7) #define CDNC_UART_INT_FRAMING (1<<6) #define CDNC_UART_INT_RXOVR (1<<5) #define CDNC_UART_INT_TXFULL (1<<4) #define CDNC_UART_INT_TXEMPTY (1<<3) #define CDNC_UART_INT_RXFULL (1<<2) #define CDNC_UART_INT_RXEMPTY (1<<1) #define CDNC_UART_INT_RXTRIG (1<<0) #define CDNC_UART_INT_ALL 0x1FFF #define CDNC_UART_BAUDGEN_REG 0x18 #define CDNC_UART_RX_TIMEO_REG 0x1C #define CDNC_UART_RX_WATER_REG 0x20 #define CDNC_UART_MODEM_CTRL_REG 0x24 #define CDNC_UART_MODEM_CTRL_REG_FCM (1<<5) /* automatic flow control */ #define CDNC_UART_MODEM_CTRL_REG_RTS (1<<1) #define CDNC_UART_MODEM_CTRL_REG_DTR (1<<0) #define CDNC_UART_MODEM_STAT_REG 0x28 #define CDNC_UART_MODEM_STAT_REG_FCMS (1<<8) /* flow control mode (rw) */ #define CDNC_UART_MODEM_STAT_REG_DCD (1<<7) #define CDNC_UART_MODEM_STAT_REG_RI (1<<6) #define CDNC_UART_MODEM_STAT_REG_DSR (1<<5) #define CDNC_UART_MODEM_STAT_REG_CTS (1<<4) #define CDNC_UART_MODEM_STAT_REG_DDCD (1<<3) /* change in DCD (w1tc) */ #define CDNC_UART_MODEM_STAT_REG_TERI (1<<2) /* trail edge ring (w1tc) */ #define CDNC_UART_MODEM_STAT_REG_DDSR (1<<1) /* change in DSR (w1tc) */ #define CDNC_UART_MODEM_STAT_REG_DCTS (1<<0) /* change in CTS (w1tc) */ #define CDNC_UART_CHAN_STAT_REG 0x2C /* Channel status register. */ #define CDNC_UART_CHAN_STAT_REG_TXNRLYFUL (1<<14) /* tx "nearly" full */ #define CDNC_UART_CHAN_STAT_REG_TXTRIG (1<<13) #define CDNC_UART_CHAN_STAT_REG_FDELT (1<<12) #define CDNC_UART_CHAN_STAT_REG_TXACTIVE (1<<11) #define CDNC_UART_CHAN_STAT_REG_RXACTIVE (1<<10) #define CDNC_UART_CHAN_STAT_REG_TXFULL (1<<4) #define CDNC_UART_CHAN_STAT_REG_TXEMPTY (1<<3) #define CDNC_UART_CHAN_STAT_REG_RXEMPTY (1<<1) #define CDNC_UART_CHAN_STAT_REG_RXTRIG (1<<0) #define CDNC_UART_FIFO 0x30 /* Data FIFO (tx and rx) */ #define CDNC_UART_BAUDDIV_REG 0x34 #define CDNC_UART_FLOWDEL_REG 0x38 #define CDNC_UART_TX_WATER_REG 0x44 /* * Low-level UART interface. */ static int cdnc_uart_probe(struct uart_bas *bas); static void cdnc_uart_init(struct uart_bas *bas, int, int, int, int); static void cdnc_uart_term(struct uart_bas *bas); static void cdnc_uart_putc(struct uart_bas *bas, int); static int cdnc_uart_rxready(struct uart_bas *bas); static int cdnc_uart_getc(struct uart_bas *bas, struct mtx *mtx); extern SLIST_HEAD(uart_devinfo_list, uart_devinfo) uart_sysdevs; static struct uart_ops cdnc_uart_ops = { .probe = cdnc_uart_probe, .init = cdnc_uart_init, .term = cdnc_uart_term, .putc = cdnc_uart_putc, .rxready = cdnc_uart_rxready, .getc = cdnc_uart_getc, }; #define SIGCHG(c, i, s, d) \ if (c) { \ i |= (i & s) ? s : s | d; \ } else { \ i = (i & s) ? (i & ~s) | d : i; \ } static int cdnc_uart_probe(struct uart_bas *bas) { return (0); } static int cdnc_uart_set_baud(struct uart_bas *bas, int baudrate) { uint32_t baudgen, bauddiv; uint32_t best_bauddiv, best_baudgen, best_error; uint32_t baud_out, err; best_bauddiv = 0; best_baudgen = 0; best_error = ~0; /* Try all possible bauddiv values and pick best match. */ for (bauddiv = 4; bauddiv <= 255; bauddiv++) { baudgen = (bas->rclk + (baudrate * (bauddiv + 1)) / 2) / (baudrate * (bauddiv + 1)); if (baudgen < 1 || baudgen > 0xffff) continue; baud_out = bas->rclk / (baudgen * (bauddiv + 1)); err = baud_out > baudrate ? baud_out - baudrate : baudrate - baud_out; if (err < best_error) { best_error = err; best_bauddiv = bauddiv; best_baudgen = baudgen; } } if (best_bauddiv > 0) { WR4(bas, CDNC_UART_BAUDDIV_REG, best_bauddiv); WR4(bas, CDNC_UART_BAUDGEN_REG, best_baudgen); return (0); } else return (-1); /* out of range */ } static int cdnc_uart_set_params(struct uart_bas *bas, int baudrate, int databits, int stopbits, int parity) { uint32_t mode_reg_value = 0; switch (databits) { case 6: mode_reg_value |= CDNC_UART_MODE_REG_6BIT; break; case 7: mode_reg_value |= CDNC_UART_MODE_REG_7BIT; break; case 8: default: mode_reg_value |= CDNC_UART_MODE_REG_8BIT; break; } if (stopbits == 2) mode_reg_value |= CDNC_UART_MODE_REG_STOP2; switch (parity) { case UART_PARITY_MARK: mode_reg_value |= CDNC_UART_MODE_REG_PAR_MARK; break; case UART_PARITY_SPACE: mode_reg_value |= CDNC_UART_MODE_REG_PAR_SPACE; break; case UART_PARITY_ODD: mode_reg_value |= CDNC_UART_MODE_REG_PAR_ODD; break; case UART_PARITY_EVEN: mode_reg_value |= CDNC_UART_MODE_REG_PAR_EVEN; break; case UART_PARITY_NONE: default: mode_reg_value |= CDNC_UART_MODE_REG_PAR_NONE; break; } WR4(bas, CDNC_UART_MODE_REG, mode_reg_value); if (baudrate > 0 && cdnc_uart_set_baud(bas, baudrate) < 0) return (EINVAL); return(0); } static void cdnc_uart_hw_init(struct uart_bas *bas) { /* Reset RX and TX. */ WR4(bas, CDNC_UART_CTRL_REG, CDNC_UART_CTRL_REG_RXRST | CDNC_UART_CTRL_REG_TXRST); /* Interrupts all off. */ WR4(bas, CDNC_UART_IDIS_REG, CDNC_UART_INT_ALL); WR4(bas, CDNC_UART_ISTAT_REG, CDNC_UART_INT_ALL); /* Clear delta bits. */ WR4(bas, CDNC_UART_MODEM_STAT_REG, CDNC_UART_MODEM_STAT_REG_DDCD | CDNC_UART_MODEM_STAT_REG_TERI | CDNC_UART_MODEM_STAT_REG_DDSR | CDNC_UART_MODEM_STAT_REG_DCTS); /* RX FIFO water level, stale timeout */ WR4(bas, CDNC_UART_RX_WATER_REG, UART_FIFO_SIZE/2); WR4(bas, CDNC_UART_RX_TIMEO_REG, 10); /* TX FIFO water level (not used.) */ WR4(bas, CDNC_UART_TX_WATER_REG, UART_FIFO_SIZE/2); /* Bring RX and TX online. */ WR4(bas, CDNC_UART_CTRL_REG, CDNC_UART_CTRL_REG_RX_EN | CDNC_UART_CTRL_REG_TX_EN | CDNC_UART_CTRL_REG_TORST | CDNC_UART_CTRL_REG_STOPBRK); /* Set DTR and RTS. */ WR4(bas, CDNC_UART_MODEM_CTRL_REG, CDNC_UART_MODEM_CTRL_REG_DTR | CDNC_UART_MODEM_CTRL_REG_RTS); } /* * Initialize this device for use as a console. */ static void cdnc_uart_init(struct uart_bas *bas, int baudrate, int databits, int stopbits, int parity) { /* Initialize hardware. */ cdnc_uart_hw_init(bas); /* Set baudrate, parameters. */ (void)cdnc_uart_set_params(bas, baudrate, databits, stopbits, parity); } /* * Free resources now that we're no longer the console. This appears to * be never called, and I'm unsure quite what to do if I am called. */ static void cdnc_uart_term(struct uart_bas *bas) { /* XXX */ } /* * Put a character of console output (so we do it here polling rather than * interrutp driven). */ static void cdnc_uart_putc(struct uart_bas *bas, int c) { /* Wait for room. */ while ((RD4(bas,CDNC_UART_CHAN_STAT_REG) & CDNC_UART_CHAN_STAT_REG_TXFULL) != 0) ; WR4(bas, CDNC_UART_FIFO, c); while ((RD4(bas,CDNC_UART_CHAN_STAT_REG) & CDNC_UART_CHAN_STAT_REG_TXEMPTY) == 0) ; } /* * Check for a character available. */ static int cdnc_uart_rxready(struct uart_bas *bas) { return ((RD4(bas, CDNC_UART_CHAN_STAT_REG) & CDNC_UART_CHAN_STAT_REG_RXEMPTY) == 0); } /* * Block waiting for a character. */ static int cdnc_uart_getc(struct uart_bas *bas, struct mtx *mtx) { int c; uart_lock(mtx); while ((RD4(bas, CDNC_UART_CHAN_STAT_REG) & CDNC_UART_CHAN_STAT_REG_RXEMPTY) != 0) { uart_unlock(mtx); DELAY(4); uart_lock(mtx); } c = RD4(bas, CDNC_UART_FIFO); uart_unlock(mtx); c &= 0xff; return (c); } /*****************************************************************************/ /* * High-level UART interface. */ static int cdnc_uart_bus_probe(struct uart_softc *sc); static int cdnc_uart_bus_attach(struct uart_softc *sc); static int cdnc_uart_bus_flush(struct uart_softc *, int); static int cdnc_uart_bus_getsig(struct uart_softc *); static int cdnc_uart_bus_ioctl(struct uart_softc *, int, intptr_t); static int cdnc_uart_bus_ipend(struct uart_softc *); static int cdnc_uart_bus_param(struct uart_softc *, int, int, int, int); static int cdnc_uart_bus_receive(struct uart_softc *); static int cdnc_uart_bus_setsig(struct uart_softc *, int); static int cdnc_uart_bus_transmit(struct uart_softc *); static void cdnc_uart_bus_grab(struct uart_softc *); static void cdnc_uart_bus_ungrab(struct uart_softc *); static kobj_method_t cdnc_uart_bus_methods[] = { KOBJMETHOD(uart_probe, cdnc_uart_bus_probe), KOBJMETHOD(uart_attach, cdnc_uart_bus_attach), KOBJMETHOD(uart_flush, cdnc_uart_bus_flush), KOBJMETHOD(uart_getsig, cdnc_uart_bus_getsig), KOBJMETHOD(uart_ioctl, cdnc_uart_bus_ioctl), KOBJMETHOD(uart_ipend, cdnc_uart_bus_ipend), KOBJMETHOD(uart_param, cdnc_uart_bus_param), KOBJMETHOD(uart_receive, cdnc_uart_bus_receive), KOBJMETHOD(uart_setsig, cdnc_uart_bus_setsig), KOBJMETHOD(uart_transmit, cdnc_uart_bus_transmit), KOBJMETHOD(uart_grab, cdnc_uart_bus_grab), KOBJMETHOD(uart_ungrab, cdnc_uart_bus_ungrab), KOBJMETHOD_END }; int cdnc_uart_bus_probe(struct uart_softc *sc) { sc->sc_txfifosz = UART_FIFO_SIZE; sc->sc_rxfifosz = UART_FIFO_SIZE; sc->sc_hwiflow = 0; sc->sc_hwoflow = 0; device_set_desc(sc->sc_dev, "Cadence UART"); return (0); } static int cdnc_uart_bus_attach(struct uart_softc *sc) { struct uart_bas *bas = &sc->sc_bas; struct uart_devinfo *di; if (sc->sc_sysdev != NULL) { di = sc->sc_sysdev; (void)cdnc_uart_set_params(bas, di->baudrate, di->databits, di->stopbits, di->parity); } else cdnc_uart_hw_init(bas); (void)cdnc_uart_bus_getsig(sc); /* Enable interrupts. */ WR4(bas, CDNC_UART_IEN_REG, CDNC_UART_INT_RXTRIG | CDNC_UART_INT_RXTMOUT | CDNC_UART_INT_TXOVR | CDNC_UART_INT_RXOVR | CDNC_UART_INT_DMSI); return (0); } static int cdnc_uart_bus_transmit(struct uart_softc *sc) { int i; struct uart_bas *bas = &sc->sc_bas; uart_lock(sc->sc_hwmtx); /* Clear sticky TXEMPTY status bit. */ WR4(bas, CDNC_UART_ISTAT_REG, CDNC_UART_INT_TXEMPTY); for (i = 0; i < sc->sc_txdatasz; i++) WR4(bas, CDNC_UART_FIFO, sc->sc_txbuf[i]); /* Enable TX empty interrupt. */ WR4(bas, CDNC_UART_IEN_REG, CDNC_UART_INT_TXEMPTY); sc->sc_txbusy = 1; uart_unlock(sc->sc_hwmtx); return (0); } static int cdnc_uart_bus_setsig(struct uart_softc *sc, int sig) { struct uart_bas *bas = &sc->sc_bas; uint32_t new, old, modem_ctrl; do { old = sc->sc_hwsig; new = old; if (sig & SER_DDTR) { SIGCHG(sig & SER_DTR, new, SER_DTR, SER_DDTR); } if (sig & SER_DRTS) { SIGCHG(sig & SER_RTS, new, SER_RTS, SER_DRTS); } } while (!atomic_cmpset_32(&sc->sc_hwsig, old, new)); uart_lock(sc->sc_hwmtx); modem_ctrl = RD4(bas, CDNC_UART_MODEM_CTRL_REG) & ~(CDNC_UART_MODEM_CTRL_REG_DTR | CDNC_UART_MODEM_CTRL_REG_RTS); if ((new & SER_DTR) != 0) modem_ctrl |= CDNC_UART_MODEM_CTRL_REG_DTR; if ((new & SER_RTS) != 0) modem_ctrl |= CDNC_UART_MODEM_CTRL_REG_RTS; WR4(bas, CDNC_UART_MODEM_CTRL_REG, modem_ctrl); uart_unlock(sc->sc_hwmtx); return (0); } static int cdnc_uart_bus_receive(struct uart_softc *sc) { struct uart_bas *bas = &sc->sc_bas; uint32_t status; int c, c_status = 0; uart_lock(sc->sc_hwmtx); /* Check for parity or framing errors and clear the status bits. */ status = RD4(bas, CDNC_UART_ISTAT_REG); if ((status & (CDNC_UART_INT_FRAMING | CDNC_UART_INT_PARITY)) != 0) { WR4(bas, CDNC_UART_ISTAT_REG, status & (CDNC_UART_INT_FRAMING | CDNC_UART_INT_PARITY)); if ((status & CDNC_UART_INT_PARITY) != 0) c_status |= UART_STAT_PARERR; if ((status & CDNC_UART_INT_FRAMING) != 0) c_status |= UART_STAT_FRAMERR; } while ((RD4(bas, CDNC_UART_CHAN_STAT_REG) & CDNC_UART_CHAN_STAT_REG_RXEMPTY) == 0) { c = RD4(bas, CDNC_UART_FIFO) & 0xff; #ifdef KDB /* Detect break and drop into debugger. */ if (c == 0 && (c_status & UART_STAT_FRAMERR) != 0 && sc->sc_sysdev != NULL && sc->sc_sysdev->type == UART_DEV_CONSOLE) { kdb_break(); WR4(bas, CDNC_UART_ISTAT_REG, CDNC_UART_INT_FRAMING); } #endif uart_rx_put(sc, c | c_status); } uart_unlock(sc->sc_hwmtx); return (0); } static int cdnc_uart_bus_param(struct uart_softc *sc, int baudrate, int databits, int stopbits, int parity) { return (cdnc_uart_set_params(&sc->sc_bas, baudrate, databits, stopbits, parity)); } static int cdnc_uart_bus_ipend(struct uart_softc *sc) { int ipend = 0; struct uart_bas *bas = &sc->sc_bas; uint32_t istatus; uart_lock(sc->sc_hwmtx); istatus = RD4(bas, CDNC_UART_ISTAT_REG); /* Clear interrupt bits. */ WR4(bas, CDNC_UART_ISTAT_REG, istatus & (CDNC_UART_INT_RXTRIG | CDNC_UART_INT_RXTMOUT | CDNC_UART_INT_TXOVR | CDNC_UART_INT_RXOVR | CDNC_UART_INT_TXEMPTY | CDNC_UART_INT_DMSI)); /* Receive data. */ if ((istatus & (CDNC_UART_INT_RXTRIG | CDNC_UART_INT_RXTMOUT)) != 0) ipend |= SER_INT_RXREADY; /* Transmit fifo empty. */ if (sc->sc_txbusy && (istatus & CDNC_UART_INT_TXEMPTY) != 0) { /* disable txempty interrupt. */ WR4(bas, CDNC_UART_IDIS_REG, CDNC_UART_INT_TXEMPTY); ipend |= SER_INT_TXIDLE; } /* TX Overflow. */ if ((istatus & CDNC_UART_INT_TXOVR) != 0) ipend |= SER_INT_OVERRUN; /* RX Overflow. */ if ((istatus & CDNC_UART_INT_RXOVR) != 0) ipend |= SER_INT_OVERRUN; /* Modem signal change. */ if ((istatus & CDNC_UART_INT_DMSI) != 0) { WR4(bas, CDNC_UART_MODEM_STAT_REG, CDNC_UART_MODEM_STAT_REG_DDCD | CDNC_UART_MODEM_STAT_REG_TERI | CDNC_UART_MODEM_STAT_REG_DDSR | CDNC_UART_MODEM_STAT_REG_DCTS); ipend |= SER_INT_SIGCHG; } uart_unlock(sc->sc_hwmtx); return (ipend); } static int cdnc_uart_bus_flush(struct uart_softc *sc, int what) { return (0); } static int cdnc_uart_bus_getsig(struct uart_softc *sc) { struct uart_bas *bas = &sc->sc_bas; uint32_t new, old, sig; uint8_t modem_status; do { old = sc->sc_hwsig; sig = old; uart_lock(sc->sc_hwmtx); modem_status = RD4(bas, CDNC_UART_MODEM_STAT_REG); uart_unlock(sc->sc_hwmtx); SIGCHG(modem_status & CDNC_UART_MODEM_STAT_REG_DSR, sig, SER_DSR, SER_DDSR); SIGCHG(modem_status & CDNC_UART_MODEM_STAT_REG_CTS, sig, SER_CTS, SER_DCTS); SIGCHG(modem_status & CDNC_UART_MODEM_STAT_REG_DCD, sig, SER_DCD, SER_DDCD); SIGCHG(modem_status & CDNC_UART_MODEM_STAT_REG_RI, sig, SER_RI, SER_DRI); new = sig & ~SER_MASK_DELTA; } while (!atomic_cmpset_32(&sc->sc_hwsig, old, new)); return (sig); } static int cdnc_uart_bus_ioctl(struct uart_softc *sc, int request, intptr_t data) { struct uart_bas *bas = &sc->sc_bas; uint32_t uart_ctrl, modem_ctrl; int error = 0; uart_lock(sc->sc_hwmtx); switch (request) { case UART_IOCTL_BREAK: uart_ctrl = RD4(bas, CDNC_UART_CTRL_REG); if (data) { uart_ctrl |= CDNC_UART_CTRL_REG_STARTBRK; uart_ctrl &= ~CDNC_UART_CTRL_REG_STOPBRK; } else { uart_ctrl |= CDNC_UART_CTRL_REG_STOPBRK; uart_ctrl &= ~CDNC_UART_CTRL_REG_STARTBRK; } WR4(bas, CDNC_UART_CTRL_REG, uart_ctrl); break; case UART_IOCTL_IFLOW: modem_ctrl = RD4(bas, CDNC_UART_MODEM_CTRL_REG); if (data) modem_ctrl |= CDNC_UART_MODEM_CTRL_REG_RTS; else modem_ctrl &= ~CDNC_UART_MODEM_CTRL_REG_RTS; WR4(bas, CDNC_UART_MODEM_CTRL_REG, modem_ctrl); break; default: error = EINVAL; break; } uart_unlock(sc->sc_hwmtx); return (error); } static void cdnc_uart_bus_grab(struct uart_softc *sc) { /* Enable interrupts. */ WR4(&sc->sc_bas, CDNC_UART_IEN_REG, CDNC_UART_INT_TXOVR | CDNC_UART_INT_RXOVR | CDNC_UART_INT_DMSI); } static void cdnc_uart_bus_ungrab(struct uart_softc *sc) { /* Enable interrupts. */ WR4(&sc->sc_bas, CDNC_UART_IEN_REG, CDNC_UART_INT_RXTRIG | CDNC_UART_INT_RXTMOUT | CDNC_UART_INT_TXOVR | CDNC_UART_INT_RXOVR | CDNC_UART_INT_DMSI); } static struct uart_class uart_cdnc_class = { "cdnc_uart", cdnc_uart_bus_methods, sizeof(struct uart_softc), .uc_ops = &cdnc_uart_ops, .uc_range = 8 }; static struct ofw_compat_data compat_data[] = { {"cadence,uart", (uintptr_t)&uart_cdnc_class}, {"cdns,uart-r1p12", (uintptr_t)&uart_cdnc_class}, {"xlnx,xuartps", (uintptr_t)&uart_cdnc_class}, {NULL, (uintptr_t)NULL}, }; UART_FDT_CLASS_AND_DEVICE(compat_data); Index: head/sys/arm64/include/_bus.h =================================================================== --- head/sys/arm64/include/_bus.h (revision 355393) +++ head/sys/arm64/include/_bus.h (revision 355394) @@ -1,46 +1,45 @@ /*- - * Copyright (c) 2005 M. Warner Losh. - * All rights reserved. + * Copyright (c) 2005 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions, and the following disclaimer, * without modification, immediately at the beginning of the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _MACHINE__BUS_H_ #define _MACHINE__BUS_H_ /* * Addresses (in bus space). */ typedef u_long bus_addr_t; typedef u_long bus_size_t; /* * Access methods for bus space. */ typedef u_long bus_space_handle_t; typedef struct bus_space *bus_space_tag_t; #endif /* !_MACHINE__BUS_H_ */ Index: head/sys/cam/mmc/mmc_da.c =================================================================== --- head/sys/cam/mmc/mmc_da.c (revision 355393) +++ head/sys/cam/mmc/mmc_da.c (revision 355394) @@ -1,1940 +1,1939 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2006 Bernd Walter + * Copyright (c) 2006 Bernd Walter All rights reserved. + * Copyright (c) 2009 Alexander Motin All rights reserved. + * Copyright (c) 2015-2017 Ilya Bakulin All rights reserved. * Copyright (c) 2006 M. Warner Losh - * Copyright (c) 2009 Alexander Motin - * Copyright (c) 2015-2017 Ilya Bakulin - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * without modification, immediately at the beginning of the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Some code derived from the sys/dev/mmc and sys/cam/ata * Thanks to Warner Losh , Alexander Motin * Bernd Walter , and other authors. */ #include __FBSDID("$FreeBSD$"); //#include "opt_sdda.h" #include #ifdef _KERNEL #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* for PRIu64 */ #endif /* _KERNEL */ #ifndef _KERNEL #include #include #endif /* _KERNEL */ #include #include #include #include #include #include #include #include #include #include #include #include /* geometry translation */ #ifdef _KERNEL typedef enum { SDDA_FLAG_OPEN = 0x0002, SDDA_FLAG_DIRTY = 0x0004 } sdda_flags; typedef enum { SDDA_STATE_INIT, SDDA_STATE_INVALID, SDDA_STATE_NORMAL, SDDA_STATE_PART_SWITCH, } sdda_state; #define SDDA_FMT_BOOT "sdda%dboot" #define SDDA_FMT_GP "sdda%dgp" #define SDDA_FMT_RPMB "sdda%drpmb" #define SDDA_LABEL_ENH "enh" #define SDDA_PART_NAMELEN (16 + 1) struct sdda_softc; struct sdda_part { struct disk *disk; struct bio_queue_head bio_queue; sdda_flags flags; struct sdda_softc *sc; u_int cnt; u_int type; bool ro; char name[SDDA_PART_NAMELEN]; }; struct sdda_softc { int outstanding_cmds; /* Number of active commands */ int refcount; /* Active xpt_action() calls */ sdda_state state; struct mmc_data *mmcdata; struct cam_periph *periph; // sdda_quirks quirks; struct task start_init_task; uint32_t raw_csd[4]; uint8_t raw_ext_csd[512]; /* MMC only? */ struct mmc_csd csd; struct mmc_cid cid; struct mmc_scr scr; /* Calculated from CSD */ uint64_t sector_count; uint64_t mediasize; /* Calculated from CID */ char card_id_string[64];/* Formatted CID info (serial, MFG, etc) */ char card_sn_string[16];/* Formatted serial # for disk->d_ident */ /* Determined from CSD + is highspeed card*/ uint32_t card_f_max; /* Generic switch timeout */ uint32_t cmd6_time; /* MMC partitions support */ struct sdda_part *part[MMC_PART_MAX]; uint8_t part_curr; /* Partition currently switched to */ uint8_t part_requested; /* What partition we're currently switching to */ uint32_t part_time; /* Partition switch timeout [us] */ off_t enh_base; /* Enhanced user data area slice base ... */ off_t enh_size; /* ... and size [bytes] */ int log_count; struct timeval log_time; }; static const char *mmc_errmsg[] = { "None", "Timeout", "Bad CRC", "Fifo", "Failed", "Invalid", "NO MEMORY" }; #define ccb_bp ppriv_ptr1 static disk_strategy_t sddastrategy; static periph_init_t sddainit; static void sddaasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg); static periph_ctor_t sddaregister; static periph_dtor_t sddacleanup; static periph_start_t sddastart; static periph_oninv_t sddaoninvalidate; static void sddadone(struct cam_periph *periph, union ccb *done_ccb); static int sddaerror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags); static int mmc_handle_reply(union ccb *ccb); static uint16_t get_rca(struct cam_periph *periph); static void sdda_start_init(void *context, union ccb *start_ccb); static void sdda_start_init_task(void *context, int pending); static void sdda_process_mmc_partitions(struct cam_periph *periph, union ccb *start_ccb); static uint32_t sdda_get_host_caps(struct cam_periph *periph, union ccb *ccb); static void sdda_init_switch_part(struct cam_periph *periph, union ccb *start_ccb, u_int part); static int mmc_select_card(struct cam_periph *periph, union ccb *ccb, uint32_t rca); static inline uint32_t mmc_get_sector_size(struct cam_periph *periph) {return MMC_SECTOR_SIZE;} /* TODO: actually issue GET_TRAN_SETTINGS to get R/O status */ static inline bool sdda_get_read_only(struct cam_periph *periph, union ccb *start_ccb) { return (false); } static uint32_t mmc_get_spec_vers(struct cam_periph *periph); static uint64_t mmc_get_media_size(struct cam_periph *periph); static uint32_t mmc_get_cmd6_timeout(struct cam_periph *periph); static void sdda_add_part(struct cam_periph *periph, u_int type, const char *name, u_int cnt, off_t media_size, bool ro); static struct periph_driver sddadriver = { sddainit, "sdda", TAILQ_HEAD_INITIALIZER(sddadriver.units), /* generation */ 0 }; PERIPHDRIVER_DECLARE(sdda, sddadriver); static MALLOC_DEFINE(M_SDDA, "sd_da", "sd_da buffers"); static const int exp[8] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000 }; static const int mant[16] = { 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80 }; static const int cur_min[8] = { 500, 1000, 5000, 10000, 25000, 35000, 60000, 100000 }; static const int cur_max[8] = { 1000, 5000, 10000, 25000, 35000, 45000, 800000, 200000 }; static uint16_t get_rca(struct cam_periph *periph) { return periph->path->device->mmc_ident_data.card_rca; } /* * Figure out if CCB execution resulted in error. * Look at both CAM-level errors and on MMC protocol errors. */ static int mmc_handle_reply(union ccb *ccb) { KASSERT(ccb->ccb_h.func_code == XPT_MMC_IO, ("ccb %p: cannot handle non-XPT_MMC_IO errors, got func_code=%d", ccb, ccb->ccb_h.func_code)); /* TODO: maybe put MMC-specific handling into cam.c/cam_error_print altogether */ if (((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP)) { if (ccb->mmcio.cmd.error != 0) { xpt_print_path(ccb->ccb_h.path); printf("CMD%d failed, err %d (%s)\n", ccb->mmcio.cmd.opcode, ccb->mmcio.cmd.error, mmc_errmsg[ccb->mmcio.cmd.error]); return (EIO); } } else { cam_error_print(ccb, CAM_ESF_ALL, CAM_EPF_ALL); return (EIO); } return (0); /* Normal return */ } static uint32_t mmc_get_bits(uint32_t *bits, int bit_len, int start, int size) { const int i = (bit_len / 32) - (start / 32) - 1; const int shift = start & 31; uint32_t retval = bits[i] >> shift; if (size + shift > 32) retval |= bits[i - 1] << (32 - shift); return (retval & ((1llu << size) - 1)); } static void mmc_decode_csd_sd(uint32_t *raw_csd, struct mmc_csd *csd) { int v; int m; int e; memset(csd, 0, sizeof(*csd)); csd->csd_structure = v = mmc_get_bits(raw_csd, 128, 126, 2); if (v == 0) { m = mmc_get_bits(raw_csd, 128, 115, 4); e = mmc_get_bits(raw_csd, 128, 112, 3); csd->tacc = (exp[e] * mant[m] + 9) / 10; csd->nsac = mmc_get_bits(raw_csd, 128, 104, 8) * 100; m = mmc_get_bits(raw_csd, 128, 99, 4); e = mmc_get_bits(raw_csd, 128, 96, 3); csd->tran_speed = exp[e] * 10000 * mant[m]; csd->ccc = mmc_get_bits(raw_csd, 128, 84, 12); csd->read_bl_len = 1 << mmc_get_bits(raw_csd, 128, 80, 4); csd->read_bl_partial = mmc_get_bits(raw_csd, 128, 79, 1); csd->write_blk_misalign = mmc_get_bits(raw_csd, 128, 78, 1); csd->read_blk_misalign = mmc_get_bits(raw_csd, 128, 77, 1); csd->dsr_imp = mmc_get_bits(raw_csd, 128, 76, 1); csd->vdd_r_curr_min = cur_min[mmc_get_bits(raw_csd, 128, 59, 3)]; csd->vdd_r_curr_max = cur_max[mmc_get_bits(raw_csd, 128, 56, 3)]; csd->vdd_w_curr_min = cur_min[mmc_get_bits(raw_csd, 128, 53, 3)]; csd->vdd_w_curr_max = cur_max[mmc_get_bits(raw_csd, 128, 50, 3)]; m = mmc_get_bits(raw_csd, 128, 62, 12); e = mmc_get_bits(raw_csd, 128, 47, 3); csd->capacity = ((1 + m) << (e + 2)) * csd->read_bl_len; csd->erase_blk_en = mmc_get_bits(raw_csd, 128, 46, 1); csd->erase_sector = mmc_get_bits(raw_csd, 128, 39, 7) + 1; csd->wp_grp_size = mmc_get_bits(raw_csd, 128, 32, 7); csd->wp_grp_enable = mmc_get_bits(raw_csd, 128, 31, 1); csd->r2w_factor = 1 << mmc_get_bits(raw_csd, 128, 26, 3); csd->write_bl_len = 1 << mmc_get_bits(raw_csd, 128, 22, 4); csd->write_bl_partial = mmc_get_bits(raw_csd, 128, 21, 1); } else if (v == 1) { m = mmc_get_bits(raw_csd, 128, 115, 4); e = mmc_get_bits(raw_csd, 128, 112, 3); csd->tacc = (exp[e] * mant[m] + 9) / 10; csd->nsac = mmc_get_bits(raw_csd, 128, 104, 8) * 100; m = mmc_get_bits(raw_csd, 128, 99, 4); e = mmc_get_bits(raw_csd, 128, 96, 3); csd->tran_speed = exp[e] * 10000 * mant[m]; csd->ccc = mmc_get_bits(raw_csd, 128, 84, 12); csd->read_bl_len = 1 << mmc_get_bits(raw_csd, 128, 80, 4); csd->read_bl_partial = mmc_get_bits(raw_csd, 128, 79, 1); csd->write_blk_misalign = mmc_get_bits(raw_csd, 128, 78, 1); csd->read_blk_misalign = mmc_get_bits(raw_csd, 128, 77, 1); csd->dsr_imp = mmc_get_bits(raw_csd, 128, 76, 1); csd->capacity = ((uint64_t)mmc_get_bits(raw_csd, 128, 48, 22) + 1) * 512 * 1024; csd->erase_blk_en = mmc_get_bits(raw_csd, 128, 46, 1); csd->erase_sector = mmc_get_bits(raw_csd, 128, 39, 7) + 1; csd->wp_grp_size = mmc_get_bits(raw_csd, 128, 32, 7); csd->wp_grp_enable = mmc_get_bits(raw_csd, 128, 31, 1); csd->r2w_factor = 1 << mmc_get_bits(raw_csd, 128, 26, 3); csd->write_bl_len = 1 << mmc_get_bits(raw_csd, 128, 22, 4); csd->write_bl_partial = mmc_get_bits(raw_csd, 128, 21, 1); } else panic("unknown SD CSD version"); } static void mmc_decode_csd_mmc(uint32_t *raw_csd, struct mmc_csd *csd) { int m; int e; memset(csd, 0, sizeof(*csd)); csd->csd_structure = mmc_get_bits(raw_csd, 128, 126, 2); csd->spec_vers = mmc_get_bits(raw_csd, 128, 122, 4); m = mmc_get_bits(raw_csd, 128, 115, 4); e = mmc_get_bits(raw_csd, 128, 112, 3); csd->tacc = exp[e] * mant[m] + 9 / 10; csd->nsac = mmc_get_bits(raw_csd, 128, 104, 8) * 100; m = mmc_get_bits(raw_csd, 128, 99, 4); e = mmc_get_bits(raw_csd, 128, 96, 3); csd->tran_speed = exp[e] * 10000 * mant[m]; csd->ccc = mmc_get_bits(raw_csd, 128, 84, 12); csd->read_bl_len = 1 << mmc_get_bits(raw_csd, 128, 80, 4); csd->read_bl_partial = mmc_get_bits(raw_csd, 128, 79, 1); csd->write_blk_misalign = mmc_get_bits(raw_csd, 128, 78, 1); csd->read_blk_misalign = mmc_get_bits(raw_csd, 128, 77, 1); csd->dsr_imp = mmc_get_bits(raw_csd, 128, 76, 1); csd->vdd_r_curr_min = cur_min[mmc_get_bits(raw_csd, 128, 59, 3)]; csd->vdd_r_curr_max = cur_max[mmc_get_bits(raw_csd, 128, 56, 3)]; csd->vdd_w_curr_min = cur_min[mmc_get_bits(raw_csd, 128, 53, 3)]; csd->vdd_w_curr_max = cur_max[mmc_get_bits(raw_csd, 128, 50, 3)]; m = mmc_get_bits(raw_csd, 128, 62, 12); e = mmc_get_bits(raw_csd, 128, 47, 3); csd->capacity = ((1 + m) << (e + 2)) * csd->read_bl_len; csd->erase_blk_en = 0; csd->erase_sector = (mmc_get_bits(raw_csd, 128, 42, 5) + 1) * (mmc_get_bits(raw_csd, 128, 37, 5) + 1); csd->wp_grp_size = mmc_get_bits(raw_csd, 128, 32, 5); csd->wp_grp_enable = mmc_get_bits(raw_csd, 128, 31, 1); csd->r2w_factor = 1 << mmc_get_bits(raw_csd, 128, 26, 3); csd->write_bl_len = 1 << mmc_get_bits(raw_csd, 128, 22, 4); csd->write_bl_partial = mmc_get_bits(raw_csd, 128, 21, 1); } static void mmc_decode_cid_sd(uint32_t *raw_cid, struct mmc_cid *cid) { int i; /* There's no version info, so we take it on faith */ memset(cid, 0, sizeof(*cid)); cid->mid = mmc_get_bits(raw_cid, 128, 120, 8); cid->oid = mmc_get_bits(raw_cid, 128, 104, 16); for (i = 0; i < 5; i++) cid->pnm[i] = mmc_get_bits(raw_cid, 128, 96 - i * 8, 8); cid->pnm[5] = 0; cid->prv = mmc_get_bits(raw_cid, 128, 56, 8); cid->psn = mmc_get_bits(raw_cid, 128, 24, 32); cid->mdt_year = mmc_get_bits(raw_cid, 128, 12, 8) + 2000; cid->mdt_month = mmc_get_bits(raw_cid, 128, 8, 4); } static void mmc_decode_cid_mmc(uint32_t *raw_cid, struct mmc_cid *cid) { int i; /* There's no version info, so we take it on faith */ memset(cid, 0, sizeof(*cid)); cid->mid = mmc_get_bits(raw_cid, 128, 120, 8); cid->oid = mmc_get_bits(raw_cid, 128, 104, 8); for (i = 0; i < 6; i++) cid->pnm[i] = mmc_get_bits(raw_cid, 128, 96 - i * 8, 8); cid->pnm[6] = 0; cid->prv = mmc_get_bits(raw_cid, 128, 48, 8); cid->psn = mmc_get_bits(raw_cid, 128, 16, 32); cid->mdt_month = mmc_get_bits(raw_cid, 128, 12, 4); cid->mdt_year = mmc_get_bits(raw_cid, 128, 8, 4) + 1997; } static void mmc_format_card_id_string(struct sdda_softc *sc, struct mmc_params *mmcp) { char oidstr[8]; uint8_t c1; uint8_t c2; /* * Format a card ID string for use by the mmcsd driver, it's what * appears between the <> in the following: * mmcsd0: 968MB at mmc0 * 22.5MHz/4bit/128-block * * Also format just the card serial number, which the mmcsd driver will * use as the disk->d_ident string. * * The card_id_string in mmc_ivars is currently allocated as 64 bytes, * and our max formatted length is currently 55 bytes if every field * contains the largest value. * * Sometimes the oid is two printable ascii chars; when it's not, * format it as 0xnnnn instead. */ c1 = (sc->cid.oid >> 8) & 0x0ff; c2 = sc->cid.oid & 0x0ff; if (c1 > 0x1f && c1 < 0x7f && c2 > 0x1f && c2 < 0x7f) snprintf(oidstr, sizeof(oidstr), "%c%c", c1, c2); else snprintf(oidstr, sizeof(oidstr), "0x%04x", sc->cid.oid); snprintf(sc->card_sn_string, sizeof(sc->card_sn_string), "%08X", sc->cid.psn); snprintf(sc->card_id_string, sizeof(sc->card_id_string), "%s%s %s %d.%d SN %08X MFG %02d/%04d by %d %s", mmcp->card_features & CARD_FEATURE_MMC ? "MMC" : "SD", mmcp->card_features & CARD_FEATURE_SDHC ? "HC" : "", sc->cid.pnm, sc->cid.prv >> 4, sc->cid.prv & 0x0f, sc->cid.psn, sc->cid.mdt_month, sc->cid.mdt_year, sc->cid.mid, oidstr); } static int sddaopen(struct disk *dp) { struct sdda_part *part; struct cam_periph *periph; struct sdda_softc *softc; int error; part = (struct sdda_part *)dp->d_drv1; softc = part->sc; periph = softc->periph; if (cam_periph_acquire(periph) != 0) { return(ENXIO); } cam_periph_lock(periph); if ((error = cam_periph_hold(periph, PRIBIO|PCATCH)) != 0) { cam_periph_unlock(periph); cam_periph_release(periph); return (error); } CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("sddaopen\n")); part->flags |= SDDA_FLAG_OPEN; cam_periph_unhold(periph); cam_periph_unlock(periph); return (0); } static int sddaclose(struct disk *dp) { struct sdda_part *part; struct cam_periph *periph; struct sdda_softc *softc; part = (struct sdda_part *)dp->d_drv1; softc = part->sc; periph = softc->periph; part->flags &= ~SDDA_FLAG_OPEN; cam_periph_lock(periph); CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("sddaclose\n")); while (softc->refcount != 0) cam_periph_sleep(periph, &softc->refcount, PRIBIO, "sddaclose", 1); cam_periph_unlock(periph); cam_periph_release(periph); return (0); } static void sddaschedule(struct cam_periph *periph) { struct sdda_softc *softc = (struct sdda_softc *)periph->softc; struct sdda_part *part; struct bio *bp; int i; /* Check if we have more work to do. */ /* Find partition that has outstanding commands. Prefer current partition. */ bp = bioq_first(&softc->part[softc->part_curr]->bio_queue); if (bp == NULL) { for (i = 0; i < MMC_PART_MAX; i++) { if ((part = softc->part[i]) != NULL && (bp = bioq_first(&softc->part[i]->bio_queue)) != NULL) break; } } if (bp != NULL) { xpt_schedule(periph, CAM_PRIORITY_NORMAL); } } /* * Actually translate the requested transfer into one the physical driver * can understand. The transfer is described by a buf and will include * only one physical transfer. */ static void sddastrategy(struct bio *bp) { struct cam_periph *periph; struct sdda_part *part; struct sdda_softc *softc; part = (struct sdda_part *)bp->bio_disk->d_drv1; softc = part->sc; periph = softc->periph; cam_periph_lock(periph); CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("sddastrategy(%p)\n", bp)); /* * If the device has been made invalid, error out */ if ((periph->flags & CAM_PERIPH_INVALID) != 0) { cam_periph_unlock(periph); biofinish(bp, NULL, ENXIO); return; } /* * Place it in the queue of disk activities for this disk */ bioq_disksort(&part->bio_queue, bp); /* * Schedule ourselves for performing the work. */ sddaschedule(periph); cam_periph_unlock(periph); return; } static void sddainit(void) { cam_status status; /* * Install a global async callback. This callback will * receive async callbacks like "new device found". */ status = xpt_register_async(AC_FOUND_DEVICE, sddaasync, NULL, NULL); if (status != CAM_REQ_CMP) { printf("sdda: Failed to attach master async callback " "due to status 0x%x!\n", status); } } /* * Callback from GEOM, called when it has finished cleaning up its * resources. */ static void sddadiskgonecb(struct disk *dp) { struct cam_periph *periph; struct sdda_part *part; part = (struct sdda_part *)dp->d_drv1; periph = part->sc->periph; CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("sddadiskgonecb\n")); cam_periph_release(periph); } static void sddaoninvalidate(struct cam_periph *periph) { struct sdda_softc *softc; struct sdda_part *part; softc = (struct sdda_softc *)periph->softc; CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("sddaoninvalidate\n")); /* * De-register any async callbacks. */ xpt_register_async(0, sddaasync, periph, periph->path); /* * Return all queued I/O with ENXIO. * XXX Handle any transactions queued to the card * with XPT_ABORT_CCB. */ CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("bioq_flush start\n")); for (int i = 0; i < MMC_PART_MAX; i++) { if ((part = softc->part[i]) != NULL) { bioq_flush(&part->bio_queue, NULL, ENXIO); disk_gone(part->disk); } } CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("bioq_flush end\n")); } static void sddacleanup(struct cam_periph *periph) { struct sdda_softc *softc; struct sdda_part *part; int i; CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("sddacleanup\n")); softc = (struct sdda_softc *)periph->softc; cam_periph_unlock(periph); for (i = 0; i < MMC_PART_MAX; i++) { if ((part = softc->part[i]) != NULL) { disk_destroy(part->disk); free(part, M_DEVBUF); softc->part[i] = NULL; } } free(softc, M_DEVBUF); cam_periph_lock(periph); } static void sddaasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg) { struct ccb_getdev cgd; struct cam_periph *periph; struct sdda_softc *softc; periph = (struct cam_periph *)callback_arg; CAM_DEBUG(path, CAM_DEBUG_TRACE, ("sddaasync(code=%d)\n", code)); switch (code) { case AC_FOUND_DEVICE: { CAM_DEBUG(path, CAM_DEBUG_TRACE, ("=> AC_FOUND_DEVICE\n")); struct ccb_getdev *cgd; cam_status status; cgd = (struct ccb_getdev *)arg; if (cgd == NULL) break; if (cgd->protocol != PROTO_MMCSD) break; if (!(path->device->mmc_ident_data.card_features & CARD_FEATURE_MEMORY)) { CAM_DEBUG(path, CAM_DEBUG_TRACE, ("No memory on the card!\n")); break; } /* * Allocate a peripheral instance for * this device and start the probe * process. */ status = cam_periph_alloc(sddaregister, sddaoninvalidate, sddacleanup, sddastart, "sdda", CAM_PERIPH_BIO, path, sddaasync, AC_FOUND_DEVICE, cgd); if (status != CAM_REQ_CMP && status != CAM_REQ_INPROG) printf("sddaasync: Unable to attach to new device " "due to status 0x%x\n", status); break; } case AC_GETDEV_CHANGED: { CAM_DEBUG(path, CAM_DEBUG_TRACE, ("=> AC_GETDEV_CHANGED\n")); softc = (struct sdda_softc *)periph->softc; xpt_setup_ccb(&cgd.ccb_h, periph->path, CAM_PRIORITY_NORMAL); cgd.ccb_h.func_code = XPT_GDEV_TYPE; xpt_action((union ccb *)&cgd); cam_periph_async(periph, code, path, arg); break; } case AC_ADVINFO_CHANGED: { uintptr_t buftype; int i; CAM_DEBUG(path, CAM_DEBUG_TRACE, ("=> AC_ADVINFO_CHANGED\n")); buftype = (uintptr_t)arg; if (buftype == CDAI_TYPE_PHYS_PATH) { struct sdda_softc *softc; struct sdda_part *part; softc = periph->softc; for (i = 0; i < MMC_PART_MAX; i++) { if ((part = softc->part[i]) != NULL) { disk_attr_changed(part->disk, "GEOM::physpath", M_NOWAIT); } } } break; } default: CAM_DEBUG(path, CAM_DEBUG_TRACE, ("=> default?!\n")); cam_periph_async(periph, code, path, arg); break; } } static int sddagetattr(struct bio *bp) { struct cam_periph *periph; struct sdda_softc *softc; struct sdda_part *part; int ret; part = (struct sdda_part *)bp->bio_disk->d_drv1; softc = part->sc; periph = softc->periph; cam_periph_lock(periph); ret = xpt_getattr(bp->bio_data, bp->bio_length, bp->bio_attribute, periph->path); cam_periph_unlock(periph); if (ret == 0) bp->bio_completed = bp->bio_length; return (ret); } static cam_status sddaregister(struct cam_periph *periph, void *arg) { struct sdda_softc *softc; struct ccb_getdev *cgd; union ccb *request_ccb; /* CCB representing the probe request */ CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("sddaregister\n")); cgd = (struct ccb_getdev *)arg; if (cgd == NULL) { printf("sddaregister: no getdev CCB, can't register device\n"); return (CAM_REQ_CMP_ERR); } softc = (struct sdda_softc *)malloc(sizeof(*softc), M_DEVBUF, M_NOWAIT|M_ZERO); if (softc == NULL) { printf("sddaregister: Unable to probe new device. " "Unable to allocate softc\n"); return (CAM_REQ_CMP_ERR); } softc->state = SDDA_STATE_INIT; softc->mmcdata = (struct mmc_data *)malloc(sizeof(struct mmc_data), M_DEVBUF, M_NOWAIT|M_ZERO); if (softc->mmcdata == NULL) { printf("sddaregister: Unable to probe new device. " "Unable to allocate mmcdata\n"); return (CAM_REQ_CMP_ERR); } periph->softc = softc; softc->periph = periph; request_ccb = (union ccb*) arg; xpt_schedule(periph, CAM_PRIORITY_XPT); TASK_INIT(&softc->start_init_task, 0, sdda_start_init_task, periph); taskqueue_enqueue(taskqueue_thread, &softc->start_init_task); return (CAM_REQ_CMP); } static int mmc_exec_app_cmd(struct cam_periph *periph, union ccb *ccb, struct mmc_command *cmd) { int err; /* Send APP_CMD first */ memset(&ccb->mmcio.cmd, 0, sizeof(struct mmc_command)); memset(&ccb->mmcio.stop, 0, sizeof(struct mmc_command)); cam_fill_mmcio(&ccb->mmcio, /*retries*/ 0, /*cbfcnp*/ NULL, /*flags*/ CAM_DIR_NONE, /*mmc_opcode*/ MMC_APP_CMD, /*mmc_arg*/ get_rca(periph) << 16, /*mmc_flags*/ MMC_RSP_R1 | MMC_CMD_AC, /*mmc_data*/ NULL, /*timeout*/ 0); cam_periph_runccb(ccb, sddaerror, CAM_FLAG_NONE, /*sense_flags*/0, NULL); err = mmc_handle_reply(ccb); if (err != 0) return (err); if (!(ccb->mmcio.cmd.resp[0] & R1_APP_CMD)) return (EIO); /* Now exec actual command */ int flags = 0; if (cmd->data != NULL) { ccb->mmcio.cmd.data = cmd->data; if (cmd->data->flags & MMC_DATA_READ) flags |= CAM_DIR_IN; if (cmd->data->flags & MMC_DATA_WRITE) flags |= CAM_DIR_OUT; } else flags = CAM_DIR_NONE; cam_fill_mmcio(&ccb->mmcio, /*retries*/ 0, /*cbfcnp*/ NULL, /*flags*/ flags, /*mmc_opcode*/ cmd->opcode, /*mmc_arg*/ cmd->arg, /*mmc_flags*/ cmd->flags, /*mmc_data*/ cmd->data, /*timeout*/ 0); cam_periph_runccb(ccb, sddaerror, CAM_FLAG_NONE, /*sense_flags*/0, NULL); err = mmc_handle_reply(ccb); if (err != 0) return (err); memcpy(cmd->resp, ccb->mmcio.cmd.resp, sizeof(cmd->resp)); cmd->error = ccb->mmcio.cmd.error; return (0); } static int mmc_app_get_scr(struct cam_periph *periph, union ccb *ccb, uint32_t *rawscr) { int err; struct mmc_command cmd; struct mmc_data d; memset(&cmd, 0, sizeof(cmd)); memset(&d, 0, sizeof(d)); memset(rawscr, 0, 8); cmd.opcode = ACMD_SEND_SCR; cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; cmd.arg = 0; d.data = rawscr; d.len = 8; d.flags = MMC_DATA_READ; cmd.data = &d; err = mmc_exec_app_cmd(periph, ccb, &cmd); rawscr[0] = be32toh(rawscr[0]); rawscr[1] = be32toh(rawscr[1]); return (err); } static int mmc_send_ext_csd(struct cam_periph *periph, union ccb *ccb, uint8_t *rawextcsd, size_t buf_len) { int err; struct mmc_data d; KASSERT(buf_len == 512, ("Buffer for ext csd must be 512 bytes")); memset(&d, 0, sizeof(d)); d.data = rawextcsd; d.len = buf_len; d.flags = MMC_DATA_READ; memset(d.data, 0, d.len); cam_fill_mmcio(&ccb->mmcio, /*retries*/ 0, /*cbfcnp*/ NULL, /*flags*/ CAM_DIR_IN, /*mmc_opcode*/ MMC_SEND_EXT_CSD, /*mmc_arg*/ 0, /*mmc_flags*/ MMC_RSP_R1 | MMC_CMD_ADTC, /*mmc_data*/ &d, /*timeout*/ 0); cam_periph_runccb(ccb, sddaerror, CAM_FLAG_NONE, /*sense_flags*/0, NULL); err = mmc_handle_reply(ccb); return (err); } static void mmc_app_decode_scr(uint32_t *raw_scr, struct mmc_scr *scr) { unsigned int scr_struct; memset(scr, 0, sizeof(*scr)); scr_struct = mmc_get_bits(raw_scr, 64, 60, 4); if (scr_struct != 0) { printf("Unrecognised SCR structure version %d\n", scr_struct); return; } scr->sda_vsn = mmc_get_bits(raw_scr, 64, 56, 4); scr->bus_widths = mmc_get_bits(raw_scr, 64, 48, 4); } static inline void mmc_switch_fill_mmcio(union ccb *ccb, uint8_t set, uint8_t index, uint8_t value, u_int timeout) { int arg = (MMC_SWITCH_FUNC_WR << 24) | (index << 16) | (value << 8) | set; cam_fill_mmcio(&ccb->mmcio, /*retries*/ 0, /*cbfcnp*/ NULL, /*flags*/ CAM_DIR_NONE, /*mmc_opcode*/ MMC_SWITCH_FUNC, /*mmc_arg*/ arg, /*mmc_flags*/ MMC_RSP_R1B | MMC_CMD_AC, /*mmc_data*/ NULL, /*timeout*/ timeout); } static int mmc_select_card(struct cam_periph *periph, union ccb *ccb, uint32_t rca) { int flags, err; flags = (rca ? MMC_RSP_R1B : MMC_RSP_NONE) | MMC_CMD_AC; cam_fill_mmcio(&ccb->mmcio, /*retries*/ 0, /*cbfcnp*/ NULL, /*flags*/ CAM_DIR_IN, /*mmc_opcode*/ MMC_SELECT_CARD, /*mmc_arg*/ rca << 16, /*mmc_flags*/ flags, /*mmc_data*/ NULL, /*timeout*/ 0); cam_periph_runccb(ccb, sddaerror, CAM_FLAG_NONE, /*sense_flags*/0, NULL); err = mmc_handle_reply(ccb); return (err); } static int mmc_switch(struct cam_periph *periph, union ccb *ccb, uint8_t set, uint8_t index, uint8_t value, u_int timeout) { int err; mmc_switch_fill_mmcio(ccb, set, index, value, timeout); cam_periph_runccb(ccb, sddaerror, CAM_FLAG_NONE, /*sense_flags*/0, NULL); err = mmc_handle_reply(ccb); return (err); } static uint32_t mmc_get_spec_vers(struct cam_periph *periph) { struct sdda_softc *softc = (struct sdda_softc *)periph->softc; return (softc->csd.spec_vers); } static uint64_t mmc_get_media_size(struct cam_periph *periph) { struct sdda_softc *softc = (struct sdda_softc *)periph->softc; return (softc->mediasize); } static uint32_t mmc_get_cmd6_timeout(struct cam_periph *periph) { struct sdda_softc *softc = (struct sdda_softc *)periph->softc; if (mmc_get_spec_vers(periph) >= 6) return (softc->raw_ext_csd[EXT_CSD_GEN_CMD6_TIME] * 10); return (500 * 1000); } static int mmc_sd_switch(struct cam_periph *periph, union ccb *ccb, uint8_t mode, uint8_t grp, uint8_t value, uint8_t *res) { struct mmc_data mmc_d; uint32_t arg; int err; memset(res, 0, 64); memset(&mmc_d, 0, sizeof(mmc_d)); mmc_d.len = 64; mmc_d.data = res; mmc_d.flags = MMC_DATA_READ; arg = mode << 31; /* 0 - check, 1 - set */ arg |= 0x00FFFFFF; arg &= ~(0xF << (grp * 4)); arg |= value << (grp * 4); cam_fill_mmcio(&ccb->mmcio, /*retries*/ 0, /*cbfcnp*/ NULL, /*flags*/ CAM_DIR_IN, /*mmc_opcode*/ SD_SWITCH_FUNC, /*mmc_arg*/ arg, /*mmc_flags*/ MMC_RSP_R1 | MMC_CMD_ADTC, /*mmc_data*/ &mmc_d, /*timeout*/ 0); cam_periph_runccb(ccb, sddaerror, CAM_FLAG_NONE, /*sense_flags*/0, NULL); err = mmc_handle_reply(ccb); return (err); } static int mmc_set_timing(struct cam_periph *periph, union ccb *ccb, enum mmc_bus_timing timing) { u_char switch_res[64]; int err; uint8_t value; struct sdda_softc *softc = (struct sdda_softc *)periph->softc; struct mmc_params *mmcp = &periph->path->device->mmc_ident_data; CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("mmc_set_timing(timing=%d)", timing)); switch (timing) { case bus_timing_normal: value = 0; break; case bus_timing_hs: value = 1; break; default: return (MMC_ERR_INVALID); } if (mmcp->card_features & CARD_FEATURE_MMC) { err = mmc_switch(periph, ccb, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, value, softc->cmd6_time); } else { err = mmc_sd_switch(periph, ccb, SD_SWITCH_MODE_SET, SD_SWITCH_GROUP1, value, switch_res); } /* Set high-speed timing on the host */ struct ccb_trans_settings_mmc *cts; cts = &ccb->cts.proto_specific.mmc; ccb->ccb_h.func_code = XPT_SET_TRAN_SETTINGS; ccb->ccb_h.flags = CAM_DIR_NONE; ccb->ccb_h.retry_count = 0; ccb->ccb_h.timeout = 100; ccb->ccb_h.cbfcnp = NULL; cts->ios.timing = timing; cts->ios_valid = MMC_BT; xpt_action(ccb); return (err); } static void sdda_start_init_task(void *context, int pending) { union ccb *new_ccb; struct cam_periph *periph; periph = (struct cam_periph *)context; CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("sdda_start_init_task\n")); new_ccb = xpt_alloc_ccb(); xpt_setup_ccb(&new_ccb->ccb_h, periph->path, CAM_PRIORITY_NONE); cam_periph_lock(periph); sdda_start_init(context, new_ccb); cam_periph_unlock(periph); xpt_free_ccb(new_ccb); } static void sdda_set_bus_width(struct cam_periph *periph, union ccb *ccb, int width) { struct sdda_softc *softc = (struct sdda_softc *)periph->softc; struct mmc_params *mmcp = &periph->path->device->mmc_ident_data; int err; CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("sdda_set_bus_width\n")); /* First set for the card, then for the host */ if (mmcp->card_features & CARD_FEATURE_MMC) { uint8_t value; switch (width) { case bus_width_1: value = EXT_CSD_BUS_WIDTH_1; break; case bus_width_4: value = EXT_CSD_BUS_WIDTH_4; break; case bus_width_8: value = EXT_CSD_BUS_WIDTH_8; break; default: panic("Invalid bus width %d", width); } err = mmc_switch(periph, ccb, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, value, softc->cmd6_time); } else { /* For SD cards we send ACMD6 with the required bus width in arg */ struct mmc_command cmd; memset(&cmd, 0, sizeof(struct mmc_command)); cmd.opcode = ACMD_SET_BUS_WIDTH; cmd.arg = width; cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; err = mmc_exec_app_cmd(periph, ccb, &cmd); } if (err != MMC_ERR_NONE) { CAM_DEBUG(periph->path, CAM_DEBUG_PERIPH, ("Error %d when setting bus width on the card\n", err)); return; } /* Now card is done, set the host to the same width */ struct ccb_trans_settings_mmc *cts; cts = &ccb->cts.proto_specific.mmc; ccb->ccb_h.func_code = XPT_SET_TRAN_SETTINGS; ccb->ccb_h.flags = CAM_DIR_NONE; ccb->ccb_h.retry_count = 0; ccb->ccb_h.timeout = 100; ccb->ccb_h.cbfcnp = NULL; cts->ios.bus_width = width; cts->ios_valid = MMC_BW; xpt_action(ccb); } static inline const char *part_type(u_int type) { switch (type) { case EXT_CSD_PART_CONFIG_ACC_RPMB: return ("RPMB"); case EXT_CSD_PART_CONFIG_ACC_DEFAULT: return ("default"); case EXT_CSD_PART_CONFIG_ACC_BOOT0: return ("boot0"); case EXT_CSD_PART_CONFIG_ACC_BOOT1: return ("boot1"); case EXT_CSD_PART_CONFIG_ACC_GP0: case EXT_CSD_PART_CONFIG_ACC_GP1: case EXT_CSD_PART_CONFIG_ACC_GP2: case EXT_CSD_PART_CONFIG_ACC_GP3: return ("general purpose"); default: return ("(unknown type)"); } } static inline const char *bus_width_str(enum mmc_bus_width w) { switch (w) { case bus_width_1: return ("1-bit"); case bus_width_4: return ("4-bit"); case bus_width_8: return ("8-bit"); } } static uint32_t sdda_get_host_caps(struct cam_periph *periph, union ccb *ccb) { struct ccb_trans_settings_mmc *cts; cts = &ccb->cts.proto_specific.mmc; ccb->ccb_h.func_code = XPT_GET_TRAN_SETTINGS; ccb->ccb_h.flags = CAM_DIR_NONE; ccb->ccb_h.retry_count = 0; ccb->ccb_h.timeout = 100; ccb->ccb_h.cbfcnp = NULL; xpt_action(ccb); if (ccb->ccb_h.status != CAM_REQ_CMP) panic("Cannot get host caps"); return (cts->host_caps); } static uint32_t sdda_get_max_data(struct cam_periph *periph, union ccb *ccb) { struct ccb_trans_settings_mmc *cts; cts = &ccb->cts.proto_specific.mmc; memset(cts, 0, sizeof(struct ccb_trans_settings_mmc)); ccb->ccb_h.func_code = XPT_GET_TRAN_SETTINGS; ccb->ccb_h.flags = CAM_DIR_NONE; ccb->ccb_h.retry_count = 0; ccb->ccb_h.timeout = 100; ccb->ccb_h.cbfcnp = NULL; xpt_action(ccb); if (ccb->ccb_h.status != CAM_REQ_CMP) panic("Cannot get host max data"); KASSERT(cts->host_max_data != 0, ("host_max_data == 0?!")); return (cts->host_max_data); } static void sdda_start_init(void *context, union ccb *start_ccb) { struct cam_periph *periph = (struct cam_periph *)context; struct ccb_trans_settings_mmc *cts; uint32_t host_caps; uint32_t sec_count; int err; int host_f_max; CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("sdda_start_init\n")); /* periph was held for us when this task was enqueued */ if ((periph->flags & CAM_PERIPH_INVALID) != 0) { cam_periph_release(periph); return; } struct sdda_softc *softc = (struct sdda_softc *)periph->softc; //struct ccb_mmcio *mmcio = &start_ccb->mmcio; struct mmc_params *mmcp = &periph->path->device->mmc_ident_data; struct cam_ed *device = periph->path->device; if (mmcp->card_features & CARD_FEATURE_MMC) { mmc_decode_csd_mmc(mmcp->card_csd, &softc->csd); mmc_decode_cid_mmc(mmcp->card_cid, &softc->cid); if (mmc_get_spec_vers(periph) >= 4) { err = mmc_send_ext_csd(periph, start_ccb, (uint8_t *)&softc->raw_ext_csd, sizeof(softc->raw_ext_csd)); if (err != 0) { CAM_DEBUG(periph->path, CAM_DEBUG_PERIPH, ("Cannot read EXT_CSD, err %d", err)); return; } } } else { mmc_decode_csd_sd(mmcp->card_csd, &softc->csd); mmc_decode_cid_sd(mmcp->card_cid, &softc->cid); } softc->sector_count = softc->csd.capacity / 512; softc->mediasize = softc->csd.capacity; softc->cmd6_time = mmc_get_cmd6_timeout(periph); /* MMC >= 4.x have EXT_CSD that has its own opinion about capacity */ if (mmc_get_spec_vers(periph) >= 4) { sec_count = softc->raw_ext_csd[EXT_CSD_SEC_CNT] + (softc->raw_ext_csd[EXT_CSD_SEC_CNT + 1] << 8) + (softc->raw_ext_csd[EXT_CSD_SEC_CNT + 2] << 16) + (softc->raw_ext_csd[EXT_CSD_SEC_CNT + 3] << 24); if (sec_count != 0) { softc->sector_count = sec_count; softc->mediasize = softc->sector_count * 512; /* FIXME: there should be a better name for this option...*/ mmcp->card_features |= CARD_FEATURE_SDHC; } } CAM_DEBUG(periph->path, CAM_DEBUG_PERIPH, ("Capacity: %"PRIu64", sectors: %"PRIu64"\n", softc->mediasize, softc->sector_count)); mmc_format_card_id_string(softc, mmcp); /* Update info for CAM */ device->serial_num_len = strlen(softc->card_sn_string); device->serial_num = (u_int8_t *)malloc((device->serial_num_len + 1), M_CAMXPT, M_NOWAIT); strlcpy(device->serial_num, softc->card_sn_string, device->serial_num_len); device->device_id_len = strlen(softc->card_id_string); device->device_id = (u_int8_t *)malloc((device->device_id_len + 1), M_CAMXPT, M_NOWAIT); strlcpy(device->device_id, softc->card_id_string, device->device_id_len); strlcpy(mmcp->model, softc->card_id_string, sizeof(mmcp->model)); /* Set the clock frequency that the card can handle */ cts = &start_ccb->cts.proto_specific.mmc; /* First, get the host's max freq */ start_ccb->ccb_h.func_code = XPT_GET_TRAN_SETTINGS; start_ccb->ccb_h.flags = CAM_DIR_NONE; start_ccb->ccb_h.retry_count = 0; start_ccb->ccb_h.timeout = 100; start_ccb->ccb_h.cbfcnp = NULL; xpt_action(start_ccb); if (start_ccb->ccb_h.status != CAM_REQ_CMP) panic("Cannot get max host freq"); host_f_max = cts->host_f_max; host_caps = cts->host_caps; if (cts->ios.bus_width != bus_width_1) panic("Bus width in ios is not 1-bit"); /* Now check if the card supports High-speed */ softc->card_f_max = softc->csd.tran_speed; if (host_caps & MMC_CAP_HSPEED) { /* Find out if the card supports High speed timing */ if (mmcp->card_features & CARD_FEATURE_SD20) { /* Get and decode SCR */ uint32_t rawscr[2]; uint8_t res[64]; if (mmc_app_get_scr(periph, start_ccb, rawscr)) { CAM_DEBUG(periph->path, CAM_DEBUG_PERIPH, ("Cannot get SCR\n")); goto finish_hs_tests; } mmc_app_decode_scr(rawscr, &softc->scr); if ((softc->scr.sda_vsn >= 1) && (softc->csd.ccc & (1<<10))) { mmc_sd_switch(periph, start_ccb, SD_SWITCH_MODE_CHECK, SD_SWITCH_GROUP1, SD_SWITCH_NOCHANGE, res); if (res[13] & 2) { CAM_DEBUG(periph->path, CAM_DEBUG_PERIPH, ("Card supports HS\n")); softc->card_f_max = SD_HS_MAX; } /* * We deselect then reselect the card here. Some cards * become unselected and timeout with the above two * commands, although the state tables / diagrams in the * standard suggest they go back to the transfer state. * Other cards don't become deselected, and if we * attempt to blindly re-select them, we get timeout * errors from some controllers. So we deselect then * reselect to handle all situations. */ mmc_select_card(periph, start_ccb, 0); mmc_select_card(periph, start_ccb, get_rca(periph)); } else { CAM_DEBUG(periph->path, CAM_DEBUG_PERIPH, ("Not trying the switch\n")); goto finish_hs_tests; } } if (mmcp->card_features & CARD_FEATURE_MMC && mmc_get_spec_vers(periph) >= 4) { if (softc->raw_ext_csd[EXT_CSD_CARD_TYPE] & EXT_CSD_CARD_TYPE_HS_52) softc->card_f_max = MMC_TYPE_HS_52_MAX; else if (softc->raw_ext_csd[EXT_CSD_CARD_TYPE] & EXT_CSD_CARD_TYPE_HS_26) softc->card_f_max = MMC_TYPE_HS_26_MAX; } } int f_max; finish_hs_tests: f_max = min(host_f_max, softc->card_f_max); CAM_DEBUG(periph->path, CAM_DEBUG_PERIPH, ("Set SD freq to %d MHz (min out of host f=%d MHz and card f=%d MHz)\n", f_max / 1000000, host_f_max / 1000000, softc->card_f_max / 1000000)); /* Enable high-speed timing on the card */ if (f_max > 25000000) { err = mmc_set_timing(periph, start_ccb, bus_timing_hs); if (err != MMC_ERR_NONE) { CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("Cannot switch card to high-speed mode")); f_max = 25000000; } } /* Set frequency on the controller */ start_ccb->ccb_h.func_code = XPT_SET_TRAN_SETTINGS; start_ccb->ccb_h.flags = CAM_DIR_NONE; start_ccb->ccb_h.retry_count = 0; start_ccb->ccb_h.timeout = 100; start_ccb->ccb_h.cbfcnp = NULL; cts->ios.clock = f_max; cts->ios_valid = MMC_CLK; xpt_action(start_ccb); /* Set bus width */ enum mmc_bus_width desired_bus_width = bus_width_1; enum mmc_bus_width max_host_bus_width = (host_caps & MMC_CAP_8_BIT_DATA ? bus_width_8 : host_caps & MMC_CAP_4_BIT_DATA ? bus_width_4 : bus_width_1); enum mmc_bus_width max_card_bus_width = bus_width_1; if (mmcp->card_features & CARD_FEATURE_SD20 && softc->scr.bus_widths & SD_SCR_BUS_WIDTH_4) max_card_bus_width = bus_width_4; /* * Unlike SD, MMC cards don't have any information about supported bus width... * So we need to perform read/write test to find out the width. */ /* TODO: figure out bus width for MMC; use 8-bit for now (to test on BBB) */ if (mmcp->card_features & CARD_FEATURE_MMC) max_card_bus_width = bus_width_8; desired_bus_width = min(max_host_bus_width, max_card_bus_width); CAM_DEBUG(periph->path, CAM_DEBUG_PERIPH, ("Set bus width to %s (min of host %s and card %s)\n", bus_width_str(desired_bus_width), bus_width_str(max_host_bus_width), bus_width_str(max_card_bus_width))); sdda_set_bus_width(periph, start_ccb, desired_bus_width); softc->state = SDDA_STATE_NORMAL; /* MMC partitions support */ if (mmcp->card_features & CARD_FEATURE_MMC && mmc_get_spec_vers(periph) >= 4) { sdda_process_mmc_partitions(periph, start_ccb); } else if (mmcp->card_features & CARD_FEATURE_SD20) { /* For SD[HC] cards, just add one partition that is the whole card */ sdda_add_part(periph, 0, "sdda", periph->unit_number, mmc_get_media_size(periph), sdda_get_read_only(periph, start_ccb)); softc->part_curr = 0; } xpt_announce_periph(periph, softc->card_id_string); /* * Add async callbacks for bus reset and bus device reset calls. * I don't bother checking if this fails as, in most cases, * the system will function just fine without them and the only * alternative would be to not attach the device on failure. */ xpt_register_async(AC_LOST_DEVICE | AC_GETDEV_CHANGED | AC_ADVINFO_CHANGED, sddaasync, periph, periph->path); } static void sdda_add_part(struct cam_periph *periph, u_int type, const char *name, u_int cnt, off_t media_size, bool ro) { struct sdda_softc *sc = (struct sdda_softc *)periph->softc; struct sdda_part *part; struct ccb_pathinq cpi; CAM_DEBUG(periph->path, CAM_DEBUG_PERIPH, ("Partition type '%s', size %ju %s\n", part_type(type), media_size, ro ? "(read-only)" : "")); part = sc->part[type] = malloc(sizeof(*part), M_DEVBUF, M_WAITOK | M_ZERO); part->cnt = cnt; part->type = type; part->ro = ro; part->sc = sc; snprintf(part->name, sizeof(part->name), name, periph->unit_number); /* * Due to the nature of RPMB partition it doesn't make much sense * to add it as a disk. It would be more appropriate to create a * userland tool to operate on the partition or leverage the existing * tools from sysutils/mmc-utils. */ if (type == EXT_CSD_PART_CONFIG_ACC_RPMB) { /* TODO: Create device, assign IOCTL handler */ CAM_DEBUG(periph->path, CAM_DEBUG_PERIPH, ("Don't know what to do with RPMB partitions yet\n")); return; } bioq_init(&part->bio_queue); bzero(&cpi, sizeof(cpi)); xpt_setup_ccb(&cpi.ccb_h, periph->path, CAM_PRIORITY_NONE); cpi.ccb_h.func_code = XPT_PATH_INQ; xpt_action((union ccb *)&cpi); /* * Register this media as a disk */ (void)cam_periph_hold(periph, PRIBIO); cam_periph_unlock(periph); part->disk = disk_alloc(); part->disk->d_rotation_rate = DISK_RR_NON_ROTATING; part->disk->d_devstat = devstat_new_entry(part->name, cnt, 512, DEVSTAT_ALL_SUPPORTED, DEVSTAT_TYPE_DIRECT | XPORT_DEVSTAT_TYPE(cpi.transport), DEVSTAT_PRIORITY_DISK); part->disk->d_open = sddaopen; part->disk->d_close = sddaclose; part->disk->d_strategy = sddastrategy; part->disk->d_getattr = sddagetattr; // sc->disk->d_dump = sddadump; part->disk->d_gone = sddadiskgonecb; part->disk->d_name = part->name; part->disk->d_drv1 = part; part->disk->d_maxsize = MIN(MAXPHYS, sdda_get_max_data(periph, (union ccb *)&cpi) * mmc_get_sector_size(periph)); part->disk->d_unit = cnt; part->disk->d_flags = 0; strlcpy(part->disk->d_descr, sc->card_id_string, MIN(sizeof(part->disk->d_descr), sizeof(sc->card_id_string))); strlcpy(part->disk->d_ident, sc->card_sn_string, MIN(sizeof(part->disk->d_ident), sizeof(sc->card_sn_string))); part->disk->d_hba_vendor = cpi.hba_vendor; part->disk->d_hba_device = cpi.hba_device; part->disk->d_hba_subvendor = cpi.hba_subvendor; part->disk->d_hba_subdevice = cpi.hba_subdevice; snprintf(part->disk->d_attachment, sizeof(part->disk->d_attachment), "%s%d", cpi.dev_name, cpi.unit_number); part->disk->d_sectorsize = mmc_get_sector_size(periph); part->disk->d_mediasize = media_size; part->disk->d_stripesize = 0; part->disk->d_fwsectors = 0; part->disk->d_fwheads = 0; /* * Acquire a reference to the periph before we register with GEOM. * We'll release this reference once GEOM calls us back (via * sddadiskgonecb()) telling us that our provider has been freed. */ if (cam_periph_acquire(periph) != 0) { xpt_print(periph->path, "%s: lost periph during " "registration!\n", __func__); cam_periph_lock(periph); return; } disk_create(part->disk, DISK_VERSION); cam_periph_lock(periph); cam_periph_unhold(periph); } /* * For MMC cards, process EXT_CSD and add partitions that are supported by * this device. */ static void sdda_process_mmc_partitions(struct cam_periph *periph, union ccb *ccb) { struct sdda_softc *sc = (struct sdda_softc *)periph->softc; struct mmc_params *mmcp = &periph->path->device->mmc_ident_data; off_t erase_size, sector_size, size, wp_size; int i; const uint8_t *ext_csd; uint8_t rev; bool comp, ro; ext_csd = sc->raw_ext_csd; /* * Enhanced user data area and general purpose partitions are only * supported in revision 1.4 (EXT_CSD_REV == 4) and later, the RPMB * partition in revision 1.5 (MMC v4.41, EXT_CSD_REV == 5) and later. */ rev = ext_csd[EXT_CSD_REV]; /* * Ignore user-creatable enhanced user data area and general purpose * partitions partitions as long as partitioning hasn't been finished. */ comp = (ext_csd[EXT_CSD_PART_SET] & EXT_CSD_PART_SET_COMPLETED) != 0; /* * Add enhanced user data area slice, unless it spans the entirety of * the user data area. The enhanced area is of a multiple of high * capacity write protect groups ((ERASE_GRP_SIZE + HC_WP_GRP_SIZE) * * 512 KB) and its offset given in either sectors or bytes, depending * on whether it's a high capacity device or not. * NB: The slicer and its slices need to be registered before adding * the disk for the corresponding user data area as re-tasting is * racy. */ sector_size = mmc_get_sector_size(periph); size = ext_csd[EXT_CSD_ENH_SIZE_MULT] + (ext_csd[EXT_CSD_ENH_SIZE_MULT + 1] << 8) + (ext_csd[EXT_CSD_ENH_SIZE_MULT + 2] << 16); if (rev >= 4 && comp == TRUE && size > 0 && (ext_csd[EXT_CSD_PART_SUPPORT] & EXT_CSD_PART_SUPPORT_ENH_ATTR_EN) != 0 && (ext_csd[EXT_CSD_PART_ATTR] & (EXT_CSD_PART_ATTR_ENH_USR)) != 0) { erase_size = ext_csd[EXT_CSD_ERASE_GRP_SIZE] * 1024 * MMC_SECTOR_SIZE; wp_size = ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; size *= erase_size * wp_size; if (size != mmc_get_media_size(periph) * sector_size) { sc->enh_size = size; sc->enh_base = (ext_csd[EXT_CSD_ENH_START_ADDR] + (ext_csd[EXT_CSD_ENH_START_ADDR + 1] << 8) + (ext_csd[EXT_CSD_ENH_START_ADDR + 2] << 16) + (ext_csd[EXT_CSD_ENH_START_ADDR + 3] << 24)) * ((mmcp->card_features & CARD_FEATURE_SDHC) ? 1: MMC_SECTOR_SIZE); } else CAM_DEBUG(periph->path, CAM_DEBUG_PERIPH, ("enhanced user data area spans entire device")); } /* * Add default partition. This may be the only one or the user * data area in case partitions are supported. */ ro = sdda_get_read_only(periph, ccb); sdda_add_part(periph, EXT_CSD_PART_CONFIG_ACC_DEFAULT, "sdda", periph->unit_number, mmc_get_media_size(periph), ro); sc->part_curr = EXT_CSD_PART_CONFIG_ACC_DEFAULT; if (mmc_get_spec_vers(periph) < 3) return; /* Belatedly announce enhanced user data slice. */ if (sc->enh_size != 0) { CAM_DEBUG(periph->path, CAM_DEBUG_PERIPH, ("enhanced user data area off 0x%jx size %ju bytes\n", sc->enh_base, sc->enh_size)); } /* * Determine partition switch timeout (provided in units of 10 ms) * and ensure it's at least 300 ms as some eMMC chips lie. */ sc->part_time = max(ext_csd[EXT_CSD_PART_SWITCH_TO] * 10 * 1000, 300 * 1000); /* Add boot partitions, which are of a fixed multiple of 128 KB. */ size = ext_csd[EXT_CSD_BOOT_SIZE_MULT] * MMC_BOOT_RPMB_BLOCK_SIZE; if (size > 0 && (sdda_get_host_caps(periph, ccb) & MMC_CAP_BOOT_NOACC) == 0) { sdda_add_part(periph, EXT_CSD_PART_CONFIG_ACC_BOOT0, SDDA_FMT_BOOT, 0, size, ro | ((ext_csd[EXT_CSD_BOOT_WP_STATUS] & EXT_CSD_BOOT_WP_STATUS_BOOT0_MASK) != 0)); sdda_add_part(periph, EXT_CSD_PART_CONFIG_ACC_BOOT1, SDDA_FMT_BOOT, 1, size, ro | ((ext_csd[EXT_CSD_BOOT_WP_STATUS] & EXT_CSD_BOOT_WP_STATUS_BOOT1_MASK) != 0)); } /* Add RPMB partition, which also is of a fixed multiple of 128 KB. */ size = ext_csd[EXT_CSD_RPMB_MULT] * MMC_BOOT_RPMB_BLOCK_SIZE; if (rev >= 5 && size > 0) sdda_add_part(periph, EXT_CSD_PART_CONFIG_ACC_RPMB, SDDA_FMT_RPMB, 0, size, ro); if (rev <= 3 || comp == FALSE) return; /* * Add general purpose partitions, which are of a multiple of high * capacity write protect groups, too. */ if ((ext_csd[EXT_CSD_PART_SUPPORT] & EXT_CSD_PART_SUPPORT_EN) != 0) { erase_size = ext_csd[EXT_CSD_ERASE_GRP_SIZE] * 1024 * MMC_SECTOR_SIZE; wp_size = ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; for (i = 0; i < MMC_PART_GP_MAX; i++) { size = ext_csd[EXT_CSD_GP_SIZE_MULT + i * 3] + (ext_csd[EXT_CSD_GP_SIZE_MULT + i * 3 + 1] << 8) + (ext_csd[EXT_CSD_GP_SIZE_MULT + i * 3 + 2] << 16); if (size == 0) continue; sdda_add_part(periph, EXT_CSD_PART_CONFIG_ACC_GP0 + i, SDDA_FMT_GP, i, size * erase_size * wp_size, ro); } } } /* * We cannot just call mmc_switch() since it will sleep, and we are in * GEOM context and cannot sleep. Instead, create an MMCIO request to switch * partitions and send it to h/w, and upon completion resume processing * the I/O queue. * This function cannot fail, instead check switch errors in sddadone(). */ static void sdda_init_switch_part(struct cam_periph *periph, union ccb *start_ccb, u_int part) { struct sdda_softc *sc = (struct sdda_softc *)periph->softc; uint8_t value; sc->part_requested = part; value = (sc->raw_ext_csd[EXT_CSD_PART_CONFIG] & ~EXT_CSD_PART_CONFIG_ACC_MASK) | part; mmc_switch_fill_mmcio(start_ccb, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONFIG, value, sc->part_time); start_ccb->ccb_h.cbfcnp = sddadone; sc->outstanding_cmds++; cam_periph_unlock(periph); xpt_action(start_ccb); cam_periph_lock(periph); } /* Called with periph lock held! */ static void sddastart(struct cam_periph *periph, union ccb *start_ccb) { struct bio *bp; struct sdda_softc *softc = (struct sdda_softc *)periph->softc; struct sdda_part *part; struct mmc_params *mmcp = &periph->path->device->mmc_ident_data; int part_index; CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("sddastart\n")); if (softc->state != SDDA_STATE_NORMAL) { CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("device is not in SDDA_STATE_NORMAL yet\n")); xpt_release_ccb(start_ccb); return; } /* Find partition that has outstanding commands. Prefer current partition. */ part = softc->part[softc->part_curr]; bp = bioq_first(&part->bio_queue); if (bp == NULL) { for (part_index = 0; part_index < MMC_PART_MAX; part_index++) { if ((part = softc->part[part_index]) != NULL && (bp = bioq_first(&softc->part[part_index]->bio_queue)) != NULL) break; } } if (bp == NULL) { xpt_release_ccb(start_ccb); return; } if (part_index != softc->part_curr) { CAM_DEBUG(periph->path, CAM_DEBUG_PERIPH, ("Partition %d -> %d\n", softc->part_curr, part_index)); /* * According to section "6.2.2 Command restrictions" of the eMMC * specification v5.1, CMD19/CMD21 aren't allowed to be used with * RPMB partitions. So we pause re-tuning along with triggering * it up-front to decrease the likelihood of re-tuning becoming * necessary while accessing an RPMB partition. Consequently, an * RPMB partition should immediately be switched away from again * after an access in order to allow for re-tuning to take place * anew. */ /* TODO: pause retune if switching to RPMB partition */ softc->state = SDDA_STATE_PART_SWITCH; sdda_init_switch_part(periph, start_ccb, part_index); return; } bioq_remove(&part->bio_queue, bp); switch (bp->bio_cmd) { case BIO_WRITE: CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("BIO_WRITE\n")); part->flags |= SDDA_FLAG_DIRTY; /* FALLTHROUGH */ case BIO_READ: { struct ccb_mmcio *mmcio; uint64_t blockno = bp->bio_pblkno; uint16_t count = bp->bio_bcount / 512; uint16_t opcode; if (bp->bio_cmd == BIO_READ) CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("BIO_READ\n")); CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("Block %"PRIu64" cnt %u\n", blockno, count)); /* Construct new MMC command */ if (bp->bio_cmd == BIO_READ) { if (count > 1) opcode = MMC_READ_MULTIPLE_BLOCK; else opcode = MMC_READ_SINGLE_BLOCK; } else { if (count > 1) opcode = MMC_WRITE_MULTIPLE_BLOCK; else opcode = MMC_WRITE_BLOCK; } start_ccb->ccb_h.func_code = XPT_MMC_IO; start_ccb->ccb_h.flags = (bp->bio_cmd == BIO_READ ? CAM_DIR_IN : CAM_DIR_OUT); start_ccb->ccb_h.retry_count = 0; start_ccb->ccb_h.timeout = 15 * 1000; start_ccb->ccb_h.cbfcnp = sddadone; mmcio = &start_ccb->mmcio; mmcio->cmd.opcode = opcode; mmcio->cmd.arg = blockno; if (!(mmcp->card_features & CARD_FEATURE_SDHC)) mmcio->cmd.arg <<= 9; mmcio->cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; mmcio->cmd.data = softc->mmcdata; memset(mmcio->cmd.data, 0, sizeof(struct mmc_data)); mmcio->cmd.data->data = bp->bio_data; mmcio->cmd.data->len = 512 * count; mmcio->cmd.data->flags = (bp->bio_cmd == BIO_READ ? MMC_DATA_READ : MMC_DATA_WRITE); /* Direct h/w to issue CMD12 upon completion */ if (count > 1) { mmcio->cmd.data->flags |= MMC_DATA_MULTI; mmcio->stop.opcode = MMC_STOP_TRANSMISSION; mmcio->stop.flags = MMC_RSP_R1B | MMC_CMD_AC; mmcio->stop.arg = 0; } break; } case BIO_FLUSH: CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("BIO_FLUSH\n")); sddaschedule(periph); break; case BIO_DELETE: CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("BIO_DELETE\n")); sddaschedule(periph); break; } start_ccb->ccb_h.ccb_bp = bp; softc->outstanding_cmds++; softc->refcount++; cam_periph_unlock(periph); xpt_action(start_ccb); cam_periph_lock(periph); /* May have more work to do, so ensure we stay scheduled */ sddaschedule(periph); } static void sddadone(struct cam_periph *periph, union ccb *done_ccb) { struct bio *bp; struct sdda_softc *softc; struct ccb_mmcio *mmcio; struct cam_path *path; uint32_t card_status; int error = 0; softc = (struct sdda_softc *)periph->softc; mmcio = &done_ccb->mmcio; path = done_ccb->ccb_h.path; CAM_DEBUG(path, CAM_DEBUG_TRACE, ("sddadone\n")); // cam_periph_lock(periph); if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { CAM_DEBUG(path, CAM_DEBUG_TRACE, ("Error!!!\n")); if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) cam_release_devq(path, /*relsim_flags*/0, /*reduction*/0, /*timeout*/0, /*getcount_only*/0); error = 5; /* EIO */ } else { if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) panic("REQ_CMP with QFRZN"); error = 0; } card_status = mmcio->cmd.resp[0]; CAM_DEBUG(path, CAM_DEBUG_TRACE, ("Card status: %08x\n", R1_STATUS(card_status))); CAM_DEBUG(path, CAM_DEBUG_TRACE, ("Current state: %d\n", R1_CURRENT_STATE(card_status))); /* Process result of switching MMC partitions */ if (softc->state == SDDA_STATE_PART_SWITCH) { CAM_DEBUG(path, CAM_DEBUG_TRACE, ("Compteting partition switch to %d\n", softc->part_requested)); softc->outstanding_cmds--; /* Complete partition switch */ softc->state = SDDA_STATE_NORMAL; if (error != MMC_ERR_NONE) { /* TODO: Unpause retune if accessing RPMB */ xpt_release_ccb(done_ccb); xpt_schedule(periph, CAM_PRIORITY_NORMAL); return; } softc->raw_ext_csd[EXT_CSD_PART_CONFIG] = (softc->raw_ext_csd[EXT_CSD_PART_CONFIG] & ~EXT_CSD_PART_CONFIG_ACC_MASK) | softc->part_requested; /* TODO: Unpause retune if accessing RPMB */ softc->part_curr = softc->part_requested; xpt_release_ccb(done_ccb); /* Return to processing BIO requests */ xpt_schedule(periph, CAM_PRIORITY_NORMAL); return; } bp = (struct bio *)done_ccb->ccb_h.ccb_bp; bp->bio_error = error; if (error != 0) { bp->bio_resid = bp->bio_bcount; bp->bio_flags |= BIO_ERROR; } else { /* XXX: How many bytes remaining? */ bp->bio_resid = 0; if (bp->bio_resid > 0) bp->bio_flags |= BIO_ERROR; } softc->outstanding_cmds--; xpt_release_ccb(done_ccb); /* * Release the periph refcount taken in sddastart() for each CCB. */ KASSERT(softc->refcount >= 1, ("sddadone softc %p refcount %d", softc, softc->refcount)); softc->refcount--; biodone(bp); } static int sddaerror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags) { return(cam_periph_error(ccb, cam_flags, sense_flags)); } #endif /* _KERNEL */ Index: head/sys/dev/cardbus/cardbus.c =================================================================== --- head/sys/dev/cardbus/cardbus.c (revision 355393) +++ head/sys/dev/cardbus/cardbus.c (revision 355394) @@ -1,373 +1,372 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2000,2001 Jonathan Chen. All rights reserved. - * - * Copyright (c) 2003-2008 M. Warner Losh. + * Copyright (c) 2003-2008 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "power_if.h" #include "pcib_if.h" /* sysctl vars */ static SYSCTL_NODE(_hw, OID_AUTO, cardbus, CTLFLAG_RD, 0, "CardBus parameters"); int cardbus_debug = 0; SYSCTL_INT(_hw_cardbus, OID_AUTO, debug, CTLFLAG_RWTUN, &cardbus_debug, 0, "CardBus debug"); int cardbus_cis_debug = 0; SYSCTL_INT(_hw_cardbus, OID_AUTO, cis_debug, CTLFLAG_RWTUN, &cardbus_cis_debug, 0, "CardBus CIS debug"); #define DPRINTF(a) if (cardbus_debug) printf a #define DEVPRINTF(x) if (cardbus_debug) device_printf x static int cardbus_attach(device_t cbdev); static int cardbus_attach_card(device_t cbdev); static int cardbus_detach(device_t cbdev); static int cardbus_detach_card(device_t cbdev); static void cardbus_device_setup_regs(pcicfgregs *cfg); static void cardbus_driver_added(device_t cbdev, driver_t *driver); static int cardbus_probe(device_t cbdev); static int cardbus_read_ivar(device_t cbdev, device_t child, int which, uintptr_t *result); /************************************************************************/ /* Probe/Attach */ /************************************************************************/ static int cardbus_probe(device_t cbdev) { device_set_desc(cbdev, "CardBus bus"); return (0); } static int cardbus_attach(device_t cbdev) { struct cardbus_softc *sc; #ifdef PCI_RES_BUS int rid; #endif sc = device_get_softc(cbdev); sc->sc_dev = cbdev; #ifdef PCI_RES_BUS rid = 0; sc->sc_bus = bus_alloc_resource(cbdev, PCI_RES_BUS, &rid, pcib_get_bus(cbdev), pcib_get_bus(cbdev), 1, 0); if (sc->sc_bus == NULL) { device_printf(cbdev, "failed to allocate bus number\n"); return (ENXIO); } #else device_printf(cbdev, "Your bus numbers may be AFU\n"); #endif return (0); } static int cardbus_detach(device_t cbdev) { #ifdef PCI_RES_BUS struct cardbus_softc *sc; #endif cardbus_detach_card(cbdev); #ifdef PCI_RES_BUS sc = device_get_softc(cbdev); device_printf(cbdev, "Freeing up the allocatd bus\n"); (void)bus_release_resource(cbdev, PCI_RES_BUS, 0, sc->sc_bus); #endif return (0); } static int cardbus_suspend(device_t self) { cardbus_detach_card(self); return (0); } static int cardbus_resume(device_t self) { return (0); } /************************************************************************/ /* Attach/Detach card */ /************************************************************************/ static void cardbus_device_setup_regs(pcicfgregs *cfg) { device_t dev = cfg->dev; int i; /* * Some cards power up with garbage in their BARs. This * code clears all that junk out. */ for (i = 0; i < PCIR_MAX_BAR_0; i++) pci_write_config(dev, PCIR_BAR(i), 0, 4); cfg->intline = pci_get_irq(device_get_parent(device_get_parent(dev))); pci_write_config(dev, PCIR_INTLINE, cfg->intline, 1); pci_write_config(dev, PCIR_CACHELNSZ, 0x08, 1); pci_write_config(dev, PCIR_LATTIMER, 0xa8, 1); pci_write_config(dev, PCIR_MINGNT, 0x14, 1); pci_write_config(dev, PCIR_MAXLAT, 0x14, 1); } static struct pci_devinfo * cardbus_alloc_devinfo(device_t dev) { struct cardbus_devinfo *dinfo; dinfo = malloc(sizeof(*dinfo), M_DEVBUF, M_WAITOK | M_ZERO); return (&dinfo->pci); } static int cardbus_attach_card(device_t cbdev) { device_t brdev = device_get_parent(cbdev); device_t child; int bus, domain, slot, func; int cardattached = 0; int cardbusfunchigh = 0; struct cardbus_softc *sc; sc = device_get_softc(cbdev); cardbus_detach_card(cbdev); /* detach existing cards */ POWER_DISABLE_SOCKET(brdev, cbdev); /* Turn the socket off first */ POWER_ENABLE_SOCKET(brdev, cbdev); domain = pcib_get_domain(cbdev); bus = pcib_get_bus(cbdev); slot = 0; mtx_lock(&Giant); /* For each function, set it up and try to attach a driver to it */ for (func = 0; func <= cardbusfunchigh; func++) { struct cardbus_devinfo *dinfo; dinfo = (struct cardbus_devinfo *) pci_read_device(brdev, cbdev, domain, bus, slot, func); if (dinfo == NULL) continue; if (dinfo->pci.cfg.mfdev) cardbusfunchigh = PCI_FUNCMAX; child = device_add_child(cbdev, NULL, -1); if (child == NULL) { DEVPRINTF((cbdev, "Cannot add child!\n")); pci_freecfg((struct pci_devinfo *)dinfo); continue; } dinfo->pci.cfg.dev = child; resource_list_init(&dinfo->pci.resources); device_set_ivars(child, dinfo); cardbus_device_create(sc, dinfo, cbdev, child); if (cardbus_do_cis(cbdev, child) != 0) DEVPRINTF((cbdev, "Warning: Bogus CIS ignored\n")); pci_cfg_save(dinfo->pci.cfg.dev, &dinfo->pci, 0); pci_cfg_restore(dinfo->pci.cfg.dev, &dinfo->pci); cardbus_device_setup_regs(&dinfo->pci.cfg); pci_add_resources(cbdev, child, 1, dinfo->mprefetchable); pci_print_verbose(&dinfo->pci); if (device_probe_and_attach(child) == 0) cardattached++; else pci_cfg_save(dinfo->pci.cfg.dev, &dinfo->pci, 1); } mtx_unlock(&Giant); if (cardattached > 0) return (0); /* POWER_DISABLE_SOCKET(brdev, cbdev); */ return (ENOENT); } static void cardbus_child_deleted(device_t cbdev, device_t child) { struct cardbus_devinfo *dinfo = device_get_ivars(child); if (dinfo->pci.cfg.dev != child) device_printf(cbdev, "devinfo dev mismatch\n"); cardbus_device_destroy(dinfo); pci_child_deleted(cbdev, child); } static int cardbus_detach_card(device_t cbdev) { int err = 0; err = bus_generic_detach(cbdev); if (err) return (err); err = device_delete_children(cbdev); if (err) return (err); POWER_DISABLE_SOCKET(device_get_parent(cbdev), cbdev); return (err); } static void cardbus_driver_added(device_t cbdev, driver_t *driver) { int numdevs; device_t *devlist; device_t dev; int i; struct cardbus_devinfo *dinfo; DEVICE_IDENTIFY(driver, cbdev); if (device_get_children(cbdev, &devlist, &numdevs) != 0) return; /* * If there are no drivers attached, but there are children, * then power the card up. */ for (i = 0; i < numdevs; i++) { dev = devlist[i]; if (device_get_state(dev) != DS_NOTPRESENT) break; } if (i > 0 && i == numdevs) POWER_ENABLE_SOCKET(device_get_parent(cbdev), cbdev); for (i = 0; i < numdevs; i++) { dev = devlist[i]; if (device_get_state(dev) != DS_NOTPRESENT) continue; dinfo = device_get_ivars(dev); pci_print_verbose(&dinfo->pci); if (bootverbose) printf("pci%d:%d:%d:%d: reprobing on driver added\n", dinfo->pci.cfg.domain, dinfo->pci.cfg.bus, dinfo->pci.cfg.slot, dinfo->pci.cfg.func); pci_cfg_restore(dinfo->pci.cfg.dev, &dinfo->pci); if (device_probe_and_attach(dev) != 0) pci_cfg_save(dev, &dinfo->pci, 1); } free(devlist, M_TEMP); } /************************************************************************/ /* Other Bus Methods */ /************************************************************************/ static int cardbus_read_ivar(device_t cbdev, device_t child, int which, uintptr_t *result) { struct cardbus_devinfo *dinfo; pcicfgregs *cfg; dinfo = device_get_ivars(child); cfg = &dinfo->pci.cfg; switch (which) { case PCI_IVAR_ETHADDR: /* * The generic accessor doesn't deal with failure, so * we set the return value, then return an error. */ if (dinfo->fepresent & (1 << PCCARD_TPLFE_TYPE_LAN_NID)) { *((uint8_t **) result) = dinfo->funce.lan.nid; break; } *((uint8_t **) result) = NULL; return (EINVAL); default: return (pci_read_ivar(cbdev, child, which, result)); } return 0; } static device_method_t cardbus_methods[] = { /* Device interface */ DEVMETHOD(device_probe, cardbus_probe), DEVMETHOD(device_attach, cardbus_attach), DEVMETHOD(device_detach, cardbus_detach), DEVMETHOD(device_suspend, cardbus_suspend), DEVMETHOD(device_resume, cardbus_resume), /* Bus interface */ DEVMETHOD(bus_child_deleted, cardbus_child_deleted), DEVMETHOD(bus_get_dma_tag, bus_generic_get_dma_tag), DEVMETHOD(bus_read_ivar, cardbus_read_ivar), DEVMETHOD(bus_driver_added, cardbus_driver_added), DEVMETHOD(bus_rescan, bus_null_rescan), /* Card Interface */ DEVMETHOD(card_attach_card, cardbus_attach_card), DEVMETHOD(card_detach_card, cardbus_detach_card), /* PCI interface */ DEVMETHOD(pci_alloc_devinfo, cardbus_alloc_devinfo), {0,0} }; DEFINE_CLASS_1(cardbus, cardbus_driver, cardbus_methods, sizeof(struct cardbus_softc), pci_driver); static devclass_t cardbus_devclass; DRIVER_MODULE(cardbus, cbb, cardbus_driver, cardbus_devclass, 0, 0); MODULE_VERSION(cardbus, 1); Index: head/sys/dev/cardbus/cardbus_cis.c =================================================================== --- head/sys/dev/cardbus/cardbus_cis.c (revision 355393) +++ head/sys/dev/cardbus/cardbus_cis.c (revision 355394) @@ -1,661 +1,661 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2005-2008, M. Warner Losh - * Copyright (c) 2000,2001 Jonathan Chen. - * All rights reserved. + * Copyright (c) 2000,2001 Jonathan Chen All rights reserved. + * Copyright (c) 2005-2008 M. Warner Losh + * * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /* * CIS Handling for the Cardbus Bus */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include extern int cardbus_cis_debug; #define DPRINTF(a) if (cardbus_cis_debug) printf a #define DEVPRINTF(x) if (cardbus_cis_debug) device_printf x #define CIS_CONFIG_SPACE (struct resource *)~0UL static int decode_tuple_generic(device_t cbdev, device_t child, int id, int len, uint8_t *tupledata, uint32_t start, uint32_t *off, struct tuple_callbacks *info, void *); static int decode_tuple_linktarget(device_t cbdev, device_t child, int id, int len, uint8_t *tupledata, uint32_t start, uint32_t *off, struct tuple_callbacks *info, void *); static int decode_tuple_vers_1(device_t cbdev, device_t child, int id, int len, uint8_t *tupledata, uint32_t start, uint32_t *off, struct tuple_callbacks *info, void *); static int decode_tuple_funcid(device_t cbdev, device_t child, int id, int len, uint8_t *tupledata, uint32_t start, uint32_t *off, struct tuple_callbacks *info, void *); static int decode_tuple_manfid(device_t cbdev, device_t child, int id, int len, uint8_t *tupledata, uint32_t start, uint32_t *off, struct tuple_callbacks *info, void *); static int decode_tuple_funce(device_t cbdev, device_t child, int id, int len, uint8_t *tupledata, uint32_t start, uint32_t *off, struct tuple_callbacks *info, void *); static int decode_tuple_bar(device_t cbdev, device_t child, int id, int len, uint8_t *tupledata, uint32_t start, uint32_t *off, struct tuple_callbacks *info, void *); static int decode_tuple_unhandled(device_t cbdev, device_t child, int id, int len, uint8_t *tupledata, uint32_t start, uint32_t *off, struct tuple_callbacks *info, void *); static int decode_tuple_end(device_t cbdev, device_t child, int id, int len, uint8_t *tupledata, uint32_t start, uint32_t *off, struct tuple_callbacks *info, void *); static int cardbus_read_tuple_conf(device_t cbdev, device_t child, uint32_t start, uint32_t *off, int *tupleid, int *len, uint8_t *tupledata); static int cardbus_read_tuple_mem(device_t cbdev, struct resource *res, uint32_t start, uint32_t *off, int *tupleid, int *len, uint8_t *tupledata); static int cardbus_read_tuple(device_t cbdev, device_t child, struct resource *res, uint32_t start, uint32_t *off, int *tupleid, int *len, uint8_t *tupledata); static void cardbus_read_tuple_finish(device_t cbdev, device_t child, int rid, struct resource *res); static struct resource *cardbus_read_tuple_init(device_t cbdev, device_t child, uint32_t *start, int *rid); static int decode_tuple(device_t cbdev, device_t child, int tupleid, int len, uint8_t *tupledata, uint32_t start, uint32_t *off, struct tuple_callbacks *callbacks, void *); #define MAKETUPLE(NAME,FUNC) { CISTPL_ ## NAME, #NAME, decode_tuple_ ## FUNC } static char *funcnames[] = { "Multi-Functioned", "Memory", "Serial Port", "Parallel Port", "Fixed Disk", "Video Adaptor", "Network Adaptor", "AIMS", "SCSI", "Security" }; /* * Handler functions for various CIS tuples */ static int decode_tuple_generic(device_t cbdev, device_t child, int id, int len, uint8_t *tupledata, uint32_t start, uint32_t *off, struct tuple_callbacks *info, void *argp) { int i; if (cardbus_cis_debug) { if (info) printf("TUPLE: %s [%d]:", info->name, len); else printf("TUPLE: Unknown(0x%02x) [%d]:", id, len); for (i = 0; i < len; i++) { if (i % 0x10 == 0 && len > 0x10) printf("\n 0x%02x:", i); printf(" %02x", tupledata[i]); } printf("\n"); } return (0); } static int decode_tuple_linktarget(device_t cbdev, device_t child, int id, int len, uint8_t *tupledata, uint32_t start, uint32_t *off, struct tuple_callbacks *info, void *argp) { int i; if (cardbus_cis_debug) { printf("TUPLE: %s [%d]:", info->name, len); for (i = 0; i < len; i++) { if (i % 0x10 == 0 && len > 0x10) printf("\n 0x%02x:", i); printf(" %02x", tupledata[i]); } printf("\n"); } if (len != 3 || tupledata[0] != 'C' || tupledata[1] != 'I' || tupledata[2] != 'S') { printf("Invalid data for CIS Link Target!\n"); decode_tuple_generic(cbdev, child, id, len, tupledata, start, off, info, argp); return (EINVAL); } return (0); } static int decode_tuple_vers_1(device_t cbdev, device_t child, int id, int len, uint8_t *tupledata, uint32_t start, uint32_t *off, struct tuple_callbacks *info, void *argp) { int i; if (cardbus_cis_debug) { printf("Product version: %d.%d\n", tupledata[0], tupledata[1]); printf("Product name: "); for (i = 2; i < len; i++) { if (tupledata[i] == '\0') printf(" | "); else if (tupledata[i] == 0xff) break; else printf("%c", tupledata[i]); } printf("\n"); } return (0); } static int decode_tuple_funcid(device_t cbdev, device_t child, int id, int len, uint8_t *tupledata, uint32_t start, uint32_t *off, struct tuple_callbacks *info, void *argp) { struct cardbus_devinfo *dinfo = device_get_ivars(child); int numnames = nitems(funcnames); int i; if (cardbus_cis_debug) { printf("Functions: "); for (i = 0; i < len; i++) { if (tupledata[i] < numnames) printf("%s", funcnames[tupledata[i]]); else printf("Unknown(%d)", tupledata[i]); if (i < len - 1) printf(", "); } printf("\n"); } if (len > 0) dinfo->funcid = tupledata[0]; /* use first in list */ return (0); } static int decode_tuple_manfid(device_t cbdev, device_t child, int id, int len, uint8_t *tupledata, uint32_t start, uint32_t *off, struct tuple_callbacks *info, void *argp) { struct cardbus_devinfo *dinfo = device_get_ivars(child); int i; if (cardbus_cis_debug) { printf("Manufacturer ID: "); for (i = 0; i < len; i++) printf("%02x", tupledata[i]); printf("\n"); } if (len == 5) { dinfo->mfrid = tupledata[1] | (tupledata[2] << 8); dinfo->prodid = tupledata[3] | (tupledata[4] << 8); } return (0); } static int decode_tuple_funce(device_t cbdev, device_t child, int id, int len, uint8_t *tupledata, uint32_t start, uint32_t *off, struct tuple_callbacks *info, void *argp) { struct cardbus_devinfo *dinfo = device_get_ivars(child); int type, i; if (cardbus_cis_debug) { printf("Function Extension: "); for (i = 0; i < len; i++) printf("%02x", tupledata[i]); printf("\n"); } if (len < 2) /* too short */ return (0); type = tupledata[0]; /* XXX <32 always? */ switch (dinfo->funcid) { case PCCARD_FUNCTION_NETWORK: switch (type) { case PCCARD_TPLFE_TYPE_LAN_NID: if (tupledata[1] > sizeof(dinfo->funce.lan.nid)) { /* ignore, warning? */ return (0); } bcopy(tupledata + 2, dinfo->funce.lan.nid, tupledata[1]); break; } dinfo->fepresent |= 1<mprefetchable |= (1 << PCI_RID2BAR(bar)); /* * The PC Card spec says we're only supposed to honor this * hint when the cardbus bridge is a child of pci0 (the main * bus). The PC Card spec seems to indicate that this should * only be done on x86 based machines, which suggests that on * non-x86 machines the addresses can be anywhere. Since the * hardware can do it on non-x86 machines, it should be able * to do it on x86 machines too. Therefore, we can and should * ignore this hint. Furthermore, the PC Card spec recommends * always allocating memory above 1MB, contradicting the other * part of the PC Card spec, it seems. We make note of it, * but otherwise don't use this information. * * Some Realtek cards have this set in their CIS, but fail * to actually work when mapped this way, and experience * has shown ignoring this big to be a wise choice. * * XXX We should cite chapter and verse for standard refs. */ if (reg & TPL_BAR_REG_BELOW1MB) dinfo->mbelow1mb |= (1 << PCI_RID2BAR(bar)); } return (0); } static int decode_tuple_unhandled(device_t cbdev, device_t child, int id, int len, uint8_t *tupledata, uint32_t start, uint32_t *off, struct tuple_callbacks *info, void *argp) { /* Make this message suck less XXX */ printf("TUPLE: %s [%d] is unhandled! Bailing...", info->name, len); return (EINVAL); } static int decode_tuple_end(device_t cbdev, device_t child, int id, int len, uint8_t *tupledata, uint32_t start, uint32_t *off, struct tuple_callbacks *info, void *argp) { if (cardbus_cis_debug) printf("CIS reading done\n"); return (0); } /* * Functions to read the a tuple from the card */ /* * Read CIS bytes out of the config space. We have to read it 4 bytes at a * time and do the usual mask and shift to return the bytes. The standard * defines the byte order to be little endian. pci_read_config converts it to * host byte order. This is why we have no endian conversion functions: the * shifts wind up being endian neutral. This is also why we avoid the obvious * memcpy optimization. */ static int cardbus_read_tuple_conf(device_t cbdev, device_t child, uint32_t start, uint32_t *off, int *tupleid, int *len, uint8_t *tupledata) { int i, j; uint32_t e; uint32_t loc; loc = start + *off; e = pci_read_config(child, loc & ~0x3, 4); e >>= 8 * (loc & 0x3); *len = 0; for (i = loc, j = -2; j < *len; j++, i++) { if ((i & 0x3) == 0) e = pci_read_config(child, i, 4); if (j == -2) *tupleid = 0xff & e; else if (j == -1) *len = 0xff & e; else tupledata[j] = 0xff & e; e >>= 8; } *off += *len + 2; return (0); } /* * Read the CIS data out of memory. We indirect through the bus space * routines to ensure proper byte ordering conversions when necessary. */ static int cardbus_read_tuple_mem(device_t cbdev, struct resource *res, uint32_t start, uint32_t *off, int *tupleid, int *len, uint8_t *tupledata) { int ret; *tupleid = bus_read_1(res, start + *off); *len = bus_read_1(res, start + *off + 1); bus_read_region_1(res, *off + start + 2, tupledata, *len); ret = 0; *off += *len + 2; return (ret); } static int cardbus_read_tuple(device_t cbdev, device_t child, struct resource *res, uint32_t start, uint32_t *off, int *tupleid, int *len, uint8_t *tupledata) { if (res == CIS_CONFIG_SPACE) return (cardbus_read_tuple_conf(cbdev, child, start, off, tupleid, len, tupledata)); return (cardbus_read_tuple_mem(cbdev, res, start, off, tupleid, len, tupledata)); } static void cardbus_read_tuple_finish(device_t cbdev, device_t child, int rid, struct resource *res) { if (res != CIS_CONFIG_SPACE) { bus_release_resource(child, SYS_RES_MEMORY, rid, res); bus_delete_resource(child, SYS_RES_MEMORY, rid); } } static struct resource * cardbus_read_tuple_init(device_t cbdev, device_t child, uint32_t *start, int *rid) { struct resource *res; uint32_t space; space = *start & PCIM_CIS_ASI_MASK; switch (space) { case PCIM_CIS_ASI_CONFIG: DEVPRINTF((cbdev, "CIS in PCI config space\n")); /* CIS in PCI config space need no initialization */ return (CIS_CONFIG_SPACE); case PCIM_CIS_ASI_BAR0: case PCIM_CIS_ASI_BAR1: case PCIM_CIS_ASI_BAR2: case PCIM_CIS_ASI_BAR3: case PCIM_CIS_ASI_BAR4: case PCIM_CIS_ASI_BAR5: *rid = PCIR_BAR(space - PCIM_CIS_ASI_BAR0); DEVPRINTF((cbdev, "CIS in BAR %#x\n", *rid)); break; case PCIM_CIS_ASI_ROM: *rid = PCIR_BIOS; DEVPRINTF((cbdev, "CIS in option rom\n")); break; default: device_printf(cbdev, "Unable to read CIS: Unknown space: %d\n", space); return (NULL); } /* allocate the memory space to read CIS */ res = bus_alloc_resource_any(child, SYS_RES_MEMORY, rid, rman_make_alignment_flags(4096) | RF_ACTIVE); if (res == NULL) { device_printf(cbdev, "Unable to allocate resource " "to read CIS.\n"); return (NULL); } DEVPRINTF((cbdev, "CIS Mapped to %#jx\n", rman_get_start(res))); /* Flip to the right ROM image if CIS is in ROM */ if (space == PCIM_CIS_ASI_ROM) { uint32_t imagesize; uint32_t imagebase = 0; uint32_t pcidata; uint16_t romsig; int romnum = 0; int imagenum; imagenum = (*start & PCIM_CIS_ROM_MASK) >> 28; for (romnum = 0;; romnum++) { romsig = bus_read_2(res, imagebase + CARDBUS_EXROM_SIGNATURE); if (romsig != 0xaa55) { device_printf(cbdev, "Bad header in rom %d: " "[%x] %04x\n", romnum, imagebase + CARDBUS_EXROM_SIGNATURE, romsig); cardbus_read_tuple_finish(cbdev, child, *rid, res); *rid = 0; return (NULL); } /* * If this was the Option ROM image that we were * looking for, then we are done. */ if (romnum == imagenum) break; /* Find out where the next Option ROM image is */ pcidata = imagebase + bus_read_2(res, imagebase + CARDBUS_EXROM_DATA_PTR); imagesize = bus_read_2(res, pcidata + CARDBUS_EXROM_DATA_IMAGE_LENGTH); if (imagesize == 0) { /* * XXX some ROMs seem to have this as zero, * can we assume this means 1 block? */ device_printf(cbdev, "Warning, size of Option " "ROM image %d is 0 bytes, assuming 512 " "bytes.\n", romnum); imagesize = 1; } /* Image size is in 512 byte units */ imagesize <<= 9; if ((bus_read_1(res, pcidata + CARDBUS_EXROM_DATA_INDICATOR) & 0x80) != 0) { device_printf(cbdev, "Cannot find CIS in " "Option ROM\n"); cardbus_read_tuple_finish(cbdev, child, *rid, res); *rid = 0; return (NULL); } imagebase += imagesize; } *start = imagebase + (*start & PCIM_CIS_ADDR_MASK); } else { *start = *start & PCIM_CIS_ADDR_MASK; } DEVPRINTF((cbdev, "CIS offset is %#x\n", *start)); return (res); } /* * Dispatch the right handler function per tuple */ static int decode_tuple(device_t cbdev, device_t child, int tupleid, int len, uint8_t *tupledata, uint32_t start, uint32_t *off, struct tuple_callbacks *callbacks, void *argp) { int i; for (i = 0; callbacks[i].id != CISTPL_GENERIC; i++) { if (tupleid == callbacks[i].id) return (callbacks[i].func(cbdev, child, tupleid, len, tupledata, start, off, &callbacks[i], argp)); } return (callbacks[i].func(cbdev, child, tupleid, len, tupledata, start, off, NULL, argp)); } int cardbus_parse_cis(device_t cbdev, device_t child, struct tuple_callbacks *callbacks, void *argp) { uint8_t *tupledata; int tupleid = CISTPL_NULL; int len; int expect_linktarget; uint32_t start, off; struct resource *res; int rid; tupledata = malloc(MAXTUPLESIZE, M_DEVBUF, M_WAITOK | M_ZERO); expect_linktarget = TRUE; if ((start = pci_read_config(child, PCIR_CIS, 4)) == 0) { DEVPRINTF((cbdev, "Warning: CIS pointer is 0: (no CIS)\n")); free(tupledata, M_DEVBUF); return (0); } DEVPRINTF((cbdev, "CIS pointer is %#x\n", start)); off = 0; res = cardbus_read_tuple_init(cbdev, child, &start, &rid); if (res == NULL) { device_printf(cbdev, "Unable to allocate resources for CIS\n"); free(tupledata, M_DEVBUF); return (ENXIO); } do { if (cardbus_read_tuple(cbdev, child, res, start, &off, &tupleid, &len, tupledata) != 0) { device_printf(cbdev, "Failed to read CIS.\n"); cardbus_read_tuple_finish(cbdev, child, rid, res); free(tupledata, M_DEVBUF); return (ENXIO); } if (expect_linktarget && tupleid != CISTPL_LINKTARGET) { device_printf(cbdev, "Expecting link target, got 0x%x\n", tupleid); cardbus_read_tuple_finish(cbdev, child, rid, res); free(tupledata, M_DEVBUF); return (EINVAL); } expect_linktarget = decode_tuple(cbdev, child, tupleid, len, tupledata, start, &off, callbacks, argp); if (expect_linktarget != 0) { device_printf(cbdev, "Parsing failed with %d\n", expect_linktarget); cardbus_read_tuple_finish(cbdev, child, rid, res); free(tupledata, M_DEVBUF); return (expect_linktarget); } } while (tupleid != CISTPL_END); cardbus_read_tuple_finish(cbdev, child, rid, res); free(tupledata, M_DEVBUF); return (0); } int cardbus_do_cis(device_t cbdev, device_t child) { struct tuple_callbacks init_callbacks[] = { MAKETUPLE(LONGLINK_CB, unhandled), MAKETUPLE(INDIRECT, unhandled), MAKETUPLE(LONGLINK_MFC, unhandled), MAKETUPLE(BAR, bar), MAKETUPLE(LONGLINK_A, unhandled), MAKETUPLE(LONGLINK_C, unhandled), MAKETUPLE(LINKTARGET, linktarget), MAKETUPLE(VERS_1, vers_1), MAKETUPLE(MANFID, manfid), MAKETUPLE(FUNCID, funcid), MAKETUPLE(FUNCE, funce), MAKETUPLE(END, end), MAKETUPLE(GENERIC, generic), }; return (cardbus_parse_cis(cbdev, child, init_callbacks, NULL)); } Index: head/sys/dev/cardbus/cardbus_device.c =================================================================== --- head/sys/dev/cardbus/cardbus_device.c (revision 355393) +++ head/sys/dev/cardbus/cardbus_device.c (revision 355394) @@ -1,168 +1,167 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2005-2008, M. Warner Losh - * All rights reserved. + * Copyright (c) 2005-2008 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice unmodified, this list of conditions, and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static d_open_t cardbus_open; static d_close_t cardbus_close; static d_read_t cardbus_read; static d_ioctl_t cardbus_ioctl; static struct cdevsw cardbus_cdevsw = { .d_version = D_VERSION, .d_open = cardbus_open, .d_close = cardbus_close, .d_read = cardbus_read, .d_ioctl = cardbus_ioctl, .d_name = "cardbus" }; static int cardbus_build_cis(device_t cbdev, device_t child, int id, int len, uint8_t *tupledata, uint32_t start, uint32_t *off, struct tuple_callbacks *info, void *argp) { struct cis_buffer *cis; int i; cis = (struct cis_buffer *)argp; /* * CISTPL_END is a special case, it has no length field. */ if (id == CISTPL_END) { if (cis->len + 1 > sizeof(cis->buffer)) { cis->len = 0; return (ENOSPC); } cis->buffer[cis->len++] = id; return (0); } if (cis->len + 2 + len > sizeof(cis->buffer)) { cis->len = 0; return (ENOSPC); } cis->buffer[cis->len++] = id; cis->buffer[cis->len++] = len; for (i = 0; i < len; i++) cis->buffer[cis->len++] = tupledata[i]; return (0); } static int cardbus_device_buffer_cis(device_t parent, device_t child, struct cis_buffer *cbp) { struct tuple_callbacks cb[] = { {CISTPL_GENERIC, "GENERIC", cardbus_build_cis} }; return (cardbus_parse_cis(parent, child, cb, cbp)); } int cardbus_device_create(struct cardbus_softc *sc, struct cardbus_devinfo *devi, device_t parent, device_t child) { uint32_t minor; int unit; cardbus_device_buffer_cis(parent, child, &devi->sc_cis); minor = (device_get_unit(sc->sc_dev) << 8) + devi->pci.cfg.func; unit = device_get_unit(sc->sc_dev); devi->sc_cisdev = make_dev(&cardbus_cdevsw, minor, 0, 0, 0666, "cardbus%d.%d.cis", unit, devi->pci.cfg.func); if (devi->pci.cfg.func == 0) make_dev_alias(devi->sc_cisdev, "cardbus%d.cis", unit); devi->sc_cisdev->si_drv1 = devi; return (0); } int cardbus_device_destroy(struct cardbus_devinfo *devi) { if (devi->sc_cisdev) destroy_dev(devi->sc_cisdev); return (0); } static int cardbus_open(struct cdev *dev, int oflags, int devtype, struct thread *td) { return (0); } static int cardbus_close(struct cdev *dev, int fflags, int devtype, struct thread *td) { return (0); } static int cardbus_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread *td) { return (ENOTTY); } static int cardbus_read(struct cdev *dev, struct uio *uio, int ioflag) { struct cardbus_devinfo *devi; devi = dev->si_drv1; /* EOF */ if (uio->uio_offset >= devi->sc_cis.len) return (0); return (uiomove(devi->sc_cis.buffer + uio->uio_offset, MIN(uio->uio_resid, devi->sc_cis.len - uio->uio_offset), uio)); } Index: head/sys/dev/cardbus/cardbusvar.h =================================================================== --- head/sys/dev/cardbus/cardbusvar.h (revision 355393) +++ head/sys/dev/cardbus/cardbusvar.h (revision 355394) @@ -1,96 +1,95 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2008, M. Warner Losh - * Copyright (c) 2000,2001 Jonathan Chen. - * All rights reserved. + * Copyright (c) 2000,2001 Jonathan Chen. All rights reserved. + * Copyright (c) 2008 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ /* * Structure definitions for the Cardbus Bus driver */ /* * Static copy of the CIS buffer. Technically, you aren't supposed * to do this. In practice, however, it works well. */ struct cis_buffer { size_t len; /* Actual length of the CIS */ uint8_t buffer[2040]; /* small enough to be 2k */ }; /* * Per child information for the PCI device. Cardbus layers on some * additional data. */ struct cardbus_devinfo { struct pci_devinfo pci; uint8_t mprefetchable; /* bit mask of prefetchable BARs */ uint8_t mbelow1mb; /* bit mask of BARs which require below 1Mb */ uint16_t mfrid; /* manufacturer id */ uint16_t prodid; /* product id */ u_int funcid; /* function id */ union { struct { uint8_t nid[6]; /* MAC address */ } lan; } funce; uint32_t fepresent; /* bit mask of funce values present */ struct cdev *sc_cisdev; struct cis_buffer sc_cis; }; /* * Per cardbus soft info. Not sure why we even keep this around... */ struct cardbus_softc { device_t sc_dev; #ifdef PCI_RES_BUS struct resource *sc_bus; #endif }; /* * Per node callback structures. */ struct tuple_callbacks; typedef int (tuple_cb) (device_t cbdev, device_t child, int id, int len, uint8_t *tupledata, uint32_t start, uint32_t *off, struct tuple_callbacks *info, void *); struct tuple_callbacks { int id; char *name; tuple_cb *func; }; int cardbus_device_create(struct cardbus_softc *sc, struct cardbus_devinfo *devi, device_t parent, device_t child); int cardbus_device_destroy(struct cardbus_devinfo *devi); int cardbus_parse_cis(device_t cbdev, device_t child, struct tuple_callbacks *callbacks, void *); Index: head/sys/dev/exca/exca.c =================================================================== --- head/sys/dev/exca/exca.c (revision 355393) +++ head/sys/dev/exca/exca.c (revision 355394) @@ -1,929 +1,929 @@ /*- * SPDX-License-Identifier: BSD-4-Clause AND BSD-2-Clause-FreeBSD * - * Copyright (c) 2002-2005 M. Warner Losh. + * Copyright (c) 2002-2005 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * This software may be derived from NetBSD i82365.c and other files with * the following copyright: * * Copyright (c) 1997 Marc Horowitz. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Marc Horowitz. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef EXCA_DEBUG #define DEVPRINTF(dev, fmt, args...) device_printf((dev), (fmt), ## args) #define DPRINTF(fmt, args...) printf(fmt, ## args) #else #define DEVPRINTF(dev, fmt, args...) #define DPRINTF(fmt, args...) #endif static const char *chip_names[] = { "CardBus socket", "Intel i82365SL-A/B or clone", "Intel i82365sl-DF step", "VLSI chip", "Cirrus Logic PD6710", "Cirrus logic PD6722", "Cirrus Logic PD6729", "Vadem 365", "Vadem 465", "Vadem 468", "Vadem 469", "Ricoh RF5C296", "Ricoh RF5C396", "IBM clone", "IBM KING PCMCIA Controller" }; static exca_getb_fn exca_mem_getb; static exca_putb_fn exca_mem_putb; static exca_getb_fn exca_io_getb; static exca_putb_fn exca_io_putb; /* memory */ #define EXCA_MEMINFO(NUM) { \ EXCA_SYSMEM_ADDR ## NUM ## _START_LSB, \ EXCA_SYSMEM_ADDR ## NUM ## _START_MSB, \ EXCA_SYSMEM_ADDR ## NUM ## _STOP_LSB, \ EXCA_SYSMEM_ADDR ## NUM ## _STOP_MSB, \ EXCA_SYSMEM_ADDR ## NUM ## _WIN, \ EXCA_CARDMEM_ADDR ## NUM ## _LSB, \ EXCA_CARDMEM_ADDR ## NUM ## _MSB, \ EXCA_ADDRWIN_ENABLE_MEM ## NUM, \ } static struct mem_map_index_st { int sysmem_start_lsb; int sysmem_start_msb; int sysmem_stop_lsb; int sysmem_stop_msb; int sysmem_win; int cardmem_lsb; int cardmem_msb; int memenable; } mem_map_index[] = { EXCA_MEMINFO(0), EXCA_MEMINFO(1), EXCA_MEMINFO(2), EXCA_MEMINFO(3), EXCA_MEMINFO(4) }; #undef EXCA_MEMINFO static uint8_t exca_mem_getb(struct exca_softc *sc, int reg) { return (bus_space_read_1(sc->bst, sc->bsh, sc->offset + reg)); } static void exca_mem_putb(struct exca_softc *sc, int reg, uint8_t val) { bus_space_write_1(sc->bst, sc->bsh, sc->offset + reg, val); } static uint8_t exca_io_getb(struct exca_softc *sc, int reg) { bus_space_write_1(sc->bst, sc->bsh, EXCA_REG_INDEX, reg + sc->offset); return (bus_space_read_1(sc->bst, sc->bsh, EXCA_REG_DATA)); } static void exca_io_putb(struct exca_softc *sc, int reg, uint8_t val) { bus_space_write_1(sc->bst, sc->bsh, EXCA_REG_INDEX, reg + sc->offset); bus_space_write_1(sc->bst, sc->bsh, EXCA_REG_DATA, val); } /* * Helper function. This will map the requested memory slot. We setup the * map before we call this function. This is used to initially force the * mapping, as well as later restore the mapping after it has been destroyed * in some fashion (due to a power event typically). */ static void exca_do_mem_map(struct exca_softc *sc, int win) { struct mem_map_index_st *map; struct pccard_mem_handle *mem; uint32_t offset; uint32_t mem16; uint32_t attrmem; map = &mem_map_index[win]; mem = &sc->mem[win]; mem16 = (mem->kind & PCCARD_MEM_16BIT) ? EXCA_SYSMEM_ADDRX_START_MSB_DATASIZE_16BIT : 0; attrmem = (mem->kind & PCCARD_MEM_ATTR) ? EXCA_CARDMEM_ADDRX_MSB_REGACTIVE_ATTR : 0; offset = ((mem->cardaddr >> EXCA_CARDMEM_ADDRX_SHIFT) - (mem->addr >> EXCA_SYSMEM_ADDRX_SHIFT)) & 0x3fff; exca_putb(sc, map->sysmem_start_lsb, mem->addr >> EXCA_SYSMEM_ADDRX_SHIFT); exca_putb(sc, map->sysmem_start_msb, ((mem->addr >> (EXCA_SYSMEM_ADDRX_SHIFT + 8)) & EXCA_SYSMEM_ADDRX_START_MSB_ADDR_MASK) | mem16); exca_putb(sc, map->sysmem_stop_lsb, (mem->addr + mem->realsize - 1) >> EXCA_SYSMEM_ADDRX_SHIFT); exca_putb(sc, map->sysmem_stop_msb, (((mem->addr + mem->realsize - 1) >> (EXCA_SYSMEM_ADDRX_SHIFT + 8)) & EXCA_SYSMEM_ADDRX_STOP_MSB_ADDR_MASK) | EXCA_SYSMEM_ADDRX_STOP_MSB_WAIT2); exca_putb(sc, map->sysmem_win, mem->addr >> EXCA_MEMREG_WIN_SHIFT); exca_putb(sc, map->cardmem_lsb, offset & 0xff); exca_putb(sc, map->cardmem_msb, ((offset >> 8) & EXCA_CARDMEM_ADDRX_MSB_ADDR_MASK) | attrmem); DPRINTF("%s %d-bit memory", mem->kind & PCCARD_MEM_ATTR ? "attribute" : "common", mem->kind & PCCARD_MEM_16BIT ? 16 : 8); exca_setb(sc, EXCA_ADDRWIN_ENABLE, map->memenable | EXCA_ADDRWIN_ENABLE_MEMCS16); DELAY(100); #ifdef EXCA_DEBUG { int r1, r2, r3, r4, r5, r6, r7; r1 = exca_getb(sc, map->sysmem_start_msb); r2 = exca_getb(sc, map->sysmem_start_lsb); r3 = exca_getb(sc, map->sysmem_stop_msb); r4 = exca_getb(sc, map->sysmem_stop_lsb); r5 = exca_getb(sc, map->cardmem_msb); r6 = exca_getb(sc, map->cardmem_lsb); r7 = exca_getb(sc, map->sysmem_win); printf("exca_do_mem_map win %d: %#02x%#02x %#02x%#02x " "%#02x%#02x %#02x (%#08x+%#06x.%#06x*%#06x) flags %#x\n", win, r1, r2, r3, r4, r5, r6, r7, mem->addr, mem->size, mem->realsize, mem->cardaddr, mem->kind); } #endif } /* * public interface to map a resource. kind is the type of memory to * map (either common or attribute). Memory created via this interface * starts out at card address 0. Since the only way to set this is * to set it on a struct resource after it has been mapped, we're safe * in maping this assumption. Note that resources can be remapped using * exca_do_mem_map so that's how the card address can be set later. */ int exca_mem_map(struct exca_softc *sc, int kind, struct resource *res) { int win; for (win = 0; win < EXCA_MEM_WINS; win++) { if ((sc->memalloc & (1 << win)) == 0) { sc->memalloc |= (1 << win); break; } } if (win >= EXCA_MEM_WINS) return (ENOSPC); if (sc->flags & EXCA_HAS_MEMREG_WIN) { #ifdef __LP64__ if (rman_get_start(res) >> (EXCA_MEMREG_WIN_SHIFT + 8) != 0) { device_printf(sc->dev, "Does not support mapping above 4GB."); return (EINVAL); } #endif } else { if (rman_get_start(res) >> EXCA_MEMREG_WIN_SHIFT != 0) { device_printf(sc->dev, "Does not support mapping above 16M."); return (EINVAL); } } sc->mem[win].cardaddr = 0; sc->mem[win].memt = rman_get_bustag(res); sc->mem[win].memh = rman_get_bushandle(res); sc->mem[win].addr = rman_get_start(res); sc->mem[win].size = rman_get_end(res) - sc->mem[win].addr + 1; sc->mem[win].realsize = sc->mem[win].size + EXCA_MEM_PAGESIZE - 1; sc->mem[win].realsize = sc->mem[win].realsize - (sc->mem[win].realsize % EXCA_MEM_PAGESIZE); sc->mem[win].kind = kind; DPRINTF("exca_mem_map window %d bus %x+%x card addr %x\n", win, sc->mem[win].addr, sc->mem[win].size, sc->mem[win].cardaddr); exca_do_mem_map(sc, win); return (0); } /* * Private helper function. This turns off a given memory map that is in * use. We do this by just clearing the enable bit in the pcic. If we needed * to make memory unmapping/mapping pairs faster, we would have to store * more state information about the pcic and then use that to intelligently * to the map/unmap. However, since we don't do that sort of thing often * (generally just at configure time), it isn't a case worth optimizing. */ static void exca_mem_unmap(struct exca_softc *sc, int window) { if (window < 0 || window >= EXCA_MEM_WINS) panic("exca_mem_unmap: window out of range"); exca_clrb(sc, EXCA_ADDRWIN_ENABLE, mem_map_index[window].memenable); sc->memalloc &= ~(1 << window); } /* * Find the map that we're using to hold the resource. This works well * so long as the client drivers don't do silly things like map the same * area mutliple times, or map both common and attribute memory at the * same time. This latter restriction is a bug. We likely should just * store a pointer to the res in the mem[x] data structure. */ static int exca_mem_findmap(struct exca_softc *sc, struct resource *res) { int win; for (win = 0; win < EXCA_MEM_WINS; win++) { if (sc->mem[win].memt == rman_get_bustag(res) && sc->mem[win].addr == rman_get_start(res) && sc->mem[win].size == rman_get_size(res)) return (win); } return (-1); } /* * Set the memory flag. This means that we are setting if the memory * is coming from attribute memory or from common memory on the card. * CIS entries are generally in attribute memory (although they can * reside in common memory). Generally, this is the only use for attribute * memory. However, some cards require their drivers to dance in both * common and/or attribute memory and this interface (and setting the * offset interface) exist for such cards. */ int exca_mem_set_flags(struct exca_softc *sc, struct resource *res, uint32_t flags) { int win; win = exca_mem_findmap(sc, res); if (win < 0) { device_printf(sc->dev, "set_res_flags: specified resource not active\n"); return (ENOENT); } switch (flags) { case PCCARD_A_MEM_ATTR: sc->mem[win].kind |= PCCARD_MEM_ATTR; break; case PCCARD_A_MEM_COM: sc->mem[win].kind &= ~PCCARD_MEM_ATTR; break; case PCCARD_A_MEM_16BIT: sc->mem[win].kind |= PCCARD_MEM_16BIT; break; case PCCARD_A_MEM_8BIT: sc->mem[win].kind &= ~PCCARD_MEM_16BIT; break; } exca_do_mem_map(sc, win); return (0); } /* * Given a resource, go ahead and unmap it if we can find it in the * resrouce list that's used. */ int exca_mem_unmap_res(struct exca_softc *sc, struct resource *res) { int win; win = exca_mem_findmap(sc, res); if (win < 0) return (ENOENT); exca_mem_unmap(sc, win); return (0); } /* * Set the offset of the memory. We use this for reading the CIS and * frobbing the pccard's pccard registers (CCR, etc). Some drivers * need to access arbitrary attribute and common memory during their * initialization and operation. */ int exca_mem_set_offset(struct exca_softc *sc, struct resource *res, uint32_t cardaddr, uint32_t *deltap) { int win; uint32_t delta; win = exca_mem_findmap(sc, res); if (win < 0) { device_printf(sc->dev, "set_memory_offset: specified resource not active\n"); return (ENOENT); } sc->mem[win].cardaddr = rounddown2(cardaddr, EXCA_MEM_PAGESIZE); delta = cardaddr % EXCA_MEM_PAGESIZE; if (deltap) *deltap = delta; sc->mem[win].realsize = sc->mem[win].size + delta + EXCA_MEM_PAGESIZE - 1; sc->mem[win].realsize = sc->mem[win].realsize - (sc->mem[win].realsize % EXCA_MEM_PAGESIZE); exca_do_mem_map(sc, win); return (0); } /* I/O */ #define EXCA_IOINFO(NUM) { \ EXCA_IOADDR ## NUM ## _START_LSB, \ EXCA_IOADDR ## NUM ## _START_MSB, \ EXCA_IOADDR ## NUM ## _STOP_LSB, \ EXCA_IOADDR ## NUM ## _STOP_MSB, \ EXCA_ADDRWIN_ENABLE_IO ## NUM, \ EXCA_IOCTL_IO ## NUM ## _WAITSTATE \ | EXCA_IOCTL_IO ## NUM ## _ZEROWAIT \ | EXCA_IOCTL_IO ## NUM ## _IOCS16SRC_MASK \ | EXCA_IOCTL_IO ## NUM ## _DATASIZE_MASK, \ { \ EXCA_IOCTL_IO ## NUM ## _IOCS16SRC_CARD, \ EXCA_IOCTL_IO ## NUM ## _IOCS16SRC_DATASIZE \ | EXCA_IOCTL_IO ## NUM ## _DATASIZE_8BIT, \ EXCA_IOCTL_IO ## NUM ## _IOCS16SRC_DATASIZE \ | EXCA_IOCTL_IO ## NUM ## _DATASIZE_16BIT, \ } \ } static struct io_map_index_st { int start_lsb; int start_msb; int stop_lsb; int stop_msb; int ioenable; int ioctlmask; int ioctlbits[3]; /* indexed by PCCARD_WIDTH_* */ } io_map_index[] = { EXCA_IOINFO(0), EXCA_IOINFO(1), }; #undef EXCA_IOINFO static void exca_do_io_map(struct exca_softc *sc, int win) { struct io_map_index_st *map; struct pccard_io_handle *io; map = &io_map_index[win]; io = &sc->io[win]; exca_putb(sc, map->start_lsb, io->addr & 0xff); exca_putb(sc, map->start_msb, (io->addr >> 8) & 0xff); exca_putb(sc, map->stop_lsb, (io->addr + io->size - 1) & 0xff); exca_putb(sc, map->stop_msb, ((io->addr + io->size - 1) >> 8) & 0xff); exca_clrb(sc, EXCA_IOCTL, map->ioctlmask); exca_setb(sc, EXCA_IOCTL, map->ioctlbits[io->width]); exca_setb(sc, EXCA_ADDRWIN_ENABLE, map->ioenable); #ifdef EXCA_DEBUG { int r1, r2, r3, r4; r1 = exca_getb(sc, map->start_msb); r2 = exca_getb(sc, map->start_lsb); r3 = exca_getb(sc, map->stop_msb); r4 = exca_getb(sc, map->stop_lsb); DPRINTF("exca_do_io_map window %d: %02x%02x %02x%02x " "(%08x+%08x)\n", win, r1, r2, r3, r4, io->addr, io->size); } #endif } int exca_io_map(struct exca_softc *sc, int width, struct resource *r) { int win; #ifdef EXCA_DEBUG static char *width_names[] = { "auto", "io8", "io16"}; #endif for (win=0; win < EXCA_IO_WINS; win++) { if ((sc->ioalloc & (1 << win)) == 0) { sc->ioalloc |= (1 << win); break; } } if (win >= EXCA_IO_WINS) return (ENOSPC); sc->io[win].iot = rman_get_bustag(r); sc->io[win].ioh = rman_get_bushandle(r); sc->io[win].addr = rman_get_start(r); sc->io[win].size = rman_get_end(r) - sc->io[win].addr + 1; sc->io[win].flags = 0; sc->io[win].width = width; DPRINTF("exca_io_map window %d %s port %x+%x\n", win, width_names[width], sc->io[win].addr, sc->io[win].size); exca_do_io_map(sc, win); return (0); } static void exca_io_unmap(struct exca_softc *sc, int window) { if (window >= EXCA_IO_WINS) panic("exca_io_unmap: window out of range"); exca_clrb(sc, EXCA_ADDRWIN_ENABLE, io_map_index[window].ioenable); sc->ioalloc &= ~(1 << window); sc->io[window].iot = 0; sc->io[window].ioh = 0; sc->io[window].addr = 0; sc->io[window].size = 0; sc->io[window].flags = 0; sc->io[window].width = 0; } static int exca_io_findmap(struct exca_softc *sc, struct resource *res) { int win; for (win = 0; win < EXCA_IO_WINS; win++) { if (sc->io[win].iot == rman_get_bustag(res) && sc->io[win].addr == rman_get_start(res) && sc->io[win].size == rman_get_size(res)) return (win); } return (-1); } int exca_io_unmap_res(struct exca_softc *sc, struct resource *res) { int win; win = exca_io_findmap(sc, res); if (win < 0) return (ENOENT); exca_io_unmap(sc, win); return (0); } /* Misc */ /* * If interrupts are enabled, then we should be able to just wait for * an interrupt routine to wake us up. Busy waiting shouldn't be * necessary. Sadly, not all legacy ISA cards support an interrupt * for the busy state transitions, at least according to their datasheets, * so we busy wait a while here.. */ static void exca_wait_ready(struct exca_softc *sc) { int i; DEVPRINTF(sc->dev, "exca_wait_ready: status 0x%02x\n", exca_getb(sc, EXCA_IF_STATUS)); for (i = 0; i < 10000; i++) { if (exca_getb(sc, EXCA_IF_STATUS) & EXCA_IF_STATUS_READY) return; DELAY(500); } device_printf(sc->dev, "ready never happened, status = %02x\n", exca_getb(sc, EXCA_IF_STATUS)); } /* * Reset the card. Ideally, we'd do a lot of this via interrupts. * However, many PC Cards will deassert the ready signal. This means * that they are asserting an interrupt. This makes it hard to * do anything but a busy wait here. One could argue that these * such cards are broken, or that the bridge that allows this sort * of interrupt through isn't quite what you'd want (and may be a standards * violation). However, such arguing would leave a huge class of PC Cards * and bridges out of reach for use in the system. * * Maybe I should reevaluate the above based on the power bug I fixed * in OLDCARD. */ void exca_reset(struct exca_softc *sc, device_t child) { int win; /* enable socket i/o */ exca_setb(sc, EXCA_PWRCTL, EXCA_PWRCTL_OE); exca_putb(sc, EXCA_INTR, EXCA_INTR_ENABLE); /* hold reset for 30ms */ DELAY(30*1000); /* clear the reset flag */ exca_setb(sc, EXCA_INTR, EXCA_INTR_RESET); /* wait 20ms as per PC Card standard (r2.01) section 4.3.6 */ DELAY(20*1000); exca_wait_ready(sc); /* disable all address windows */ exca_putb(sc, EXCA_ADDRWIN_ENABLE, 0); exca_setb(sc, EXCA_INTR, EXCA_INTR_CARDTYPE_IO); DEVPRINTF(sc->dev, "card type is io\n"); /* reinstall all the memory and io mappings */ for (win = 0; win < EXCA_MEM_WINS; ++win) if (sc->memalloc & (1 << win)) exca_do_mem_map(sc, win); for (win = 0; win < EXCA_IO_WINS; ++win) if (sc->ioalloc & (1 << win)) exca_do_io_map(sc, win); } /* * Initialize the exca_softc data structure for the first time. */ void exca_init(struct exca_softc *sc, device_t dev, bus_space_tag_t bst, bus_space_handle_t bsh, uint32_t offset) { sc->dev = dev; sc->memalloc = 0; sc->ioalloc = 0; sc->bst = bst; sc->bsh = bsh; sc->offset = offset; sc->flags = 0; sc->getb = exca_mem_getb; sc->putb = exca_mem_putb; } /* * Is this socket valid? */ static int exca_valid_slot(struct exca_softc *exca) { uint8_t c; /* Assume the worst */ exca->chipset = EXCA_BOGUS; /* * see if there's a PCMCIA controller here * Intel PCMCIA controllers use 0x82 and 0x83 * IBM clone chips use 0x88 and 0x89, apparently */ c = exca_getb(exca, EXCA_IDENT); DEVPRINTF(exca->dev, "Ident is %x\n", c); if ((c & EXCA_IDENT_IFTYPE_MASK) != EXCA_IDENT_IFTYPE_MEM_AND_IO) return (0); if ((c & EXCA_IDENT_ZERO) != 0) return (0); switch (c & EXCA_IDENT_REV_MASK) { /* * 82365 or clones. */ case EXCA_IDENT_REV_I82365SLR0: case EXCA_IDENT_REV_I82365SLR1: exca->chipset = EXCA_I82365; /* * Check for Vadem chips by unlocking their extra * registers and looking for valid ID. Bit 3 in * the ID register is normally 0, except when * EXCA_VADEMREV is set. Other bridges appear * to ignore this frobbing. */ bus_space_write_1(exca->bst, exca->bsh, EXCA_REG_INDEX, EXCA_VADEM_COOKIE1); bus_space_write_1(exca->bst, exca->bsh, EXCA_REG_INDEX, EXCA_VADEM_COOKIE2); exca_setb(exca, EXCA_VADEM_VMISC, EXCA_VADEM_REV); c = exca_getb(exca, EXCA_IDENT); if (c & 0x08) { switch (c & 7) { case 1: exca->chipset = EXCA_VG365; break; case 2: exca->chipset = EXCA_VG465; break; case 3: exca->chipset = EXCA_VG468; break; default: exca->chipset = EXCA_VG469; break; } exca_clrb(exca, EXCA_VADEM_VMISC, EXCA_VADEM_REV); break; } /* * Check for RICOH RF5C[23]96 PCMCIA Controller */ c = exca_getb(exca, EXCA_RICOH_ID); if (c == EXCA_RID_396) { exca->chipset = EXCA_RF5C396; break; } else if (c == EXCA_RID_296) { exca->chipset = EXCA_RF5C296; break; } /* * Check for Cirrus logic chips. */ exca_putb(exca, EXCA_CIRRUS_CHIP_INFO, 0); c = exca_getb(exca, EXCA_CIRRUS_CHIP_INFO); if ((c & EXCA_CIRRUS_CHIP_INFO_CHIP_ID) == EXCA_CIRRUS_CHIP_INFO_CHIP_ID) { c = exca_getb(exca, EXCA_CIRRUS_CHIP_INFO); if ((c & EXCA_CIRRUS_CHIP_INFO_CHIP_ID) == 0) { if (c & EXCA_CIRRUS_CHIP_INFO_SLOTS) exca->chipset = EXCA_PD6722; else exca->chipset = EXCA_PD6710; break; } } break; case EXCA_IDENT_REV_I82365SLDF: /* * Intel i82365sl-DF step or maybe a vlsi 82c146 * we detected the vlsi case earlier, so if the controller * isn't set, we know it is a i82365sl step D. */ exca->chipset = EXCA_I82365SL_DF; break; case EXCA_IDENT_REV_IBM1: case EXCA_IDENT_REV_IBM2: exca->chipset = EXCA_IBM; break; case EXCA_IDENT_REV_IBM_KING: exca->chipset = EXCA_IBM_KING; break; default: return (0); } return (1); } /* * Probe the expected slots. We maybe should set the ID for each of these * slots too while we're at it. But maybe that belongs to a separate * function. * * The caller must guarantee that at least EXCA_NSLOTS are present in exca. */ int exca_probe_slots(device_t dev, struct exca_softc *exca, bus_space_tag_t iot, bus_space_handle_t ioh) { int err; int i; err = ENXIO; for (i = 0; i < EXCA_NSLOTS; i++) { exca_init(&exca[i], dev, iot, ioh, i * EXCA_SOCKET_SIZE); exca->getb = exca_io_getb; exca->putb = exca_io_putb; if (exca_valid_slot(&exca[i])) { device_set_desc(dev, chip_names[exca[i].chipset]); err = 0; } } return (err); } void exca_insert(struct exca_softc *exca) { if (device_is_attached(exca->pccarddev)) { if (CARD_ATTACH_CARD(exca->pccarddev) != 0) device_printf(exca->dev, "PC Card card activation failed\n"); } else { device_printf(exca->dev, "PC Card inserted, but no pccard bus.\n"); } } void exca_removal(struct exca_softc *exca) { if (device_is_attached(exca->pccarddev)) CARD_DETACH_CARD(exca->pccarddev); } int exca_activate_resource(struct exca_softc *exca, device_t child, int type, int rid, struct resource *res) { int err; if (rman_get_flags(res) & RF_ACTIVE) return (0); err = BUS_ACTIVATE_RESOURCE(device_get_parent(exca->dev), child, type, rid, res); if (err) return (err); switch (type) { case SYS_RES_IOPORT: err = exca_io_map(exca, PCCARD_WIDTH_AUTO, res); break; case SYS_RES_MEMORY: err = exca_mem_map(exca, 0, res); break; } if (err) BUS_DEACTIVATE_RESOURCE(device_get_parent(exca->dev), child, type, rid, res); return (err); } int exca_deactivate_resource(struct exca_softc *exca, device_t child, int type, int rid, struct resource *res) { if (rman_get_flags(res) & RF_ACTIVE) { /* if activated */ switch (type) { case SYS_RES_IOPORT: if (exca_io_unmap_res(exca, res)) return (ENOENT); break; case SYS_RES_MEMORY: if (exca_mem_unmap_res(exca, res)) return (ENOENT); break; } } return (BUS_DEACTIVATE_RESOURCE(device_get_parent(exca->dev), child, type, rid, res)); } #if 0 static struct resource * exca_alloc_resource(struct exca_softc *sc, device_t child, int type, int *rid, u_long start, u_long end, u_long count, uint flags) { struct resource *res = NULL; int tmp; switch (type) { case SYS_RES_MEMORY: if (start < cbb_start_mem) start = cbb_start_mem; if (end < start) end = start; flags = (flags & ~RF_ALIGNMENT_MASK) | rman_make_alignment_flags(CBB_MEMALIGN); break; case SYS_RES_IOPORT: if (start < cbb_start_16_io) start = cbb_start_16_io; if (end < start) end = start; break; case SYS_RES_IRQ: tmp = rman_get_start(sc->irq_res); if (start > tmp || end < tmp || count != 1) { device_printf(child, "requested interrupt %ld-%ld," "count = %ld not supported by cbb\n", start, end, count); return (NULL); } flags |= RF_SHAREABLE; start = end = rman_get_start(sc->irq_res); break; } res = BUS_ALLOC_RESOURCE(up, child, type, rid, start, end, count, flags & ~RF_ACTIVE); if (res == NULL) return (NULL); cbb_insert_res(sc, res, type, *rid); if (flags & RF_ACTIVE) { if (bus_activate_resource(child, type, *rid, res) != 0) { bus_release_resource(child, type, *rid, res); return (NULL); } } return (res); } static int exca_release_resource(struct exca_softc *sc, device_t child, int type, int rid, struct resource *res) { int error; if (rman_get_flags(res) & RF_ACTIVE) { error = bus_deactivate_resource(child, type, rid, res); if (error != 0) return (error); } cbb_remove_res(sc, res); return (BUS_RELEASE_RESOURCE(device_get_parent(brdev), child, type, rid, res)); } #endif static int exca_modevent(module_t mod, int cmd, void *arg) { return 0; } DEV_MODULE(exca, exca_modevent, NULL); MODULE_VERSION(exca, 1); Index: head/sys/dev/exca/excareg.h =================================================================== --- head/sys/dev/exca/excareg.h (revision 355393) +++ head/sys/dev/exca/excareg.h (revision 355394) @@ -1,437 +1,437 @@ /* $NetBSD: i82365reg.h,v 1.3 1998/12/20 17:53:28 nathanw Exp $ */ /* $FreeBSD$ */ /*- * SPDX-License-Identifier: BSD-4-Clause AND BSD-2-Clause-FreeBSD * - * Copyright (c) 2002 M. Warner Losh. + * Copyright (c) 2002 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * This software may be derived from NetBSD i82365.c and other files with * the following copyright: * * Copyright (c) 1997 Marc Horowitz. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Marc Horowitz. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef _SYS_DEV_EXCA_EXCAREG_H #define _SYS_DEV_EXCA_EXCAREG_H /* * All information is from the intel 82365sl PC Card Interface Controller * (PCIC) data sheet, marked "preliminary". Order number 290423-002, January * 1993. */ #define EXCA_IOSIZE 2 #define EXCA_REG_INDEX 0 #define EXCA_REG_DATA 1 #define EXCA_NSLOTS 4 /* 2 in 2 chips */ /* * I/o ports */ #define EXCA_INDEX0 0x3e0 /* * The PCIC allows two chips to share the same address. In order not to run * afoul of the bsd device model, this driver will treat those chips as * the same device. */ #define EXCA_CHIP0_BASE 0x00 #define EXCA_CHIP1_BASE 0x80 /* Each PCIC chip can drive two sockets */ #define EXCA_SOCKET_SIZE 0x40 #define EXCA_SOCKETA_INDEX 0x00 #define EXCA_SOCKETB_INDEX EXCA_SOCKET_SIZE /* general setup registers */ #define EXCA_IDENT 0x00 /* RO */ #define EXCA_IDENT_IFTYPE_MASK 0xC0 #define EXCA_IDENT_IFTYPE_IO_ONLY 0x00 #define EXCA_IDENT_IFTYPE_MEM_ONLY 0x40 #define EXCA_IDENT_IFTYPE_MEM_AND_IO 0x80 #define EXCA_IDENT_IFTYPE_RESERVED 0xC0 #define EXCA_IDENT_ZERO 0x30 #define EXCA_IDENT_REV_MASK 0x0F #define EXCA_IDENT_REV_I82365SLR0 0x02 /* step a/b */ #define EXCA_IDENT_REV_I82365SLR1 0x03 /* step c */ #define EXCA_IDENT_REV_I82365SLDF 0x04 /* step df */ #define EXCA_IDENT_REV_IBM1 0x08 /* ibm clone */ #define EXCA_IDENT_REV_IBM2 0x09 /* ibm clone */ #define EXCA_IDENT_REV_IBM_KING 0x0a /* ibm king */ #define EXCA_IF_STATUS 0x01 /* RO */ #define EXCA_IF_STATUS_GPI 0x80 /* General Purpose Input */ #define EXCA_IF_STATUS_POWERACTIVE 0x40 #define EXCA_IF_STATUS_READY 0x20 /* really READY/!BUSY */ #define EXCA_IF_STATUS_MEM_WP 0x10 #define EXCA_IF_STATUS_CARDDETECT_MASK 0x0C #define EXCA_IF_STATUS_CARDDETECT_PRESENT 0x0C #define EXCA_IF_STATUS_BATTERY_MASK 0x03 #define EXCA_IF_STATUS_BATTERY_DEAD1 0x00 #define EXCA_IF_STATUS_BATTERY_DEAD2 0x01 #define EXCA_IF_STATUS_BATTERY_WARNING 0x02 #define EXCA_IF_STATUS_BATTERY_GOOD 0x03 #define EXCA_PWRCTL 0x02 /* RW */ #define EXCA_PWRCTL_OE 0x80 /* output enable */ #define EXCA_PWRCTL_DISABLE_RESETDRV 0x40 #define EXCA_PWRCTL_AUTOSWITCH_ENABLE 0x20 #define EXCA_PWRCTL_PWR_ENABLE 0x10 #define EXCA_PWRCTL_VPP2_MASK 0x0C /* XXX these are a little unclear from the data sheet */ #define EXCA_PWRCTL_VPP2_RESERVED 0x0C #define EXCA_PWRCTL_VPP2_EN1 0x08 #define EXCA_PWRCTL_VPP2_EN0 0x04 #define EXCA_PWRCTL_VPP2_ENX 0x00 #define EXCA_PWRCTL_VPP1_MASK 0x03 /* XXX these are a little unclear from the data sheet */ #define EXCA_PWRCTL_VPP1_RESERVED 0x03 #define EXCA_PWRCTL_VPP1_EN1 0x02 #define EXCA_PWRCTL_VPP1_EN0 0x01 #define EXCA_PWRCTL_VPP1_ENX 0x00 #define EXCA_CSC 0x04 /* RW */ #define EXCA_CSC_ZERO 0xE0 #define EXCA_CSC_GPI 0x10 #define EXCA_CSC_CD 0x08 /* Card Detect Change */ #define EXCA_CSC_READY 0x04 #define EXCA_CSC_BATTWARN 0x02 #define EXCA_CSC_BATTDEAD 0x01 /* for memory cards */ #define EXCA_CSC_RI 0x01 /* for i/o cards */ #define EXCA_ADDRWIN_ENABLE 0x06 /* RW */ #define EXCA_ADDRWIN_ENABLE_IO1 0x80 #define EXCA_ADDRWIN_ENABLE_IO0 0x40 #define EXCA_ADDRWIN_ENABLE_MEMCS16 0x20 /* rtfds if you care */ #define EXCA_ADDRWIN_ENABLE_MEM4 0x10 #define EXCA_ADDRWIN_ENABLE_MEM3 0x08 #define EXCA_ADDRWIN_ENABLE_MEM2 0x04 #define EXCA_ADDRWIN_ENABLE_MEM1 0x02 #define EXCA_ADDRWIN_ENABLE_MEM0 0x01 #define EXCA_CARD_DETECT 0x16 /* RW */ #define EXCA_CARD_DETECT_RESERVED 0xC0 #define EXCA_CARD_DETECT_SW_INTR 0x20 #define EXCA_CARD_DETECT_RESUME_ENABLE 0x10 #define EXCA_CARD_DETECT_GPI_TRANSCTL 0x08 #define EXCA_CARD_DETECT_GPI_ENABLE 0x04 #define EXCA_CARD_DETECT_CFGRST_ENABLE 0x02 #define EXCA_CARD_DETECT_MEMDLY_INHIBIT 0x01 /* interrupt registers */ #define EXCA_INTR 0x03 /* RW */ #define EXCA_INTR_RI_ENABLE 0x80 #define EXCA_INTR_RESET 0x40 /* active low (zero) */ #define EXCA_INTR_CARDTYPE_MASK 0x20 #define EXCA_INTR_CARDTYPE_IO 0x20 #define EXCA_INTR_CARDTYPE_MEM 0x00 #define EXCA_INTR_ENABLE 0x10 #define EXCA_INTR_IRQ_MASK 0x0F #define EXCA_INTR_IRQ_SHIFT 0 #define EXCA_INTR_IRQ_NONE 0x00 #define EXCA_INTR_IRQ_RESERVED1 0x01 #define EXCA_INTR_IRQ_RESERVED2 0x02 #define EXCA_INTR_IRQ3 0x03 #define EXCA_INTR_IRQ4 0x04 #define EXCA_INTR_IRQ5 0x05 #define EXCA_INTR_IRQ_RESERVED6 0x06 #define EXCA_INTR_IRQ7 0x07 #define EXCA_INTR_IRQ_RESERVED8 0x08 #define EXCA_INTR_IRQ9 0x09 #define EXCA_INTR_IRQ10 0x0A #define EXCA_INTR_IRQ11 0x0B #define EXCA_INTR_IRQ12 0x0C #define EXCA_INTR_IRQ_RESERVED13 0x0D #define EXCA_INTR_IRQ14 0x0E #define EXCA_INTR_IRQ15 0x0F #define EXCA_INTR_IRQ_VALIDMASK 0xDEB8 /* 1101 1110 1011 1000 */ #define EXCA_CSC_INTR 0x05 /* RW */ #define EXCA_CSC_INTR_IRQ_MASK 0xF0 #define EXCA_CSC_INTR_IRQ_SHIFT 4 #define EXCA_CSC_INTR_IRQ_NONE 0x00 #define EXCA_CSC_INTR_IRQ_RESERVED1 0x10 #define EXCA_CSC_INTR_IRQ_RESERVED2 0x20 #define EXCA_CSC_INTR_IRQ3 0x30 #define EXCA_CSC_INTR_IRQ4 0x40 #define EXCA_CSC_INTR_IRQ5 0x50 #define EXCA_CSC_INTR_IRQ_RESERVED6 0x60 #define EXCA_CSC_INTR_IRQ7 0x70 #define EXCA_CSC_INTR_IRQ_RESERVED8 0x80 #define EXCA_CSC_INTR_IRQ9 0x90 #define EXCA_CSC_INTR_IRQ10 0xA0 #define EXCA_CSC_INTR_IRQ11 0xB0 #define EXCA_CSC_INTR_IRQ12 0xC0 #define EXCA_CSC_INTR_IRQ_RESERVED13 0xD0 #define EXCA_CSC_INTR_IRQ14 0xE0 #define EXCA_CSC_INTR_IRQ15 0xF0 #define EXCA_CSC_INTR_CD_ENABLE 0x08 #define EXCA_CSC_INTR_READY_ENABLE 0x04 #define EXCA_CSC_INTR_BATTWARN_ENABLE 0x02 #define EXCA_CSC_INTR_BATTDEAD_ENABLE 0x01 /* for memory cards */ #define EXCA_CSC_INTR_RI_ENABLE 0x01 /* for I/O cards */ #define EXCA_CSC_INTR_IRQ_VALIDMASK 0xDEB8 /* 1101 1110 1011 1000 */ /* I/O registers */ #define EXCA_IO_WINS 2 #define EXCA_IOCTL 0x07 /* RW */ #define EXCA_IOCTL_IO1_WAITSTATE 0x80 #define EXCA_IOCTL_IO1_ZEROWAIT 0x40 #define EXCA_IOCTL_IO1_IOCS16SRC_MASK 0x20 #define EXCA_IOCTL_IO1_IOCS16SRC_CARD 0x20 #define EXCA_IOCTL_IO1_IOCS16SRC_DATASIZE 0x00 #define EXCA_IOCTL_IO1_DATASIZE_MASK 0x10 #define EXCA_IOCTL_IO1_DATASIZE_16BIT 0x10 #define EXCA_IOCTL_IO1_DATASIZE_8BIT 0x00 #define EXCA_IOCTL_IO0_WAITSTATE 0x08 #define EXCA_IOCTL_IO0_ZEROWAIT 0x04 #define EXCA_IOCTL_IO0_IOCS16SRC_MASK 0x02 #define EXCA_IOCTL_IO0_IOCS16SRC_CARD 0x02 #define EXCA_IOCTL_IO0_IOCS16SRC_DATASIZE 0x00 #define EXCA_IOCTL_IO0_DATASIZE_MASK 0x01 #define EXCA_IOCTL_IO0_DATASIZE_16BIT 0x01 #define EXCA_IOCTL_IO0_DATASIZE_8BIT 0x00 #define EXCA_IOADDR0_START_LSB 0x08 #define EXCA_IOADDR0_START_MSB 0x09 #define EXCA_IOADDR0_STOP_LSB 0x0A #define EXCA_IOADDR0_STOP_MSB 0x0B #define EXCA_IOADDR1_START_LSB 0x0C #define EXCA_IOADDR1_START_MSB 0x0D #define EXCA_IOADDR1_STOP_LSB 0x0E #define EXCA_IOADDR1_STOP_MSB 0x0F /* memory registers */ /* * memory window addresses refer to bits A23-A12 of the ISA system memory * address. This is a shift of 12 bits. The LSB contains A19-A12, and the * MSB contains A23-A20, plus some other bits. */ #define EXCA_MEM_WINS 5 #define EXCA_MEM_SHIFT 12 #define EXCA_MEM_PAGESIZE (1< * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * This software may be derived from NetBSD i82365.c and other files with * the following copyright: * * Copyright (c) 1997 Marc Horowitz. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Marc Horowitz. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef _SYS_DEV_EXCA_EXCAVAR_H #define _SYS_DEV_EXCA_EXCAVAR_H /* * Structure to manage the ExCA part of the chip. */ struct exca_softc; typedef uint8_t (exca_getb_fn)(struct exca_softc *, int); typedef void (exca_putb_fn)(struct exca_softc *, int, uint8_t); struct exca_softc { device_t dev; int memalloc; struct pccard_mem_handle mem[EXCA_MEM_WINS]; int ioalloc; struct pccard_io_handle io[EXCA_IO_WINS]; bus_space_tag_t bst; bus_space_handle_t bsh; uint32_t flags; #define EXCA_SOCKET_PRESENT 0x00000001 #define EXCA_HAS_MEMREG_WIN 0x00000002 #define EXCA_CARD_OK 0x00000004 #define EXCA_EVENT 0x80000000 uint32_t offset; int chipset; #define EXCA_CARDBUS 0 #define EXCA_I82365 1 /* Intel i82365SL-A/B or clone */ #define EXCA_I82365SL_DF 2 /* Intel i82365sl-DF step */ #define EXCA_VLSI 3 /* VLSI chip */ #define EXCA_PD6710 4 /* Cirrus logic PD6710 */ #define EXCA_PD6722 5 /* Cirrus logic PD6722 */ #define EXCA_PD6729 6 /* Cirrus Logic PD6729 */ #define EXCA_VG365 7 /* Vadem 365 */ #define EXCA_VG465 8 /* Vadem 465 */ #define EXCA_VG468 9 /* Vadem 468 */ #define EXCA_VG469 10 /* Vadem 469 */ #define EXCA_RF5C296 11 /* Ricoh RF5C296 */ #define EXCA_RF5C396 12 /* Ricoh RF5C396 */ #define EXCA_IBM 13 /* IBM clone */ #define EXCA_IBM_KING 14 /* IBM KING PCMCIA Controller */ #define EXCA_BOGUS -1 /* Invalid/not present/etc */ exca_getb_fn *getb; exca_putb_fn *putb; device_t pccarddev; uint32_t status; /* status, hw dependent */ }; void exca_init(struct exca_softc *sc, device_t dev, bus_space_tag_t, bus_space_handle_t, uint32_t); void exca_insert(struct exca_softc *sc); int exca_io_map(struct exca_softc *sc, int width, struct resource *r); int exca_io_unmap_res(struct exca_softc *sc, struct resource *res); int exca_is_pcic(struct exca_softc *sc); int exca_mem_map(struct exca_softc *sc, int kind, struct resource *res); int exca_mem_set_flags(struct exca_softc *sc, struct resource *res, uint32_t flags); int exca_mem_set_offset(struct exca_softc *sc, struct resource *res, uint32_t cardaddr, uint32_t *deltap); int exca_mem_unmap_res(struct exca_softc *sc, struct resource *res); int exca_probe_slots(device_t dev, struct exca_softc *exca, bus_space_tag_t iot, bus_space_handle_t ioh); void exca_removal(struct exca_softc *); void exca_reset(struct exca_softc *, device_t child); /* bus/device interfaces */ int exca_activate_resource(struct exca_softc *exca, device_t child, int type, int rid, struct resource *res); int exca_deactivate_resource(struct exca_softc *exca, device_t child, int type, int rid, struct resource *res); static __inline uint8_t exca_getb(struct exca_softc *sc, int reg) { return (sc->getb(sc, reg)); } static __inline void exca_putb(struct exca_softc *sc, int reg, uint8_t val) { sc->putb(sc, reg, val); } static __inline void exca_setb(struct exca_softc *sc, int reg, uint8_t mask) { exca_putb(sc, reg, exca_getb(sc, reg) | mask); } static __inline void exca_clrb(struct exca_softc *sc, int reg, uint8_t mask) { exca_putb(sc, reg, exca_getb(sc, reg) & ~mask); } #endif /* !_SYS_DEV_EXCA_EXCAVAR_H */ Index: head/sys/dev/fdc/fdc_isa.c =================================================================== --- head/sys/dev/fdc/fdc_isa.c (revision 355393) +++ head/sys/dev/fdc/fdc_isa.c (revision 355394) @@ -1,227 +1,226 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2004-2005 M. Warner Losh. - * All rights reserved. + * Copyright (c) 2004-2005 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include static int fdc_isa_probe(device_t); static struct isa_pnp_id fdc_ids[] = { {0x0007d041, "PC standard floppy controller"}, /* PNP0700 */ {0x0107d041, "Standard floppy controller supporting MS Device Bay Spec"}, /* PNP0701 */ {0} }; /* * On standard ISA, we don't just use an 8 port range * (e.g. 0x3f0-0x3f7) since that covers an IDE control register at * 0x3f6. So, on older hardware, we use 0x3f0-0x3f5 and 0x3f7. * However, some BIOSs omit the control port, while others start at * 0x3f2. Of the latter, sometimes we have two resources, other times * we have one. We have to deal with the following cases: * * 1: 0x3f0-0x3f5 # very rare * 2: 0x3f0 # hints -> 0x3f0-0x3f5,0x3f7 * 3: 0x3f0-0x3f5,0x3f7 # Most common * 4: 0x3f2-0x3f5,0x3f7 # Second most common * 5: 0x3f2-0x3f5 # implies 0x3f7 too. * 6: 0x3f2-0x3f3,0x3f4-0x3f5,0x3f7 # becoming common * 7: 0x3f2-0x3f3,0x3f4-0x3f5 # rare * 8: 0x3f0-0x3f1,0x3f2-0x3f3,0x3f4-0x3f5,0x3f7 * 9: 0x3f0-0x3f3,0x3f4-0x3f5,0x3f7 * * The following code is generic for any value of 0x3fx. It is also * generic for all the above cases, as well as cases where things are * even weirder. */ int fdc_isa_alloc_resources(device_t dev, struct fdc_data *fdc) { struct resource *res; int i, j, rid, newrid, nport; u_long port; fdc->fdc_dev = dev; rid = 0; for (i = 0; i < FDC_MAXREG; i++) fdc->resio[i] = NULL; nport = isa_get_logicalid(dev) ? 1 : 6; for (rid = 0; ; rid++) { newrid = rid; res = bus_alloc_resource_anywhere(dev, SYS_RES_IOPORT, &newrid, rid == 0 ? nport : 1, RF_ACTIVE); if (res == NULL) break; /* * Mask off the upper bits of the register, and sanity * check resource ranges. */ i = rman_get_start(res) & 0x7; if (i + rman_get_size(res) - 1 > FDC_MAXREG) { bus_release_resource(dev, SYS_RES_IOPORT, newrid, res); return (ENXIO); } for (j = 0; j < rman_get_size(res); j++) { fdc->resio[i + j] = res; fdc->ridio[i + j] = newrid; fdc->ioff[i + j] = j; fdc->ioh[i + j] = rman_get_bushandle(res); } } if (fdc->resio[2] == NULL) { device_printf(dev, "No FDOUT register!\n"); return (ENXIO); } fdc->iot = rman_get_bustag(fdc->resio[2]); if (fdc->resio[7] == NULL) { port = (rman_get_start(fdc->resio[2]) & ~0x7) + 7; newrid = rid; res = bus_alloc_resource(dev, SYS_RES_IOPORT, &newrid, port, port, 1, RF_ACTIVE); if (res == NULL) { device_printf(dev, "Faking up FDCTL\n"); fdc->resio[7] = fdc->resio[2]; fdc->ridio[7] = fdc->ridio[2]; fdc->ioff[7] = fdc->ioff[2] + 5; fdc->ioh[7] = fdc->ioh[2]; } else { fdc->resio[7] = res; fdc->ridio[7] = newrid; fdc->ioff[7] = rman_get_start(res) & 7; fdc->ioh[7] = rman_get_bushandle(res); } } fdc->res_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &fdc->rid_irq, RF_ACTIVE | RF_SHAREABLE); if (fdc->res_irq == NULL) { device_printf(dev, "cannot reserve interrupt line\n"); return (ENXIO); } if ((fdc->flags & FDC_NODMA) == 0) { fdc->res_drq = bus_alloc_resource_any(dev, SYS_RES_DRQ, &fdc->rid_drq, RF_ACTIVE | RF_SHAREABLE); if (fdc->res_drq == NULL) { device_printf(dev, "cannot reserve DMA request line\n"); /* This is broken and doesn't work for ISA case */ fdc->flags |= FDC_NODMA; } else fdc->dmachan = rman_get_start(fdc->res_drq); } return (0); } static int fdc_isa_probe(device_t dev) { int error; struct fdc_data *fdc; fdc = device_get_softc(dev); fdc->fdc_dev = dev; /* Check pnp ids */ error = ISA_PNP_PROBE(device_get_parent(dev), dev, fdc_ids); if (error == ENXIO) return (ENXIO); /* Attempt to allocate our resources for the duration of the probe */ error = fdc_isa_alloc_resources(dev, fdc); if (error == 0) error = fdc_initial_reset(dev, fdc); fdc_release_resources(fdc); return (error); } static int fdc_isa_attach(device_t dev) { struct fdc_data *fdc; int error; fdc = device_get_softc(dev); fdc->fdc_dev = dev; error = fdc_isa_alloc_resources(dev, fdc); if (error == 0) error = fdc_attach(dev); if (error == 0) error = fdc_hints_probe(dev); if (error == 0) fdc_start_worker(dev); else fdc_release_resources(fdc); return (error); } static device_method_t fdc_methods[] = { /* Device interface */ DEVMETHOD(device_probe, fdc_isa_probe), DEVMETHOD(device_attach, fdc_isa_attach), DEVMETHOD(device_detach, fdc_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), /* Bus interface */ DEVMETHOD(bus_print_child, fdc_print_child), DEVMETHOD(bus_read_ivar, fdc_read_ivar), DEVMETHOD(bus_write_ivar, fdc_write_ivar), /* Our children never use any other bus interface methods. */ { 0, 0 } }; static driver_t fdc_driver = { "fdc", fdc_methods, sizeof(struct fdc_data) }; DRIVER_MODULE(fdc, isa, fdc_driver, fdc_devclass, 0, 0); ISA_PNP_INFO(fdc_ids); Index: head/sys/dev/fdc/fdc_pccard.c =================================================================== --- head/sys/dev/fdc/fdc_pccard.c (revision 355393) +++ head/sys/dev/fdc/fdc_pccard.c (revision 355394) @@ -1,146 +1,145 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2004-2005 M. Warner Losh. - * All rights reserved. + * Copyright (c) 2004-2005 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include "pccarddevs.h" static int fdc_pccard_probe(device_t); static int fdc_pccard_attach(device_t); static const struct pccard_product fdc_pccard_products[] = { PCMCIA_CARD(YEDATA, EXTERNAL_FDD), { NULL } }; static int fdc_pccard_alloc_resources(device_t dev, struct fdc_data *fdc) { struct resource *res; int rid, i; rid = 0; res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, RF_ACTIVE); if (res == NULL) { device_printf(dev, "cannot alloc I/O port range\n"); return (ENXIO); } for (i = 0; i < FDC_MAXREG; i++) { fdc->resio[i] = res; fdc->ridio[i] = rid; fdc->ioff[i] = i; fdc->ioh[i] = rman_get_bushandle(res); } fdc->iot = rman_get_bustag(res); fdc->rid_irq = 0; fdc->res_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &fdc->rid_irq, RF_ACTIVE | RF_SHAREABLE); if (fdc->res_irq == NULL) { device_printf(dev, "cannot reserve interrupt line\n"); return (ENXIO); } return (0); } static int fdc_pccard_probe(device_t dev) { if (pccard_product_lookup(dev, fdc_pccard_products, sizeof(fdc_pccard_products[0]), NULL) != NULL) { device_set_desc(dev, "PC Card Floppy"); return (0); } return (ENXIO); } static int fdc_pccard_attach(device_t dev) { int error; struct fdc_data *fdc; device_t child; fdc = device_get_softc(dev); fdc->flags = FDC_NODMA | FDC_NOFAST; fdc->fdct = FDC_NE765; error = fdc_pccard_alloc_resources(dev, fdc); if (error == 0) error = fdc_attach(dev); if (error == 0) { child = fdc_add_child(dev, "fd", -1); device_set_flags(child, 0x24); error = bus_generic_attach(dev); } if (error == 0) fdc_start_worker(dev); else fdc_release_resources(fdc); return (error); } static device_method_t fdc_pccard_methods[] = { /* Device interface */ DEVMETHOD(device_probe, fdc_pccard_probe), DEVMETHOD(device_attach, fdc_pccard_attach), DEVMETHOD(device_detach, fdc_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), /* Bus interface */ DEVMETHOD(bus_print_child, fdc_print_child), DEVMETHOD(bus_read_ivar, fdc_read_ivar), DEVMETHOD(bus_write_ivar, fdc_write_ivar), /* Our children never use any other bus interface methods. */ { 0, 0 } }; static driver_t fdc_pccard_driver = { "fdc", fdc_pccard_methods, sizeof(struct fdc_data) }; DRIVER_MODULE(fdc, pccard, fdc_pccard_driver, fdc_devclass, 0, 0); PCCARD_PNP_INFO(fdc_pccard_products); Index: head/sys/dev/fdc/fdcvar.h =================================================================== --- head/sys/dev/fdc/fdcvar.h (revision 355393) +++ head/sys/dev/fdc/fdcvar.h (revision 355394) @@ -1,94 +1,93 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2004-2005 M. Warner Losh. - * All rights reserved. + * Copyright (c) 2004-2005 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ /* XXX should audit this file to see if additional copyrights needed */ enum fdc_type { FDC_NE765, FDC_ENHANCED, FDC_UNKNOWN = -1 }; /* * Per controller structure (softc). */ struct fdc_data { int fdcu; /* our unit number */ int dmachan; int flags; #define FDC_HASDMA 0x01 #define FDC_STAT_VALID 0x08 #define FDC_HAS_FIFO 0x10 #define FDC_NEEDS_RESET 0x20 #define FDC_NODMA 0x40 /* Don't do DMA */ #define FDC_NOFAST 0x80 /* Don't register isr as a fast one */ #define FDC_KTHREAD_EXIT 0x1000 /* request worker thread to stop */ #define FDC_KTHREAD_ALIVE 0x2000 /* worker thread is alive */ struct fd_data *fd; /* The active drive */ int retry; int fdout; /* mirror of the w/o digital output reg */ u_int status[7]; /* copy of the registers */ enum fdc_type fdct; /* chip version of FDC */ int fdc_errs; /* number of logged errors */ struct bio_queue_head head; struct bio *bp; /* active buffer */ struct resource *res_irq, *res_drq; int rid_irq, rid_drq; #define FDC_MAXREG 8 int ridio[FDC_MAXREG]; struct resource *resio[FDC_MAXREG]; bus_space_tag_t iot; bus_space_handle_t ioh[FDC_MAXREG]; int ioff[FDC_MAXREG]; void *fdc_intr; device_t fdc_dev; struct mtx fdc_mtx; struct proc *fdc_thread; }; extern devclass_t fdc_devclass; enum fdc_device_ivars { FDC_IVAR_FDUNIT, FDC_IVAR_FDTYPE, }; __BUS_ACCESSOR(fdc, fdunit, FDC, FDUNIT, int); __BUS_ACCESSOR(fdc, fdtype, FDC, FDTYPE, int); void fdc_release_resources(struct fdc_data *); int fdc_attach(device_t); void fdc_start_worker(device_t); int fdc_hints_probe(device_t); int fdc_detach(device_t dev); device_t fdc_add_child(device_t, const char *, int); int fdc_initial_reset(device_t, struct fdc_data *); int fdc_print_child(device_t, device_t); int fdc_read_ivar(device_t, device_t, int, uintptr_t *); int fdc_write_ivar(device_t, device_t, int, uintptr_t); int fdc_isa_alloc_resources(device_t, struct fdc_data *); Index: head/sys/dev/flash/at45d.c =================================================================== --- head/sys/dev/flash/at45d.c (revision 355393) +++ head/sys/dev/flash/at45d.c (revision 355394) @@ -1,611 +1,610 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2006 M. Warner Losh - * Copyright (c) 2011-2012 Ian Lepore - * Copyright (c) 2012 Marius Strobl - * All rights reserved. - * + * Copyright (c) 2011-2012 Ian Lepore All rights reserved. + * Copyright (c) 2012 Marius Strobl All rights reserved. + * Copyright (c) 2006 M. Warner Losh + * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "spibus_if.h" #include "opt_platform.h" #ifdef FDT #include #include #include static struct ofw_compat_data compat_data[] = { { "atmel,at45", 1 }, { "atmel,dataflash", 1 }, { NULL, 0 }, }; #endif /* This is the information returned by the MANUFACTURER_ID command. */ struct at45d_mfg_info { uint32_t jedec_id; /* Mfg ID, DevId1, DevId2, ExtLen */ uint16_t ext_id; /* ExtId1, ExtId2 */ }; /* * This is an entry in our table of metadata describing the chips. We match on * both jedec id and extended id info returned by the MANUFACTURER_ID command. */ struct at45d_flash_ident { const char *name; uint32_t jedec; uint16_t extid; uint16_t extmask; uint16_t pagecount; uint16_t pageoffset; uint16_t pagesize; uint16_t pagesize2n; }; struct at45d_softc { struct bio_queue_head bio_queue; struct mtx sc_mtx; struct disk *disk; struct proc *p; device_t dev; u_int taskstate; uint16_t pagecount; uint16_t pageoffset; uint16_t pagesize; void *dummybuf; }; #define TSTATE_STOPPED 0 #define TSTATE_STOPPING 1 #define TSTATE_RUNNING 2 #define AT45D_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) #define AT45D_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) #define AT45D_LOCK_INIT(_sc) \ mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->dev), \ "at45d", MTX_DEF) #define AT45D_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx); #define AT45D_ASSERT_LOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED); #define AT45D_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED); /* bus entry points */ static device_attach_t at45d_attach; static device_detach_t at45d_detach; static device_probe_t at45d_probe; /* disk routines */ static int at45d_close(struct disk *dp); static int at45d_open(struct disk *dp); static int at45d_getattr(struct bio *bp); static void at45d_strategy(struct bio *bp); static void at45d_task(void *arg); /* helper routines */ static void at45d_delayed_attach(void *xsc); static int at45d_get_mfg_info(device_t dev, struct at45d_mfg_info *resp); static int at45d_get_status(device_t dev, uint8_t *status); static int at45d_wait_ready(device_t dev, uint8_t *status); #define PAGE_TO_BUFFER_TRANSFER 0x53 #define PAGE_TO_BUFFER_COMPARE 0x60 #define PROGRAM_THROUGH_BUFFER 0x82 #define MANUFACTURER_ID 0x9f #define STATUS_REGISTER_READ 0xd7 #define CONTINUOUS_ARRAY_READ 0xe8 #define STATUS_READY (1u << 7) #define STATUS_CMPFAIL (1u << 6) #define STATUS_PAGE2N (1u << 0) /* * Metadata for supported chips. * * The jedec id in this table includes the extended id length byte. A match is * based on both jedec id and extended id matching. The chip's extended id (not * present in most chips) is ANDed with ExtMask and the result is compared to * ExtId. If a chip only returns 1 ext id byte it will be in the upper 8 bits * of ExtId in this table. * * A sectorsize2n != 0 is used to indicate that a device optionally supports * 2^N byte pages. If support for the latter is enabled, the sector offset * has to be reduced by one. */ static const struct at45d_flash_ident at45d_flash_devices[] = { /* Part Name Jedec ID ExtId ExtMask PgCnt Offs PgSz PgSz2n */ { "AT45DB011B", 0x1f220000, 0x0000, 0x0000, 512, 9, 264, 256 }, { "AT45DB021B", 0x1f230000, 0x0000, 0x0000, 1024, 9, 264, 256 }, { "AT45DB041x", 0x1f240000, 0x0000, 0x0000, 2028, 9, 264, 256 }, { "AT45DB081B", 0x1f250000, 0x0000, 0x0000, 4096, 9, 264, 256 }, { "AT45DB161x", 0x1f260000, 0x0000, 0x0000, 4096, 10, 528, 512 }, { "AT45DB321x", 0x1f270000, 0x0000, 0x0000, 8192, 10, 528, 0 }, { "AT45DB321x", 0x1f270100, 0x0000, 0x0000, 8192, 10, 528, 512 }, { "AT45DB641E", 0x1f280001, 0x0000, 0xff00, 32768, 9, 264, 256 }, { "AT45DB642x", 0x1f280000, 0x0000, 0x0000, 8192, 11, 1056, 1024 }, }; static int at45d_get_status(device_t dev, uint8_t *status) { uint8_t rxBuf[8], txBuf[8]; struct spi_command cmd; int err; memset(&cmd, 0, sizeof(cmd)); memset(txBuf, 0, sizeof(txBuf)); memset(rxBuf, 0, sizeof(rxBuf)); txBuf[0] = STATUS_REGISTER_READ; cmd.tx_cmd = txBuf; cmd.rx_cmd = rxBuf; cmd.rx_cmd_sz = cmd.tx_cmd_sz = 2; err = SPIBUS_TRANSFER(device_get_parent(dev), dev, &cmd); *status = rxBuf[1]; return (err); } static int at45d_get_mfg_info(device_t dev, struct at45d_mfg_info *resp) { uint8_t rxBuf[8], txBuf[8]; struct spi_command cmd; int err; memset(&cmd, 0, sizeof(cmd)); memset(txBuf, 0, sizeof(txBuf)); memset(rxBuf, 0, sizeof(rxBuf)); txBuf[0] = MANUFACTURER_ID; cmd.tx_cmd = &txBuf; cmd.rx_cmd = &rxBuf; cmd.tx_cmd_sz = cmd.rx_cmd_sz = 7; err = SPIBUS_TRANSFER(device_get_parent(dev), dev, &cmd); if (err) return (err); resp->jedec_id = be32dec(rxBuf + 1); resp->ext_id = be16dec(rxBuf + 5); return (0); } static int at45d_wait_ready(device_t dev, uint8_t *status) { struct timeval now, tout; int err; getmicrouptime(&tout); tout.tv_sec += 3; do { getmicrouptime(&now); if (now.tv_sec > tout.tv_sec) err = ETIMEDOUT; else err = at45d_get_status(dev, status); } while (err == 0 && !(*status & STATUS_READY)); return (err); } static int at45d_probe(device_t dev) { int rv; #ifdef FDT if (!ofw_bus_status_okay(dev)) return (ENXIO); if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) return (ENXIO); rv = BUS_PROBE_DEFAULT; #else rv = BUS_PROBE_NOWILDCARD; #endif device_set_desc(dev, "AT45D Flash Family"); return (rv); } static int at45d_attach(device_t dev) { struct at45d_softc *sc; sc = device_get_softc(dev); sc->dev = dev; AT45D_LOCK_INIT(sc); config_intrhook_oneshot(at45d_delayed_attach, sc); return (0); } static int at45d_detach(device_t dev) { struct at45d_softc *sc; int err; sc = device_get_softc(dev); err = 0; AT45D_LOCK(sc); if (sc->taskstate == TSTATE_RUNNING) { sc->taskstate = TSTATE_STOPPING; wakeup(sc); while (err == 0 && sc->taskstate != TSTATE_STOPPED) { err = msleep(sc, &sc->sc_mtx, 0, "at45dt", hz * 3); if (err != 0) { sc->taskstate = TSTATE_RUNNING; device_printf(sc->dev, "Failed to stop queue task\n"); } } } AT45D_UNLOCK(sc); if (err == 0 && sc->taskstate == TSTATE_STOPPED) { if (sc->disk) { disk_destroy(sc->disk); bioq_flush(&sc->bio_queue, NULL, ENXIO); free(sc->dummybuf, M_DEVBUF); } AT45D_LOCK_DESTROY(sc); } return (err); } static void at45d_delayed_attach(void *xsc) { struct at45d_softc *sc; struct at45d_mfg_info mfginfo; const struct at45d_flash_ident *ident; u_int i; int sectorsize; uint32_t jedec; uint16_t pagesize; uint8_t status; sc = xsc; ident = NULL; jedec = 0; if (at45d_wait_ready(sc->dev, &status) != 0) { device_printf(sc->dev, "Error waiting for device-ready.\n"); return; } if (at45d_get_mfg_info(sc->dev, &mfginfo) != 0) { device_printf(sc->dev, "Failed to get ID.\n"); return; } for (i = 0; i < nitems(at45d_flash_devices); i++) { ident = &at45d_flash_devices[i]; if (mfginfo.jedec_id == ident->jedec && (mfginfo.ext_id & ident->extmask) == ident->extid) { break; } } if (i == nitems(at45d_flash_devices)) { device_printf(sc->dev, "JEDEC 0x%x not in list.\n", jedec); return; } sc->pagecount = ident->pagecount; sc->pageoffset = ident->pageoffset; if (ident->pagesize2n != 0 && (status & STATUS_PAGE2N)) { sc->pageoffset -= 1; pagesize = ident->pagesize2n; } else pagesize = ident->pagesize; sc->pagesize = pagesize; /* * By default we set up a disk with a sector size that matches the * device page size. If there is a device hint or fdt property * requesting a different size, use that, as long as it is a multiple of * the device page size). */ sectorsize = pagesize; #ifdef FDT { pcell_t size; if (OF_getencprop(ofw_bus_get_node(sc->dev), "freebsd,sectorsize", &size, sizeof(size)) > 0) sectorsize = size; } #endif resource_int_value(device_get_name(sc->dev), device_get_unit(sc->dev), "sectorsize", §orsize); if ((sectorsize % pagesize) != 0) { device_printf(sc->dev, "Invalid sectorsize %d, " "must be a multiple of %d\n", sectorsize, pagesize); return; } sc->dummybuf = malloc(pagesize, M_DEVBUF, M_WAITOK | M_ZERO); sc->disk = disk_alloc(); sc->disk->d_open = at45d_open; sc->disk->d_close = at45d_close; sc->disk->d_strategy = at45d_strategy; sc->disk->d_getattr = at45d_getattr; sc->disk->d_name = "flash/at45d"; sc->disk->d_drv1 = sc; sc->disk->d_maxsize = DFLTPHYS; sc->disk->d_sectorsize = sectorsize; sc->disk->d_mediasize = pagesize * ident->pagecount; sc->disk->d_unit = device_get_unit(sc->dev); disk_create(sc->disk, DISK_VERSION); bioq_init(&sc->bio_queue); kproc_create(&at45d_task, sc, &sc->p, 0, 0, "task: at45d flash"); sc->taskstate = TSTATE_RUNNING; device_printf(sc->dev, "%s, %d bytes per page, %d pages; %d KBytes; disk sector size %d\n", ident->name, pagesize, ident->pagecount, (pagesize * ident->pagecount) / 1024, sectorsize); } static int at45d_open(struct disk *dp) { return (0); } static int at45d_close(struct disk *dp) { return (0); } static int at45d_getattr(struct bio *bp) { struct at45d_softc *sc; /* * This function exists to support geom_flashmap and fdt_slicer. */ if (bp->bio_disk == NULL || bp->bio_disk->d_drv1 == NULL) return (ENXIO); if (strcmp(bp->bio_attribute, "SPI::device") != 0) return (-1); sc = bp->bio_disk->d_drv1; if (bp->bio_length != sizeof(sc->dev)) return (EFAULT); bcopy(&sc->dev, bp->bio_data, sizeof(sc->dev)); return (0); } static void at45d_strategy(struct bio *bp) { struct at45d_softc *sc; sc = (struct at45d_softc *)bp->bio_disk->d_drv1; AT45D_LOCK(sc); bioq_disksort(&sc->bio_queue, bp); wakeup(sc); AT45D_UNLOCK(sc); } static void at45d_task(void *arg) { uint8_t rxBuf[8], txBuf[8]; struct at45d_softc *sc; struct bio *bp; struct spi_command cmd; device_t dev, pdev; caddr_t buf; u_long len, resid; u_int addr, berr, err, offset, page; uint8_t status; sc = (struct at45d_softc*)arg; dev = sc->dev; pdev = device_get_parent(dev); memset(&cmd, 0, sizeof(cmd)); memset(txBuf, 0, sizeof(txBuf)); memset(rxBuf, 0, sizeof(rxBuf)); cmd.tx_cmd = txBuf; cmd.rx_cmd = rxBuf; for (;;) { AT45D_LOCK(sc); do { if (sc->taskstate == TSTATE_STOPPING) { sc->taskstate = TSTATE_STOPPED; AT45D_UNLOCK(sc); wakeup(sc); kproc_exit(0); } bp = bioq_takefirst(&sc->bio_queue); if (bp == NULL) msleep(sc, &sc->sc_mtx, PRIBIO, "at45dq", 0); } while (bp == NULL); AT45D_UNLOCK(sc); berr = 0; buf = bp->bio_data; len = resid = bp->bio_bcount; page = bp->bio_offset / sc->pagesize; offset = bp->bio_offset % sc->pagesize; switch (bp->bio_cmd) { case BIO_READ: txBuf[0] = CONTINUOUS_ARRAY_READ; cmd.tx_cmd_sz = cmd.rx_cmd_sz = 8; cmd.tx_data = sc->dummybuf; cmd.rx_data = buf; break; case BIO_WRITE: cmd.tx_cmd_sz = cmd.rx_cmd_sz = 4; cmd.tx_data = buf; cmd.rx_data = sc->dummybuf; if (resid + offset > sc->pagesize) len = sc->pagesize - offset; break; default: berr = EINVAL; goto out; } /* * NB: for BIO_READ, this loop is only traversed once. */ while (resid > 0) { if (page > sc->pagecount) { berr = EINVAL; goto out; } addr = page << sc->pageoffset; if (bp->bio_cmd == BIO_WRITE) { /* * If writing less than a full page, transfer * the existing page to the buffer, so that our * PROGRAM_THROUGH_BUFFER below will preserve * the parts of the page we're not writing. */ if (len != sc->pagesize) { txBuf[0] = PAGE_TO_BUFFER_TRANSFER; txBuf[1] = ((addr >> 16) & 0xff); txBuf[2] = ((addr >> 8) & 0xff); txBuf[3] = 0; cmd.tx_data_sz = cmd.rx_data_sz = 0; err = SPIBUS_TRANSFER(pdev, dev, &cmd); if (err == 0) err = at45d_wait_ready(dev, &status); if (err != 0) { berr = EIO; goto out; } } txBuf[0] = PROGRAM_THROUGH_BUFFER; } addr += offset; txBuf[1] = ((addr >> 16) & 0xff); txBuf[2] = ((addr >> 8) & 0xff); txBuf[3] = (addr & 0xff); cmd.tx_data_sz = cmd.rx_data_sz = len; err = SPIBUS_TRANSFER(pdev, dev, &cmd); if (err == 0 && bp->bio_cmd != BIO_READ) err = at45d_wait_ready(dev, &status); if (err != 0) { berr = EIO; goto out; } if (bp->bio_cmd == BIO_WRITE) { addr = page << sc->pageoffset; txBuf[0] = PAGE_TO_BUFFER_COMPARE; txBuf[1] = ((addr >> 16) & 0xff); txBuf[2] = ((addr >> 8) & 0xff); txBuf[3] = 0; cmd.tx_data_sz = cmd.rx_data_sz = 0; err = SPIBUS_TRANSFER(pdev, dev, &cmd); if (err == 0) err = at45d_wait_ready(dev, &status); if (err != 0 || (status & STATUS_CMPFAIL)) { device_printf(dev, "comparing page " "%d failed (status=0x%x)\n", page, status); berr = EIO; goto out; } } page++; buf += len; offset = 0; resid -= len; if (resid > sc->pagesize) len = sc->pagesize; else len = resid; if (bp->bio_cmd == BIO_READ) cmd.rx_data = buf; else cmd.tx_data = buf; } out: if (berr != 0) { bp->bio_flags |= BIO_ERROR; bp->bio_error = berr; } bp->bio_resid = resid; biodone(bp); } } static devclass_t at45d_devclass; static device_method_t at45d_methods[] = { /* Device interface */ DEVMETHOD(device_probe, at45d_probe), DEVMETHOD(device_attach, at45d_attach), DEVMETHOD(device_detach, at45d_detach), DEVMETHOD_END }; static driver_t at45d_driver = { "at45d", at45d_methods, sizeof(struct at45d_softc), }; DRIVER_MODULE(at45d, spibus, at45d_driver, at45d_devclass, NULL, NULL); MODULE_DEPEND(at45d, spibus, 1, 1, 1); #ifdef FDT MODULE_DEPEND(at45d, fdt_slicer, 1, 1, 1); SPIBUS_FDT_PNP_INFO(compat_data); #endif Index: head/sys/dev/flash/mx25l.c =================================================================== --- head/sys/dev/flash/mx25l.c (revision 355393) +++ head/sys/dev/flash/mx25l.c (revision 355394) @@ -1,691 +1,691 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2006 M. Warner Losh. * Copyright (c) 2009 Oleksandr Tymoshenko. All rights reserved. * Copyright (c) 2018 Ian Lepore. All rights reserved. + * Copyright (c) 2006 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include "opt_platform.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef FDT #include #include #include #endif #include #include "spibus_if.h" #include #define FL_NONE 0x00 #define FL_ERASE_4K 0x01 #define FL_ERASE_32K 0x02 #define FL_ENABLE_4B_ADDR 0x04 #define FL_DISABLE_4B_ADDR 0x08 /* * Define the sectorsize to be a smaller size rather than the flash * sector size. Trying to run FFS off of a 64k flash sector size * results in a completely un-usable system. */ #define MX25L_SECTORSIZE 512 struct mx25l_flash_ident { const char *name; uint8_t manufacturer_id; uint16_t device_id; unsigned int sectorsize; unsigned int sectorcount; unsigned int flags; }; struct mx25l_softc { device_t sc_dev; device_t sc_parent; uint8_t sc_manufacturer_id; uint16_t sc_device_id; unsigned int sc_erasesize; struct mtx sc_mtx; struct disk *sc_disk; struct proc *sc_p; struct bio_queue_head sc_bio_queue; unsigned int sc_flags; unsigned int sc_taskstate; uint8_t sc_dummybuf[FLASH_PAGE_SIZE]; }; #define TSTATE_STOPPED 0 #define TSTATE_STOPPING 1 #define TSTATE_RUNNING 2 #define M25PXX_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) #define M25PXX_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) #define M25PXX_LOCK_INIT(_sc) \ mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->sc_dev), \ "mx25l", MTX_DEF) #define M25PXX_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx); #define M25PXX_ASSERT_LOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED); #define M25PXX_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED); /* disk routines */ static int mx25l_open(struct disk *dp); static int mx25l_close(struct disk *dp); static int mx25l_ioctl(struct disk *, u_long, void *, int, struct thread *); static void mx25l_strategy(struct bio *bp); static int mx25l_getattr(struct bio *bp); static void mx25l_task(void *arg); static struct mx25l_flash_ident flash_devices[] = { { "en25f32", 0x1c, 0x3116, 64 * 1024, 64, FL_NONE }, { "en25p32", 0x1c, 0x2016, 64 * 1024, 64, FL_NONE }, { "en25p64", 0x1c, 0x2017, 64 * 1024, 128, FL_NONE }, { "en25q32", 0x1c, 0x3016, 64 * 1024, 64, FL_NONE }, { "en25q64", 0x1c, 0x3017, 64 * 1024, 128, FL_ERASE_4K }, { "m25p32", 0x20, 0x2016, 64 * 1024, 64, FL_NONE }, { "m25p64", 0x20, 0x2017, 64 * 1024, 128, FL_NONE }, { "mx25l1606e", 0xc2, 0x2015, 64 * 1024, 32, FL_ERASE_4K}, { "mx25ll32", 0xc2, 0x2016, 64 * 1024, 64, FL_NONE }, { "mx25ll64", 0xc2, 0x2017, 64 * 1024, 128, FL_NONE }, { "mx25ll128", 0xc2, 0x2018, 64 * 1024, 256, FL_ERASE_4K | FL_ERASE_32K }, { "mx25ll256", 0xc2, 0x2019, 64 * 1024, 512, FL_ERASE_4K | FL_ERASE_32K | FL_ENABLE_4B_ADDR }, { "s25fl032", 0x01, 0x0215, 64 * 1024, 64, FL_NONE }, { "s25fl064", 0x01, 0x0216, 64 * 1024, 128, FL_NONE }, { "s25fl128", 0x01, 0x2018, 64 * 1024, 256, FL_NONE }, { "s25fl256s", 0x01, 0x0219, 64 * 1024, 512, FL_NONE }, { "SST25VF010A", 0xbf, 0x2549, 4 * 1024, 32, FL_ERASE_4K | FL_ERASE_32K }, { "SST25VF032B", 0xbf, 0x254a, 64 * 1024, 64, FL_ERASE_4K | FL_ERASE_32K }, /* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */ { "w25x32", 0xef, 0x3016, 64 * 1024, 64, FL_ERASE_4K }, { "w25x64", 0xef, 0x3017, 64 * 1024, 128, FL_ERASE_4K }, { "w25q32", 0xef, 0x4016, 64 * 1024, 64, FL_ERASE_4K }, { "w25q64", 0xef, 0x4017, 64 * 1024, 128, FL_ERASE_4K }, { "w25q64bv", 0xef, 0x4017, 64 * 1024, 128, FL_ERASE_4K }, { "w25q128", 0xef, 0x4018, 64 * 1024, 256, FL_ERASE_4K }, { "w25q256", 0xef, 0x4019, 64 * 1024, 512, FL_ERASE_4K }, /* Atmel */ { "at25df641", 0x1f, 0x4800, 64 * 1024, 128, FL_ERASE_4K }, /* GigaDevice */ { "gd25q64", 0xc8, 0x4017, 64 * 1024, 128, FL_ERASE_4K }, { "gd25q128", 0xc8, 0x4018, 64 * 1024, 256, FL_ERASE_4K }, }; static int mx25l_wait_for_device_ready(struct mx25l_softc *sc) { uint8_t txBuf[2], rxBuf[2]; struct spi_command cmd; int err; memset(&cmd, 0, sizeof(cmd)); do { txBuf[0] = CMD_READ_STATUS; cmd.tx_cmd = txBuf; cmd.rx_cmd = rxBuf; cmd.rx_cmd_sz = 2; cmd.tx_cmd_sz = 2; err = SPIBUS_TRANSFER(sc->sc_parent, sc->sc_dev, &cmd); } while (err == 0 && (rxBuf[1] & STATUS_WIP)); return (err); } static struct mx25l_flash_ident* mx25l_get_device_ident(struct mx25l_softc *sc) { uint8_t txBuf[8], rxBuf[8]; struct spi_command cmd; uint8_t manufacturer_id; uint16_t dev_id; int err, i; memset(&cmd, 0, sizeof(cmd)); memset(txBuf, 0, sizeof(txBuf)); memset(rxBuf, 0, sizeof(rxBuf)); txBuf[0] = CMD_READ_IDENT; cmd.tx_cmd = &txBuf; cmd.rx_cmd = &rxBuf; /* * Some compatible devices has extended two-bytes ID * We'll use only manufacturer/deviceid atm */ cmd.tx_cmd_sz = 4; cmd.rx_cmd_sz = 4; err = SPIBUS_TRANSFER(sc->sc_parent, sc->sc_dev, &cmd); if (err) return (NULL); manufacturer_id = rxBuf[1]; dev_id = (rxBuf[2] << 8) | (rxBuf[3]); for (i = 0; i < nitems(flash_devices); i++) { if ((flash_devices[i].manufacturer_id == manufacturer_id) && (flash_devices[i].device_id == dev_id)) return &flash_devices[i]; } device_printf(sc->sc_dev, "Unknown SPI flash device. Vendor: %02x, device id: %04x\n", manufacturer_id, dev_id); return (NULL); } static int mx25l_set_writable(struct mx25l_softc *sc, int writable) { uint8_t txBuf[1], rxBuf[1]; struct spi_command cmd; int err; memset(&cmd, 0, sizeof(cmd)); memset(txBuf, 0, sizeof(txBuf)); memset(rxBuf, 0, sizeof(rxBuf)); txBuf[0] = writable ? CMD_WRITE_ENABLE : CMD_WRITE_DISABLE; cmd.tx_cmd = txBuf; cmd.rx_cmd = rxBuf; cmd.rx_cmd_sz = 1; cmd.tx_cmd_sz = 1; err = SPIBUS_TRANSFER(sc->sc_parent, sc->sc_dev, &cmd); return (err); } static int mx25l_erase_cmd(struct mx25l_softc *sc, off_t sector) { uint8_t txBuf[5], rxBuf[5]; struct spi_command cmd; int err; if ((err = mx25l_set_writable(sc, 1)) != 0) return (err); memset(&cmd, 0, sizeof(cmd)); memset(txBuf, 0, sizeof(txBuf)); memset(rxBuf, 0, sizeof(rxBuf)); cmd.tx_cmd = txBuf; cmd.rx_cmd = rxBuf; if (sc->sc_flags & FL_ERASE_4K) txBuf[0] = CMD_BLOCK_4K_ERASE; else if (sc->sc_flags & FL_ERASE_32K) txBuf[0] = CMD_BLOCK_32K_ERASE; else txBuf[0] = CMD_SECTOR_ERASE; if (sc->sc_flags & FL_ENABLE_4B_ADDR) { cmd.rx_cmd_sz = 5; cmd.tx_cmd_sz = 5; txBuf[1] = ((sector >> 24) & 0xff); txBuf[2] = ((sector >> 16) & 0xff); txBuf[3] = ((sector >> 8) & 0xff); txBuf[4] = (sector & 0xff); } else { cmd.rx_cmd_sz = 4; cmd.tx_cmd_sz = 4; txBuf[1] = ((sector >> 16) & 0xff); txBuf[2] = ((sector >> 8) & 0xff); txBuf[3] = (sector & 0xff); } if ((err = SPIBUS_TRANSFER(sc->sc_parent, sc->sc_dev, &cmd)) != 0) return (err); err = mx25l_wait_for_device_ready(sc); return (err); } static int mx25l_write(struct mx25l_softc *sc, off_t offset, caddr_t data, off_t count) { uint8_t txBuf[8], rxBuf[8]; struct spi_command cmd; off_t bytes_to_write; int err = 0; if (sc->sc_flags & FL_ENABLE_4B_ADDR) { cmd.tx_cmd_sz = 5; cmd.rx_cmd_sz = 5; } else { cmd.tx_cmd_sz = 4; cmd.rx_cmd_sz = 4; } /* * Writes must be aligned to the erase sectorsize, since blocks are * fully erased before they're written to. */ if (count % sc->sc_erasesize != 0 || offset % sc->sc_erasesize != 0) return (EIO); /* * Maximum write size for CMD_PAGE_PROGRAM is FLASH_PAGE_SIZE, so loop * to write chunks of FLASH_PAGE_SIZE bytes each. */ while (count != 0) { /* If we crossed a sector boundary, erase the next sector. */ if (((offset) % sc->sc_erasesize) == 0) { err = mx25l_erase_cmd(sc, offset); if (err) break; } txBuf[0] = CMD_PAGE_PROGRAM; if (sc->sc_flags & FL_ENABLE_4B_ADDR) { txBuf[1] = (offset >> 24) & 0xff; txBuf[2] = (offset >> 16) & 0xff; txBuf[3] = (offset >> 8) & 0xff; txBuf[4] = offset & 0xff; } else { txBuf[1] = (offset >> 16) & 0xff; txBuf[2] = (offset >> 8) & 0xff; txBuf[3] = offset & 0xff; } bytes_to_write = MIN(FLASH_PAGE_SIZE, count); cmd.tx_cmd = txBuf; cmd.rx_cmd = rxBuf; cmd.tx_data = data; cmd.rx_data = sc->sc_dummybuf; cmd.tx_data_sz = (uint32_t)bytes_to_write; cmd.rx_data_sz = (uint32_t)bytes_to_write; /* * Each completed write operation resets WEL (write enable * latch) to disabled state, so we re-enable it here. */ if ((err = mx25l_wait_for_device_ready(sc)) != 0) break; if ((err = mx25l_set_writable(sc, 1)) != 0) break; err = SPIBUS_TRANSFER(sc->sc_parent, sc->sc_dev, &cmd); if (err != 0) break; err = mx25l_wait_for_device_ready(sc); if (err) break; data += bytes_to_write; offset += bytes_to_write; count -= bytes_to_write; } return (err); } static int mx25l_read(struct mx25l_softc *sc, off_t offset, caddr_t data, off_t count) { uint8_t txBuf[8], rxBuf[8]; struct spi_command cmd; int err = 0; /* * Enforce that reads are aligned to the disk sectorsize, not the * erase sectorsize. In this way, smaller read IO is possible, * dramatically speeding up filesystem/geom_compress access. */ if (count % sc->sc_disk->d_sectorsize != 0 || offset % sc->sc_disk->d_sectorsize != 0) return (EIO); txBuf[0] = CMD_FAST_READ; if (sc->sc_flags & FL_ENABLE_4B_ADDR) { cmd.tx_cmd_sz = 6; cmd.rx_cmd_sz = 6; txBuf[1] = (offset >> 24) & 0xff; txBuf[2] = (offset >> 16) & 0xff; txBuf[3] = (offset >> 8) & 0xff; txBuf[4] = offset & 0xff; /* Dummy byte */ txBuf[5] = 0; } else { cmd.tx_cmd_sz = 5; cmd.rx_cmd_sz = 5; txBuf[1] = (offset >> 16) & 0xff; txBuf[2] = (offset >> 8) & 0xff; txBuf[3] = offset & 0xff; /* Dummy byte */ txBuf[4] = 0; } cmd.tx_cmd = txBuf; cmd.rx_cmd = rxBuf; cmd.tx_data = data; cmd.rx_data = data; cmd.tx_data_sz = count; cmd.rx_data_sz = count; err = SPIBUS_TRANSFER(sc->sc_parent, sc->sc_dev, &cmd); return (err); } static int mx25l_set_4b_mode(struct mx25l_softc *sc, uint8_t command) { uint8_t txBuf[1], rxBuf[1]; struct spi_command cmd; int err; memset(&cmd, 0, sizeof(cmd)); memset(txBuf, 0, sizeof(txBuf)); memset(rxBuf, 0, sizeof(rxBuf)); cmd.tx_cmd_sz = cmd.rx_cmd_sz = 1; cmd.tx_cmd = txBuf; cmd.rx_cmd = rxBuf; txBuf[0] = command; if ((err = SPIBUS_TRANSFER(sc->sc_parent, sc->sc_dev, &cmd)) == 0) err = mx25l_wait_for_device_ready(sc); return (err); } #ifdef FDT static struct ofw_compat_data compat_data[] = { { "st,m25p", 1 }, { "jedec,spi-nor", 1 }, { NULL, 0 }, }; #endif static int mx25l_probe(device_t dev) { #ifdef FDT int i; if (!ofw_bus_status_okay(dev)) return (ENXIO); /* First try to match the compatible property to the compat_data */ if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 1) goto found; /* * Next, try to find a compatible device using the names in the * flash_devices structure */ for (i = 0; i < nitems(flash_devices); i++) if (ofw_bus_is_compatible(dev, flash_devices[i].name)) goto found; return (ENXIO); found: #endif device_set_desc(dev, "M25Pxx Flash Family"); return (0); } static int mx25l_attach(device_t dev) { struct mx25l_softc *sc; struct mx25l_flash_ident *ident; int err; sc = device_get_softc(dev); sc->sc_dev = dev; sc->sc_parent = device_get_parent(sc->sc_dev); M25PXX_LOCK_INIT(sc); ident = mx25l_get_device_ident(sc); if (ident == NULL) return (ENXIO); if ((err = mx25l_wait_for_device_ready(sc)) != 0) return (err); sc->sc_flags = ident->flags; if (sc->sc_flags & FL_ERASE_4K) sc->sc_erasesize = 4 * 1024; else if (sc->sc_flags & FL_ERASE_32K) sc->sc_erasesize = 32 * 1024; else sc->sc_erasesize = ident->sectorsize; if (sc->sc_flags & FL_ENABLE_4B_ADDR) { if ((err = mx25l_set_4b_mode(sc, CMD_ENTER_4B_MODE)) != 0) return (err); } else if (sc->sc_flags & FL_DISABLE_4B_ADDR) { if ((err = mx25l_set_4b_mode(sc, CMD_EXIT_4B_MODE)) != 0) return (err); } sc->sc_disk = disk_alloc(); sc->sc_disk->d_open = mx25l_open; sc->sc_disk->d_close = mx25l_close; sc->sc_disk->d_strategy = mx25l_strategy; sc->sc_disk->d_getattr = mx25l_getattr; sc->sc_disk->d_ioctl = mx25l_ioctl; sc->sc_disk->d_name = "flash/spi"; sc->sc_disk->d_drv1 = sc; sc->sc_disk->d_maxsize = DFLTPHYS; sc->sc_disk->d_sectorsize = MX25L_SECTORSIZE; sc->sc_disk->d_mediasize = ident->sectorsize * ident->sectorcount; sc->sc_disk->d_stripesize = sc->sc_erasesize; sc->sc_disk->d_unit = device_get_unit(sc->sc_dev); sc->sc_disk->d_dump = NULL; /* NB: no dumps */ strlcpy(sc->sc_disk->d_descr, ident->name, sizeof(sc->sc_disk->d_descr)); disk_create(sc->sc_disk, DISK_VERSION); bioq_init(&sc->sc_bio_queue); kproc_create(&mx25l_task, sc, &sc->sc_p, 0, 0, "task: mx25l flash"); sc->sc_taskstate = TSTATE_RUNNING; device_printf(sc->sc_dev, "device type %s, size %dK in %d sectors of %dK, erase size %dK\n", ident->name, ident->sectorcount * ident->sectorsize / 1024, ident->sectorcount, ident->sectorsize / 1024, sc->sc_erasesize / 1024); return (0); } static int mx25l_detach(device_t dev) { struct mx25l_softc *sc; int err; sc = device_get_softc(dev); err = 0; M25PXX_LOCK(sc); if (sc->sc_taskstate == TSTATE_RUNNING) { sc->sc_taskstate = TSTATE_STOPPING; wakeup(sc); while (err == 0 && sc->sc_taskstate != TSTATE_STOPPED) { err = msleep(sc, &sc->sc_mtx, 0, "mx25dt", hz * 3); if (err != 0) { sc->sc_taskstate = TSTATE_RUNNING; device_printf(sc->sc_dev, "Failed to stop queue task\n"); } } } M25PXX_UNLOCK(sc); if (err == 0 && sc->sc_taskstate == TSTATE_STOPPED) { disk_destroy(sc->sc_disk); bioq_flush(&sc->sc_bio_queue, NULL, ENXIO); M25PXX_LOCK_DESTROY(sc); } return (err); } static int mx25l_open(struct disk *dp) { return (0); } static int mx25l_close(struct disk *dp) { return (0); } static int mx25l_ioctl(struct disk *dp, u_long cmd, void *data, int fflag, struct thread *td) { return (EINVAL); } static void mx25l_strategy(struct bio *bp) { struct mx25l_softc *sc; sc = (struct mx25l_softc *)bp->bio_disk->d_drv1; M25PXX_LOCK(sc); bioq_disksort(&sc->sc_bio_queue, bp); wakeup(sc); M25PXX_UNLOCK(sc); } static int mx25l_getattr(struct bio *bp) { struct mx25l_softc *sc; device_t dev; if (bp->bio_disk == NULL || bp->bio_disk->d_drv1 == NULL) return (ENXIO); sc = bp->bio_disk->d_drv1; dev = sc->sc_dev; if (strcmp(bp->bio_attribute, "SPI::device") == 0) { if (bp->bio_length != sizeof(dev)) return (EFAULT); bcopy(&dev, bp->bio_data, sizeof(dev)); } else return (-1); return (0); } static void mx25l_task(void *arg) { struct mx25l_softc *sc = (struct mx25l_softc*)arg; struct bio *bp; device_t dev; for (;;) { dev = sc->sc_dev; M25PXX_LOCK(sc); do { if (sc->sc_taskstate == TSTATE_STOPPING) { sc->sc_taskstate = TSTATE_STOPPED; M25PXX_UNLOCK(sc); wakeup(sc); kproc_exit(0); } bp = bioq_first(&sc->sc_bio_queue); if (bp == NULL) msleep(sc, &sc->sc_mtx, PRIBIO, "mx25jq", 0); } while (bp == NULL); bioq_remove(&sc->sc_bio_queue, bp); M25PXX_UNLOCK(sc); switch (bp->bio_cmd) { case BIO_READ: bp->bio_error = mx25l_read(sc, bp->bio_offset, bp->bio_data, bp->bio_bcount); break; case BIO_WRITE: bp->bio_error = mx25l_write(sc, bp->bio_offset, bp->bio_data, bp->bio_bcount); break; default: bp->bio_error = EINVAL; } biodone(bp); } } static devclass_t mx25l_devclass; static device_method_t mx25l_methods[] = { /* Device interface */ DEVMETHOD(device_probe, mx25l_probe), DEVMETHOD(device_attach, mx25l_attach), DEVMETHOD(device_detach, mx25l_detach), { 0, 0 } }; static driver_t mx25l_driver = { "mx25l", mx25l_methods, sizeof(struct mx25l_softc), }; DRIVER_MODULE(mx25l, spibus, mx25l_driver, mx25l_devclass, 0, 0); MODULE_DEPEND(mx25l, spibus, 1, 1, 1); #ifdef FDT MODULE_DEPEND(mx25l, fdt_slicer, 1, 1, 1); SPIBUS_FDT_PNP_INFO(compat_data); #endif Index: head/sys/dev/flash/n25q.c =================================================================== --- head/sys/dev/flash/n25q.c (revision 355393) +++ head/sys/dev/flash/n25q.c (revision 355394) @@ -1,490 +1,489 @@ /*- - * Copyright (c) 2006 M. Warner Losh. * Copyright (c) 2009 Oleksandr Tymoshenko. All rights reserved. * Copyright (c) 2017 Ruslan Bukin * Copyright (c) 2018 Ian Lepore. All rights reserved. - * All rights reserved. + * Copyright (c) 2006 M. Warner Losh * * This software was developed by SRI International and the University of * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237 * ("CTSRD"), as part of the DARPA CRASH research programme. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* n25q Quad SPI Flash driver. */ #include __FBSDID("$FreeBSD$"); #include "opt_platform.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "qspi_if.h" #define N25Q_DEBUG #undef N25Q_DEBUG #ifdef N25Q_DEBUG #define dprintf(fmt, ...) printf(fmt, ##__VA_ARGS__) #else #define dprintf(fmt, ...) #endif #define FL_NONE 0x00 #define FL_ERASE_4K 0x01 #define FL_ERASE_32K 0x02 #define FL_ENABLE_4B_ADDR 0x04 #define FL_DISABLE_4B_ADDR 0x08 /* * Define the sectorsize to be a smaller size rather than the flash * sector size. Trying to run FFS off of a 64k flash sector size * results in a completely un-usable system. */ #define FLASH_SECTORSIZE 512 struct n25q_flash_ident { const char *name; uint8_t manufacturer_id; uint16_t device_id; unsigned int sectorsize; unsigned int sectorcount; unsigned int flags; }; struct n25q_softc { device_t dev; bus_space_tag_t bst; bus_space_handle_t bsh; void *ih; struct resource *res[3]; uint8_t sc_manufacturer_id; uint16_t device_id; unsigned int sc_sectorsize; struct mtx sc_mtx; struct disk *sc_disk; struct proc *sc_p; struct bio_queue_head sc_bio_queue; unsigned int sc_flags; unsigned int sc_taskstate; }; #define TSTATE_STOPPED 0 #define TSTATE_STOPPING 1 #define TSTATE_RUNNING 2 #define N25Q_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) #define N25Q_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) #define N25Q_LOCK_INIT(_sc) \ mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->dev), \ "n25q", MTX_DEF) #define N25Q_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx); #define N25Q_ASSERT_LOCKED(_sc) \ mtx_assert(&_sc->sc_mtx, MA_OWNED); #define N25Q_ASSERT_UNLOCKED(_sc) \ mtx_assert(&_sc->sc_mtx, MA_NOTOWNED); static struct ofw_compat_data compat_data[] = { { "n25q00aa", 1 }, { NULL, 0 }, }; /* disk routines */ static int n25q_open(struct disk *dp); static int n25q_close(struct disk *dp); static int n25q_ioctl(struct disk *, u_long, void *, int, struct thread *); static void n25q_strategy(struct bio *bp); static int n25q_getattr(struct bio *bp); static void n25q_task(void *arg); static struct n25q_flash_ident flash_devices[] = { { "n25q00", 0x20, 0xbb21, (64 * 1024), 2048, FL_ENABLE_4B_ADDR}, }; static int n25q_wait_for_device_ready(device_t dev) { device_t pdev; uint8_t status; int err; pdev = device_get_parent(dev); do { err = QSPI_READ_REG(pdev, dev, CMD_READ_STATUS, &status, 1); } while (err == 0 && (status & STATUS_WIP)); return (err); } static struct n25q_flash_ident* n25q_get_device_ident(struct n25q_softc *sc) { uint8_t manufacturer_id; uint16_t dev_id; device_t pdev; uint8_t data[4]; int i; pdev = device_get_parent(sc->dev); QSPI_READ_REG(pdev, sc->dev, CMD_READ_IDENT, (uint8_t *)&data[0], 4); manufacturer_id = data[0]; dev_id = (data[1] << 8) | (data[2]); for (i = 0; i < nitems(flash_devices); i++) { if ((flash_devices[i].manufacturer_id == manufacturer_id) && (flash_devices[i].device_id == dev_id)) return &flash_devices[i]; } printf("Unknown SPI flash device. Vendor: %02x, device id: %04x\n", manufacturer_id, dev_id); return (NULL); } static int n25q_write(device_t dev, struct bio *bp, off_t offset, caddr_t data, off_t count) { struct n25q_softc *sc; device_t pdev; int err; pdev = device_get_parent(dev); sc = device_get_softc(dev); dprintf("%s: offset 0x%llx count %lld bytes\n", __func__, offset, count); err = QSPI_ERASE(pdev, dev, offset); if (err != 0) { return (err); } err = QSPI_WRITE(pdev, dev, bp, offset, data, count); return (err); } static int n25q_read(device_t dev, struct bio *bp, off_t offset, caddr_t data, off_t count) { struct n25q_softc *sc; device_t pdev; int err; pdev = device_get_parent(dev); sc = device_get_softc(dev); dprintf("%s: offset 0x%llx count %lld bytes\n", __func__, offset, count); /* * Enforce the disk read sectorsize not the erase sectorsize. * In this way, smaller read IO is possible,dramatically * speeding up filesystem/geom_compress access. */ if (count % sc->sc_disk->d_sectorsize != 0 || offset % sc->sc_disk->d_sectorsize != 0) { printf("EIO\n"); return (EIO); } err = QSPI_READ(pdev, dev, bp, offset, data, count); return (err); } static int n25q_set_4b_mode(device_t dev, uint8_t command) { struct n25q_softc *sc; device_t pdev; int err; pdev = device_get_parent(dev); sc = device_get_softc(dev); err = QSPI_WRITE_REG(pdev, dev, command, 0, 0); return (err); } static int n25q_probe(device_t dev) { int i; if (!ofw_bus_status_okay(dev)) return (ENXIO); /* First try to match the compatible property to the compat_data */ if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 1) goto found; /* * Next, try to find a compatible device using the names in the * flash_devices structure */ for (i = 0; i < nitems(flash_devices); i++) if (ofw_bus_is_compatible(dev, flash_devices[i].name)) goto found; return (ENXIO); found: device_set_desc(dev, "Micron n25q"); return (0); } static int n25q_attach(device_t dev) { struct n25q_flash_ident *ident; struct n25q_softc *sc; sc = device_get_softc(dev); sc->dev = dev; N25Q_LOCK_INIT(sc); ident = n25q_get_device_ident(sc); if (ident == NULL) { return (ENXIO); } n25q_wait_for_device_ready(sc->dev); sc->sc_disk = disk_alloc(); sc->sc_disk->d_open = n25q_open; sc->sc_disk->d_close = n25q_close; sc->sc_disk->d_strategy = n25q_strategy; sc->sc_disk->d_getattr = n25q_getattr; sc->sc_disk->d_ioctl = n25q_ioctl; sc->sc_disk->d_name = "flash/qspi"; sc->sc_disk->d_drv1 = sc; sc->sc_disk->d_maxsize = DFLTPHYS; sc->sc_disk->d_sectorsize = FLASH_SECTORSIZE; sc->sc_disk->d_mediasize = (ident->sectorsize * ident->sectorcount); sc->sc_disk->d_unit = device_get_unit(sc->dev); sc->sc_disk->d_dump = NULL; /* Sectorsize for erase operations */ sc->sc_sectorsize = ident->sectorsize; sc->sc_flags = ident->flags; if (sc->sc_flags & FL_ENABLE_4B_ADDR) n25q_set_4b_mode(dev, CMD_ENTER_4B_MODE); if (sc->sc_flags & FL_DISABLE_4B_ADDR) n25q_set_4b_mode(dev, CMD_EXIT_4B_MODE); /* NB: use stripesize to hold the erase/region size for RedBoot */ sc->sc_disk->d_stripesize = ident->sectorsize; disk_create(sc->sc_disk, DISK_VERSION); bioq_init(&sc->sc_bio_queue); kproc_create(&n25q_task, sc, &sc->sc_p, 0, 0, "task: n25q flash"); sc->sc_taskstate = TSTATE_RUNNING; device_printf(sc->dev, "%s, sector %d bytes, %d sectors\n", ident->name, ident->sectorsize, ident->sectorcount); return (0); } static int n25q_detach(device_t dev) { struct n25q_softc *sc; int err; sc = device_get_softc(dev); err = 0; N25Q_LOCK(sc); if (sc->sc_taskstate == TSTATE_RUNNING) { sc->sc_taskstate = TSTATE_STOPPING; wakeup(sc); while (err == 0 && sc->sc_taskstate != TSTATE_STOPPED) { err = msleep(sc, &sc->sc_mtx, 0, "n25q", hz * 3); if (err != 0) { sc->sc_taskstate = TSTATE_RUNNING; device_printf(sc->dev, "Failed to stop queue task\n"); } } } N25Q_UNLOCK(sc); if (err == 0 && sc->sc_taskstate == TSTATE_STOPPED) { disk_destroy(sc->sc_disk); bioq_flush(&sc->sc_bio_queue, NULL, ENXIO); N25Q_LOCK_DESTROY(sc); } return (err); } static int n25q_open(struct disk *dp) { return (0); } static int n25q_close(struct disk *dp) { return (0); } static int n25q_ioctl(struct disk *dp, u_long cmd, void *data, int fflag, struct thread *td) { return (EINVAL); } static void n25q_strategy(struct bio *bp) { struct n25q_softc *sc; sc = (struct n25q_softc *)bp->bio_disk->d_drv1; N25Q_LOCK(sc); bioq_disksort(&sc->sc_bio_queue, bp); wakeup(sc); N25Q_UNLOCK(sc); } static int n25q_getattr(struct bio *bp) { struct n25q_softc *sc; device_t dev; if (bp->bio_disk == NULL || bp->bio_disk->d_drv1 == NULL) { return (ENXIO); } sc = bp->bio_disk->d_drv1; dev = sc->dev; if (strcmp(bp->bio_attribute, "SPI::device") == 0) { if (bp->bio_length != sizeof(dev)) { return (EFAULT); } bcopy(&dev, bp->bio_data, sizeof(dev)); return (0); } return (-1); } static void n25q_task(void *arg) { struct n25q_softc *sc; struct bio *bp; device_t dev; sc = (struct n25q_softc *)arg; dev = sc->dev; for (;;) { N25Q_LOCK(sc); do { if (sc->sc_taskstate == TSTATE_STOPPING) { sc->sc_taskstate = TSTATE_STOPPED; N25Q_UNLOCK(sc); wakeup(sc); kproc_exit(0); } bp = bioq_first(&sc->sc_bio_queue); if (bp == NULL) msleep(sc, &sc->sc_mtx, PRIBIO, "jobqueue", hz); } while (bp == NULL); bioq_remove(&sc->sc_bio_queue, bp); N25Q_UNLOCK(sc); switch (bp->bio_cmd) { case BIO_READ: bp->bio_error = n25q_read(dev, bp, bp->bio_offset, bp->bio_data, bp->bio_bcount); break; case BIO_WRITE: bp->bio_error = n25q_write(dev, bp, bp->bio_offset, bp->bio_data, bp->bio_bcount); break; default: bp->bio_error = EINVAL; } biodone(bp); } } static devclass_t n25q_devclass; static device_method_t n25q_methods[] = { /* Device interface */ DEVMETHOD(device_probe, n25q_probe), DEVMETHOD(device_attach, n25q_attach), DEVMETHOD(device_detach, n25q_detach), { 0, 0 } }; static driver_t n25q_driver = { "n25q", n25q_methods, sizeof(struct n25q_softc), }; DRIVER_MODULE(n25q, simplebus, n25q_driver, n25q_devclass, 0, 0); Index: head/sys/dev/iicbus/icee.c =================================================================== --- head/sys/dev/iicbus/icee.c (revision 355393) +++ head/sys/dev/iicbus/icee.c (revision 355394) @@ -1,395 +1,395 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2006 M. Warner Losh. + * Copyright (c) 2006 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /* * Generic IIC eeprom support, modeled after the AT24C family of products. */ #include "opt_platform.h" #include #include #include #include #include #include #include #include #include #include #include #ifdef FDT #include #include #endif #include #include #include "iicbus_if.h" /* * AT24 parts have a "write page size" that differs per-device, and a "read page * size" that is always equal to the full device size. We define maximum values * here to limit how long we occupy the bus with a single transfer, and because * there are temporary buffers of these sizes allocated on the stack. */ #define MAX_RD_SZ 256 /* Largest read size we support */ #define MAX_WR_SZ 256 /* Largest write size we support */ struct icee_softc { device_t dev; /* Myself */ struct cdev *cdev; /* user interface */ int addr; /* Slave address on the bus */ int size; /* How big am I? */ int type; /* What address type 8 or 16 bit? */ int wr_sz; /* What's the write page size */ }; #ifdef FDT struct eeprom_desc { int type; int size; int wr_sz; const char *name; }; static struct eeprom_desc type_desc[] = { { 8, 128, 8, "AT24C01"}, { 8, 256, 8, "AT24C02"}, { 8, 512, 16, "AT24C04"}, { 8, 1024, 16, "AT24C08"}, { 8, 2 * 1024, 16, "AT24C16"}, {16, 4 * 1024, 32, "AT24C32"}, {16, 8 * 1024, 32, "AT24C64"}, {16, 16 * 1024, 64, "AT24C128"}, {16, 32 * 1024, 64, "AT24C256"}, {16, 64 * 1024, 128, "AT24C512"}, {16, 128 * 1024, 256, "AT24CM01"}, }; static struct ofw_compat_data compat_data[] = { {"atmel,24c01", (uintptr_t)(&type_desc[0])}, {"atmel,24c02", (uintptr_t)(&type_desc[1])}, {"atmel,24c04", (uintptr_t)(&type_desc[2])}, {"atmel,24c08", (uintptr_t)(&type_desc[3])}, {"atmel,24c16", (uintptr_t)(&type_desc[4])}, {"atmel,24c32", (uintptr_t)(&type_desc[5])}, {"atmel,24c64", (uintptr_t)(&type_desc[6])}, {"atmel,24c128", (uintptr_t)(&type_desc[7])}, {"atmel,24c256", (uintptr_t)(&type_desc[8])}, {"atmel,24c512", (uintptr_t)(&type_desc[9])}, {"atmel,24c1024", (uintptr_t)(&type_desc[10])}, {NULL, (uintptr_t)NULL}, }; #endif #define CDEV2SOFTC(dev) ((dev)->si_drv1) /* cdev routines */ static d_open_t icee_open; static d_close_t icee_close; static d_read_t icee_read; static d_write_t icee_write; static struct cdevsw icee_cdevsw = { .d_version = D_VERSION, .d_flags = D_TRACKCLOSE, .d_open = icee_open, .d_close = icee_close, .d_read = icee_read, .d_write = icee_write }; #ifdef FDT static int icee_probe(device_t dev) { struct eeprom_desc *d; if (!ofw_bus_status_okay(dev)) return (ENXIO); d = (struct eeprom_desc *) ofw_bus_search_compatible(dev, compat_data)->ocd_data; if (d == NULL) return (ENXIO); device_set_desc(dev, d->name); return (BUS_PROBE_DEFAULT); } static void icee_init(struct icee_softc *sc) { struct eeprom_desc *d; d = (struct eeprom_desc *) ofw_bus_search_compatible(sc->dev, compat_data)->ocd_data; if (d == NULL) return; /* attach will see sc->size == 0 and return error */ sc->size = d->size; sc->type = d->type; sc->wr_sz = d->wr_sz; } #else /* !FDT */ static int icee_probe(device_t dev) { device_set_desc(dev, "I2C EEPROM"); return (BUS_PROBE_NOWILDCARD); } static void icee_init(struct icee_softc *sc) { const char *dname; int dunit; dname = device_get_name(sc->dev); dunit = device_get_unit(sc->dev); resource_int_value(dname, dunit, "size", &sc->size); resource_int_value(dname, dunit, "type", &sc->type); resource_int_value(dname, dunit, "wr_sz", &sc->wr_sz); } #endif /* FDT */ static int icee_attach(device_t dev) { struct icee_softc *sc = device_get_softc(dev); struct sysctl_ctx_list *ctx; struct sysctl_oid_list *tree; sc->dev = dev; sc->addr = iicbus_get_addr(dev); icee_init(sc); if (sc->size == 0 || sc->type == 0 || sc->wr_sz == 0) { device_printf(sc->dev, "Missing config data, " "these cannot be zero: size %d type %d wr_sz %d\n", sc->size, sc->type, sc->wr_sz); return (EINVAL); } if (bootverbose) device_printf(dev, "size: %d bytes, addressing: %d-bits\n", sc->size, sc->type); sc->cdev = make_dev(&icee_cdevsw, device_get_unit(dev), UID_ROOT, GID_WHEEL, 0600, "icee%d", device_get_unit(dev)); if (sc->cdev == NULL) { return (ENOMEM); } sc->cdev->si_drv1 = sc; ctx = device_get_sysctl_ctx(dev); tree = SYSCTL_CHILDREN(device_get_sysctl_tree(dev)); SYSCTL_ADD_INT(ctx, tree, OID_AUTO, "address_size", CTLFLAG_RD, &sc->type, 0, "Memory array address size in bits"); SYSCTL_ADD_INT(ctx, tree, OID_AUTO, "device_size", CTLFLAG_RD, &sc->size, 0, "Memory array capacity in bytes"); SYSCTL_ADD_INT(ctx, tree, OID_AUTO, "write_size", CTLFLAG_RD, &sc->wr_sz, 0, "Memory array page write size in bytes"); return (0); } static int icee_detach(device_t dev) { struct icee_softc *sc = device_get_softc(dev); destroy_dev(sc->cdev); return (0); } static int icee_open(struct cdev *dev, int oflags, int devtype, struct thread *td) { struct icee_softc *sc; sc = CDEV2SOFTC(dev); if (device_get_state(sc->dev) < DS_BUSY) device_busy(sc->dev); return (0); } static int icee_close(struct cdev *dev, int fflag, int devtype, struct thread *td) { struct icee_softc *sc; sc = CDEV2SOFTC(dev); device_unbusy(sc->dev); return (0); } static int icee_read(struct cdev *dev, struct uio *uio, int ioflag) { struct icee_softc *sc; uint8_t addr[2]; uint8_t data[MAX_RD_SZ]; int error, i, len, slave; struct iic_msg msgs[2] = { { 0, IIC_M_WR, 1, addr }, { 0, IIC_M_RD, 0, data }, }; sc = CDEV2SOFTC(dev); if (uio->uio_offset == sc->size) return (0); if (uio->uio_offset > sc->size) return (EIO); if (sc->type != 8 && sc->type != 16) return (EINVAL); slave = error = 0; while (uio->uio_resid > 0) { if (uio->uio_offset >= sc->size) break; len = MIN(MAX_RD_SZ - (uio->uio_offset & (MAX_RD_SZ - 1)), uio->uio_resid); switch (sc->type) { case 8: slave = (uio->uio_offset >> 7) | sc->addr; msgs[0].len = 1; msgs[1].len = len; addr[0] = uio->uio_offset & 0xff; break; case 16: slave = sc->addr | (uio->uio_offset >> 15); msgs[0].len = 2; msgs[1].len = len; addr[0] = (uio->uio_offset >> 8) & 0xff; addr[1] = uio->uio_offset & 0xff; break; } for (i = 0; i < 2; i++) msgs[i].slave = slave; error = iicbus_transfer_excl(sc->dev, msgs, 2, IIC_INTRWAIT); if (error) { error = iic2errno(error); break; } error = uiomove(data, len, uio); if (error) break; } return (error); } /* * Write to the part. We use three transfers here since we're actually * doing a write followed by a read to make sure that the write finished. * It is easier to encode the dummy read here than to break things up * into smaller chunks... */ static int icee_write(struct cdev *dev, struct uio *uio, int ioflag) { struct icee_softc *sc; int error, len, slave, waitlimit; uint8_t data[MAX_WR_SZ + 2]; struct iic_msg wr[1] = { { 0, IIC_M_WR, 0, data }, }; struct iic_msg rd[1] = { { 0, IIC_M_RD, 1, data }, }; sc = CDEV2SOFTC(dev); if (uio->uio_offset >= sc->size) return (EIO); if (sc->type != 8 && sc->type != 16) return (EINVAL); slave = error = 0; while (uio->uio_resid > 0) { if (uio->uio_offset >= sc->size) break; len = MIN(sc->wr_sz - (uio->uio_offset & (sc->wr_sz - 1)), uio->uio_resid); switch (sc->type) { case 8: slave = (uio->uio_offset >> 7) | sc->addr; wr[0].len = 1 + len; data[0] = uio->uio_offset & 0xff; break; case 16: slave = sc->addr | (uio->uio_offset >> 15); wr[0].len = 2 + len; data[0] = (uio->uio_offset >> 8) & 0xff; data[1] = uio->uio_offset & 0xff; break; } wr[0].slave = slave; error = uiomove(data + sc->type / 8, len, uio); if (error) break; error = iicbus_transfer_excl(sc->dev, wr, 1, IIC_INTRWAIT); if (error) { error = iic2errno(error); break; } /* Read after write to wait for write-done. */ waitlimit = 10000; rd[0].slave = slave; do { error = iicbus_transfer_excl(sc->dev, rd, 1, IIC_INTRWAIT); } while (waitlimit-- > 0 && error != 0); if (error) { error = iic2errno(error); break; } } return error; } static device_method_t icee_methods[] = { DEVMETHOD(device_probe, icee_probe), DEVMETHOD(device_attach, icee_attach), DEVMETHOD(device_detach, icee_detach), DEVMETHOD_END }; static driver_t icee_driver = { "icee", icee_methods, sizeof(struct icee_softc), }; static devclass_t icee_devclass; DRIVER_MODULE(icee, iicbus, icee_driver, icee_devclass, 0, 0); MODULE_VERSION(icee, 1); MODULE_DEPEND(icee, iicbus, 1, 1, 1); IICBUS_FDT_PNP_INFO(compat_data); Index: head/sys/dev/mii/axphy.c =================================================================== --- head/sys/dev/mii/axphy.c (revision 355393) +++ head/sys/dev/mii/axphy.c (revision 355394) @@ -1,179 +1,178 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2009, M. Warner Losh - * All rights reserved. + * Copyright (c) 2009 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice unmodified, this list of conditions, and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /* * driver for internal phy in the AX88x9x chips. */ #include #include #include #include #include #include #include #include #include #include #include "miidevs.h" #include "miibus_if.h" static int axphy_probe(device_t dev); static int axphy_attach(device_t dev); static device_method_t axphy_methods[] = { /* device interface */ DEVMETHOD(device_probe, axphy_probe), DEVMETHOD(device_attach, axphy_attach), DEVMETHOD(device_detach, mii_phy_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD_END }; static devclass_t axphy_devclass; static driver_t axphy_driver = { "axphy", axphy_methods, sizeof(struct mii_softc) }; DRIVER_MODULE(axphy, miibus, axphy_driver, axphy_devclass, 0, 0); static int axphy_service(struct mii_softc *, struct mii_data *, int); static void axphy_status(struct mii_softc *); static const struct mii_phydesc axphys[] = { MII_PHY_DESC(xxASIX, AX88X9X), MII_PHY_END }; static const struct mii_phy_funcs axphy_funcs = { axphy_service, axphy_status, mii_phy_reset }; static int axphy_probe(device_t dev) { return (mii_phy_dev_probe(dev, axphys, BUS_PROBE_DEFAULT)); } static int axphy_attach(device_t dev) { struct mii_softc *sc; sc = device_get_softc(dev); mii_phy_dev_attach(dev, MIIF_NOISOLATE | MIIF_NOMANPAUSE, &axphy_funcs, 1); mii_phy_setmedia(sc); return (0); } static int axphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { switch (cmd) { case MII_POLLSTAT: break; case MII_MEDIACHG: mii_phy_setmedia(sc); break; case MII_TICK: if (mii_phy_tick(sc) == EJUSTRETURN) return (0); break; } /* Update the media status. */ PHY_STATUS(sc); /* Callback if something changed. */ mii_phy_update(sc, cmd); return (0); } static void axphy_status(struct mii_softc *sc) { struct mii_data *mii = sc->mii_pdata; struct ifmedia_entry *ife = mii->mii_media.ifm_cur; int bmsr, bmcr; mii->mii_media_status = IFM_AVALID; mii->mii_media_active = IFM_ETHER; bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); if (bmsr & BMSR_LINK) mii->mii_media_status |= IFM_ACTIVE; bmcr = PHY_READ(sc, MII_BMCR); if (bmcr & BMCR_ISO) { mii->mii_media_active |= IFM_NONE; mii->mii_media_status = 0; return; } if (bmcr & BMCR_LOOP) mii->mii_media_active |= IFM_LOOP; if (bmcr & BMCR_AUTOEN) { if ((bmsr & BMSR_ACOMP) == 0) { mii->mii_media_active |= IFM_NONE; return; } #if 0 scr = PHY_READ(sc, MII_AXPHY_SCR); if (scr & SCR_S100) mii->mii_media_active |= IFM_100_TX; else mii->mii_media_active |= IFM_10_T; if (scr & SCR_FDX) mii->mii_media_active |= IFM_FDX | mii_phy_flowstatus(sc); else mii->mii_media_active |= IFM_HDX; #endif } else mii->mii_media_active = ife->ifm_media; } Index: head/sys/dev/mmc/bridge.h =================================================================== --- head/sys/dev/mmc/bridge.h (revision 355393) +++ head/sys/dev/mmc/bridge.h (revision 355394) @@ -1,194 +1,194 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2006 M. Warner Losh. + * Copyright (c) 2006 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Portions of this software may have been developed with reference to * the SD Simplified Specification. The following disclaimer may apply: * * The following conditions apply to the release of the simplified * specification ("Simplified Specification") by the SD Card Association and * the SD Group. The Simplified Specification is a subset of the complete SD * Specification which is owned by the SD Card Association and the SD * Group. This Simplified Specification is provided on a non-confidential * basis subject to the disclaimers below. Any implementation of the * Simplified Specification may require a license from the SD Card * Association, SD Group, SD-3C LLC or other third parties. * * Disclaimers: * * The information contained in the Simplified Specification is presented only * as a standard specification for SD Cards and SD Host/Ancillary products and * is provided "AS-IS" without any representations or warranties of any * kind. No responsibility is assumed by the SD Group, SD-3C LLC or the SD * Card Association for any damages, any infringements of patents or other * right of the SD Group, SD-3C LLC, the SD Card Association or any third * parties, which may result from its use. No license is granted by * implication, estoppel or otherwise under any patent or other rights of the * SD Group, SD-3C LLC, the SD Card Association or any third party. Nothing * herein shall be construed as an obligation by the SD Group, the SD-3C LLC * or the SD Card Association to disclose or distribute any technical * information, know-how or other confidential information to any third party. * * $FreeBSD$ */ #ifndef DEV_MMC_BRIDGE_H #define DEV_MMC_BRIDGE_H #include /* * This file defines interfaces for the mmc bridge. The names chosen * are similar to or the same as the names used in Linux to allow for * easy porting of what Linux calls mmc host drivers. I use the * FreeBSD terminology of bridge and bus for consistency with other * drivers in the system. This file corresponds roughly to the Linux * linux/mmc/host.h file. * * A mmc bridge is a chipset that can have one or more mmc and/or sd * cards attached to it. mmc devices are attached on a bus topology, * while sd and sdio cards usually are attached using a star topology * (meaning in practice each sd card has its own, independent slot). * Since SDHCI v3.00, buses for esd and esdio are possible, though. * * Attached to the mmc bridge is an mmcbus. The mmcbus is described * in dev/mmc/mmcbus_if.m. */ /* * mmc_ios is a structure that is used to store the state of the mmc/sd * bus configuration. This include the bus' clock speed, its voltage, * the bus mode for command output, the SPI chip select, some power * states and the bus width. */ enum mmc_vdd { vdd_150 = 0, vdd_155, vdd_160, vdd_165, vdd_170, vdd_180, vdd_190, vdd_200, vdd_210, vdd_220, vdd_230, vdd_240, vdd_250, vdd_260, vdd_270, vdd_280, vdd_290, vdd_300, vdd_310, vdd_320, vdd_330, vdd_340, vdd_350, vdd_360 }; enum mmc_vccq { vccq_120 = 0, vccq_180, vccq_330 }; enum mmc_power_mode { power_off = 0, power_up, power_on }; enum mmc_bus_mode { opendrain = 1, pushpull }; enum mmc_chip_select { cs_dontcare = 0, cs_high, cs_low }; enum mmc_bus_width { bus_width_1 = 0, bus_width_4 = 2, bus_width_8 = 3 }; enum mmc_drv_type { drv_type_b = 0, drv_type_a, drv_type_c, drv_type_d }; enum mmc_bus_timing { bus_timing_normal = 0, bus_timing_hs, bus_timing_uhs_sdr12, bus_timing_uhs_sdr25, bus_timing_uhs_sdr50, bus_timing_uhs_ddr50, bus_timing_uhs_sdr104, bus_timing_mmc_ddr52, bus_timing_mmc_hs200, bus_timing_mmc_hs400, bus_timing_mmc_hs400es, bus_timing_max = bus_timing_mmc_hs400es }; struct mmc_ios { uint32_t clock; /* Speed of the clock in Hz to move data */ enum mmc_vdd vdd; /* Voltage to apply to the power pins */ enum mmc_vccq vccq; /* Voltage to use for signaling */ enum mmc_bus_mode bus_mode; enum mmc_chip_select chip_select; enum mmc_bus_width bus_width; enum mmc_power_mode power_mode; enum mmc_bus_timing timing; enum mmc_drv_type drv_type; }; enum mmc_card_mode { mode_mmc, mode_sd }; enum mmc_retune_req { retune_req_none = 0, retune_req_normal, retune_req_reset }; struct mmc_host { int f_min; int f_max; uint32_t host_ocr; uint32_t ocr; uint32_t caps; #define MMC_CAP_4_BIT_DATA (1 << 0) /* Can do 4-bit data transfers */ #define MMC_CAP_8_BIT_DATA (1 << 1) /* Can do 8-bit data transfers */ #define MMC_CAP_HSPEED (1 << 2) /* Can do High Speed transfers */ #define MMC_CAP_BOOT_NOACC (1 << 4) /* Cannot access boot partitions */ #define MMC_CAP_WAIT_WHILE_BUSY (1 << 5) /* Host waits for busy responses */ #define MMC_CAP_UHS_SDR12 (1 << 6) /* Can do UHS SDR12 */ #define MMC_CAP_UHS_SDR25 (1 << 7) /* Can do UHS SDR25 */ #define MMC_CAP_UHS_SDR50 (1 << 8) /* Can do UHS SDR50 */ #define MMC_CAP_UHS_SDR104 (1 << 9) /* Can do UHS SDR104 */ #define MMC_CAP_UHS_DDR50 (1 << 10) /* Can do UHS DDR50 */ #define MMC_CAP_MMC_DDR52_120 (1 << 11) /* Can do eMMC DDR52 at 1.2 V */ #define MMC_CAP_MMC_DDR52_180 (1 << 12) /* Can do eMMC DDR52 at 1.8 V */ #define MMC_CAP_MMC_DDR52 (MMC_CAP_MMC_DDR52_120 | MMC_CAP_MMC_DDR52_180) #define MMC_CAP_MMC_HS200_120 (1 << 13) /* Can do eMMC HS200 at 1.2 V */ #define MMC_CAP_MMC_HS200_180 (1 << 14) /* Can do eMMC HS200 at 1.8 V */ #define MMC_CAP_MMC_HS200 (MMC_CAP_MMC_HS200_120| MMC_CAP_MMC_HS200_180) #define MMC_CAP_MMC_HS400_120 (1 << 15) /* Can do eMMC HS400 at 1.2 V */ #define MMC_CAP_MMC_HS400_180 (1 << 16) /* Can do eMMC HS400 at 1.8 V */ #define MMC_CAP_MMC_HS400 (MMC_CAP_MMC_HS400_120 | MMC_CAP_MMC_HS400_180) #define MMC_CAP_MMC_HSX00_120 (MMC_CAP_MMC_HS200_120 | MMC_CAP_MMC_HS400_120) #define MMC_CAP_MMC_ENH_STROBE (1 << 17) /* Can do eMMC Enhanced Strobe */ #define MMC_CAP_SIGNALING_120 (1 << 18) /* Can do signaling at 1.2 V */ #define MMC_CAP_SIGNALING_180 (1 << 19) /* Can do signaling at 1.8 V */ #define MMC_CAP_SIGNALING_330 (1 << 20) /* Can do signaling at 3.3 V */ #define MMC_CAP_DRIVER_TYPE_A (1 << 21) /* Can do Driver Type A */ #define MMC_CAP_DRIVER_TYPE_C (1 << 22) /* Can do Driver Type C */ #define MMC_CAP_DRIVER_TYPE_D (1 << 23) /* Can do Driver Type D */ enum mmc_card_mode mode; struct mmc_ios ios; /* Current state of the host */ }; #ifdef _KERNEL extern driver_t mmc_driver; extern devclass_t mmc_devclass; #define MMC_VERSION 5 #define MMC_DECLARE_BRIDGE(name) \ DRIVER_MODULE(mmc, name, mmc_driver, mmc_devclass, NULL, NULL); \ MODULE_DEPEND(name, mmc, MMC_VERSION, MMC_VERSION, MMC_VERSION); #define MMC_DEPEND(name) \ MODULE_DEPEND(name, mmc, MMC_VERSION, MMC_VERSION, MMC_VERSION); #endif /* _KERNEL */ #endif /* DEV_MMC_BRIDGE_H */ Index: head/sys/dev/mmc/mmc.c =================================================================== --- head/sys/dev/mmc/mmc.c (revision 355393) +++ head/sys/dev/mmc/mmc.c (revision 355394) @@ -1,2582 +1,2582 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2006 Bernd Walter. All rights reserved. - * Copyright (c) 2006 M. Warner Losh. + * Copyright (c) 2006 M. Warner Losh * Copyright (c) 2017 Marius Strobl * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Portions of this software may have been developed with reference to * the SD Simplified Specification. The following disclaimer may apply: * * The following conditions apply to the release of the simplified * specification ("Simplified Specification") by the SD Card Association and * the SD Group. The Simplified Specification is a subset of the complete SD * Specification which is owned by the SD Card Association and the SD * Group. This Simplified Specification is provided on a non-confidential * basis subject to the disclaimers below. Any implementation of the * Simplified Specification may require a license from the SD Card * Association, SD Group, SD-3C LLC or other third parties. * * Disclaimers: * * The information contained in the Simplified Specification is presented only * as a standard specification for SD Cards and SD Host/Ancillary products and * is provided "AS-IS" without any representations or warranties of any * kind. No responsibility is assumed by the SD Group, SD-3C LLC or the SD * Card Association for any damages, any infringements of patents or other * right of the SD Group, SD-3C LLC, the SD Card Association or any third * parties, which may result from its use. No license is granted by * implication, estoppel or otherwise under any patent or other rights of the * SD Group, SD-3C LLC, the SD Card Association or any third party. Nothing * herein shall be construed as an obligation by the SD Group, the SD-3C LLC * or the SD Card Association to disclose or distribute any technical * information, know-how or other confidential information to any third party. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "mmcbr_if.h" #include "mmcbus_if.h" CTASSERT(bus_timing_max <= sizeof(uint32_t) * NBBY); /* * Per-card data */ struct mmc_ivars { uint32_t raw_cid[4]; /* Raw bits of the CID */ uint32_t raw_csd[4]; /* Raw bits of the CSD */ uint32_t raw_scr[2]; /* Raw bits of the SCR */ uint8_t raw_ext_csd[MMC_EXTCSD_SIZE]; /* Raw bits of the EXT_CSD */ uint32_t raw_sd_status[16]; /* Raw bits of the SD_STATUS */ uint16_t rca; u_char read_only; /* True when the device is read-only */ u_char high_cap; /* High Capacity device (block addressed) */ enum mmc_card_mode mode; enum mmc_bus_width bus_width; /* Bus width to use */ struct mmc_cid cid; /* cid decoded */ struct mmc_csd csd; /* csd decoded */ struct mmc_scr scr; /* scr decoded */ struct mmc_sd_status sd_status; /* SD_STATUS decoded */ uint32_t sec_count; /* Card capacity in 512byte blocks */ uint32_t timings; /* Mask of bus timings supported */ uint32_t vccq_120; /* Mask of bus timings at VCCQ of 1.2 V */ uint32_t vccq_180; /* Mask of bus timings at VCCQ of 1.8 V */ uint32_t tran_speed; /* Max speed in normal mode */ uint32_t hs_tran_speed; /* Max speed in high speed mode */ uint32_t erase_sector; /* Card native erase sector size */ uint32_t cmd6_time; /* Generic switch timeout [us] */ uint32_t quirks; /* Quirks as per mmc_quirk->quirks */ char card_id_string[64];/* Formatted CID info (serial, MFG, etc) */ char card_sn_string[16];/* Formatted serial # for disk->d_ident */ }; #define CMD_RETRIES 3 static const struct mmc_quirk mmc_quirks[] = { /* * For some SanDisk iNAND devices, the CMD38 argument needs to be * provided in EXT_CSD[113]. */ { 0x2, 0x100, "SEM02G", MMC_QUIRK_INAND_CMD38 }, { 0x2, 0x100, "SEM04G", MMC_QUIRK_INAND_CMD38 }, { 0x2, 0x100, "SEM08G", MMC_QUIRK_INAND_CMD38 }, { 0x2, 0x100, "SEM16G", MMC_QUIRK_INAND_CMD38 }, { 0x2, 0x100, "SEM32G", MMC_QUIRK_INAND_CMD38 }, /* * Disable TRIM for Kingston eMMCs where a firmware bug can lead to * unrecoverable data corruption. */ { 0x70, MMC_QUIRK_OID_ANY, "V10008", MMC_QUIRK_BROKEN_TRIM }, { 0x70, MMC_QUIRK_OID_ANY, "V10016", MMC_QUIRK_BROKEN_TRIM }, { 0x0, 0x0, NULL, 0x0 } }; static SYSCTL_NODE(_hw, OID_AUTO, mmc, CTLFLAG_RD, NULL, "mmc driver"); static int mmc_debug; SYSCTL_INT(_hw_mmc, OID_AUTO, debug, CTLFLAG_RWTUN, &mmc_debug, 0, "Debug level"); /* bus entry points */ static int mmc_acquire_bus(device_t busdev, device_t dev); static int mmc_attach(device_t dev); static int mmc_child_location_str(device_t dev, device_t child, char *buf, size_t buflen); static int mmc_detach(device_t dev); static int mmc_probe(device_t dev); static int mmc_read_ivar(device_t bus, device_t child, int which, uintptr_t *result); static int mmc_release_bus(device_t busdev, device_t dev); static int mmc_resume(device_t dev); static void mmc_retune_pause(device_t busdev, device_t dev, bool retune); static void mmc_retune_unpause(device_t busdev, device_t dev); static int mmc_suspend(device_t dev); static int mmc_wait_for_request(device_t busdev, device_t dev, struct mmc_request *req); static int mmc_write_ivar(device_t bus, device_t child, int which, uintptr_t value); #define MMC_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) #define MMC_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) #define MMC_LOCK_INIT(_sc) \ mtx_init(&(_sc)->sc_mtx, device_get_nameunit((_sc)->dev), \ "mmc", MTX_DEF) #define MMC_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->sc_mtx); #define MMC_ASSERT_LOCKED(_sc) mtx_assert(&(_sc)->sc_mtx, MA_OWNED); #define MMC_ASSERT_UNLOCKED(_sc) mtx_assert(&(_sc)->sc_mtx, MA_NOTOWNED); static int mmc_all_send_cid(struct mmc_softc *sc, uint32_t *rawcid); static void mmc_app_decode_scr(uint32_t *raw_scr, struct mmc_scr *scr); static void mmc_app_decode_sd_status(uint32_t *raw_sd_status, struct mmc_sd_status *sd_status); static int mmc_app_sd_status(struct mmc_softc *sc, uint16_t rca, uint32_t *rawsdstatus); static int mmc_app_send_scr(struct mmc_softc *sc, uint16_t rca, uint32_t *rawscr); static int mmc_calculate_clock(struct mmc_softc *sc); static void mmc_decode_cid_mmc(uint32_t *raw_cid, struct mmc_cid *cid, bool is_4_41p); static void mmc_decode_cid_sd(uint32_t *raw_cid, struct mmc_cid *cid); static void mmc_decode_csd_mmc(uint32_t *raw_csd, struct mmc_csd *csd); static int mmc_decode_csd_sd(uint32_t *raw_csd, struct mmc_csd *csd); static void mmc_delayed_attach(void *xsc); static int mmc_delete_cards(struct mmc_softc *sc, bool final); static void mmc_discover_cards(struct mmc_softc *sc); static void mmc_format_card_id_string(struct mmc_ivars *ivar); static void mmc_go_discovery(struct mmc_softc *sc); static uint32_t mmc_get_bits(uint32_t *bits, int bit_len, int start, int size); static int mmc_highest_voltage(uint32_t ocr); static bool mmc_host_timing(device_t dev, enum mmc_bus_timing timing); static void mmc_idle_cards(struct mmc_softc *sc); static void mmc_ms_delay(int ms); static void mmc_log_card(device_t dev, struct mmc_ivars *ivar, int newcard); static void mmc_power_down(struct mmc_softc *sc); static void mmc_power_up(struct mmc_softc *sc); static void mmc_rescan_cards(struct mmc_softc *sc); static int mmc_retune(device_t busdev, device_t dev, bool reset); static void mmc_scan(struct mmc_softc *sc); static int mmc_sd_switch(struct mmc_softc *sc, uint8_t mode, uint8_t grp, uint8_t value, uint8_t *res); static int mmc_select_card(struct mmc_softc *sc, uint16_t rca); static uint32_t mmc_select_vdd(struct mmc_softc *sc, uint32_t ocr); static int mmc_send_app_op_cond(struct mmc_softc *sc, uint32_t ocr, uint32_t *rocr); static int mmc_send_csd(struct mmc_softc *sc, uint16_t rca, uint32_t *rawcsd); static int mmc_send_if_cond(struct mmc_softc *sc, uint8_t vhs); static int mmc_send_op_cond(struct mmc_softc *sc, uint32_t ocr, uint32_t *rocr); static int mmc_send_relative_addr(struct mmc_softc *sc, uint32_t *resp); static int mmc_set_blocklen(struct mmc_softc *sc, uint32_t len); static int mmc_set_card_bus_width(struct mmc_softc *sc, struct mmc_ivars *ivar, enum mmc_bus_timing timing); static int mmc_set_power_class(struct mmc_softc *sc, struct mmc_ivars *ivar); static int mmc_set_relative_addr(struct mmc_softc *sc, uint16_t resp); static int mmc_set_timing(struct mmc_softc *sc, struct mmc_ivars *ivar, enum mmc_bus_timing timing); static int mmc_set_vccq(struct mmc_softc *sc, struct mmc_ivars *ivar, enum mmc_bus_timing timing); static int mmc_switch_to_hs200(struct mmc_softc *sc, struct mmc_ivars *ivar, uint32_t clock); static int mmc_switch_to_hs400(struct mmc_softc *sc, struct mmc_ivars *ivar, uint32_t max_dtr, enum mmc_bus_timing max_timing); static int mmc_test_bus_width(struct mmc_softc *sc); static uint32_t mmc_timing_to_dtr(struct mmc_ivars *ivar, enum mmc_bus_timing timing); static const char *mmc_timing_to_string(enum mmc_bus_timing timing); static void mmc_update_child_list(struct mmc_softc *sc); static int mmc_wait_for_command(struct mmc_softc *sc, uint32_t opcode, uint32_t arg, uint32_t flags, uint32_t *resp, int retries); static int mmc_wait_for_req(struct mmc_softc *sc, struct mmc_request *req); static void mmc_wakeup(struct mmc_request *req); static void mmc_ms_delay(int ms) { DELAY(1000 * ms); /* XXX BAD */ } static int mmc_probe(device_t dev) { device_set_desc(dev, "MMC/SD bus"); return (0); } static int mmc_attach(device_t dev) { struct mmc_softc *sc; sc = device_get_softc(dev); sc->dev = dev; MMC_LOCK_INIT(sc); /* We'll probe and attach our children later, but before / mount */ sc->config_intrhook.ich_func = mmc_delayed_attach; sc->config_intrhook.ich_arg = sc; if (config_intrhook_establish(&sc->config_intrhook) != 0) device_printf(dev, "config_intrhook_establish failed\n"); return (0); } static int mmc_detach(device_t dev) { struct mmc_softc *sc = device_get_softc(dev); int err; err = mmc_delete_cards(sc, true); if (err != 0) return (err); mmc_power_down(sc); MMC_LOCK_DESTROY(sc); return (0); } static int mmc_suspend(device_t dev) { struct mmc_softc *sc = device_get_softc(dev); int err; err = bus_generic_suspend(dev); if (err != 0) return (err); /* * We power down with the bus acquired here, mainly so that no device * is selected any longer and sc->last_rca gets set to 0. Otherwise, * the deselect as part of the bus acquisition in mmc_scan() may fail * during resume, as the bus isn't powered up again before later in * mmc_go_discovery(). */ err = mmc_acquire_bus(dev, dev); if (err != 0) return (err); mmc_power_down(sc); err = mmc_release_bus(dev, dev); return (err); } static int mmc_resume(device_t dev) { struct mmc_softc *sc = device_get_softc(dev); mmc_scan(sc); return (bus_generic_resume(dev)); } static int mmc_acquire_bus(device_t busdev, device_t dev) { struct mmc_softc *sc; struct mmc_ivars *ivar; int err; uint16_t rca; enum mmc_bus_timing timing; err = MMCBR_ACQUIRE_HOST(device_get_parent(busdev), busdev); if (err) return (err); sc = device_get_softc(busdev); MMC_LOCK(sc); if (sc->owner) panic("mmc: host bridge didn't serialize us."); sc->owner = dev; MMC_UNLOCK(sc); if (busdev != dev) { /* * Keep track of the last rca that we've selected. If * we're asked to do it again, don't. We never * unselect unless the bus code itself wants the mmc * bus, and constantly reselecting causes problems. */ ivar = device_get_ivars(dev); rca = ivar->rca; if (sc->last_rca != rca) { if (mmc_select_card(sc, rca) != MMC_ERR_NONE) { device_printf(busdev, "Card at relative " "address %d failed to select\n", rca); return (ENXIO); } sc->last_rca = rca; timing = mmcbr_get_timing(busdev); /* * For eMMC modes, setting/updating bus width and VCCQ * only really is necessary if there actually is more * than one device on the bus as generally that already * had to be done by mmc_calculate_clock() or one of * its calees. Moreover, setting the bus width anew * can trigger re-tuning (via a CRC error on the next * CMD), even if not switching between devices an the * previously selected one is still tuned. Obviously, * we need to re-tune the host controller if devices * are actually switched, though. */ if (timing >= bus_timing_mmc_ddr52 && sc->child_count == 1) return (0); /* Prepare bus width for the new card. */ if (bootverbose || mmc_debug) { device_printf(busdev, "setting bus width to %d bits %s timing\n", (ivar->bus_width == bus_width_4) ? 4 : (ivar->bus_width == bus_width_8) ? 8 : 1, mmc_timing_to_string(timing)); } if (mmc_set_card_bus_width(sc, ivar, timing) != MMC_ERR_NONE) { device_printf(busdev, "Card at relative " "address %d failed to set bus width\n", rca); return (ENXIO); } mmcbr_set_bus_width(busdev, ivar->bus_width); mmcbr_update_ios(busdev); if (mmc_set_vccq(sc, ivar, timing) != MMC_ERR_NONE) { device_printf(busdev, "Failed to set VCCQ " "for card at relative address %d\n", rca); return (ENXIO); } if (timing >= bus_timing_mmc_hs200 && mmc_retune(busdev, dev, true) != 0) { device_printf(busdev, "Card at relative " "address %d failed to re-tune\n", rca); return (ENXIO); } } } else { /* * If there's a card selected, stand down. */ if (sc->last_rca != 0) { if (mmc_select_card(sc, 0) != MMC_ERR_NONE) return (ENXIO); sc->last_rca = 0; } } return (0); } static int mmc_release_bus(device_t busdev, device_t dev) { struct mmc_softc *sc; int err; sc = device_get_softc(busdev); MMC_LOCK(sc); if (!sc->owner) panic("mmc: releasing unowned bus."); if (sc->owner != dev) panic("mmc: you don't own the bus. game over."); MMC_UNLOCK(sc); err = MMCBR_RELEASE_HOST(device_get_parent(busdev), busdev); if (err) return (err); MMC_LOCK(sc); sc->owner = NULL; MMC_UNLOCK(sc); return (0); } static uint32_t mmc_select_vdd(struct mmc_softc *sc, uint32_t ocr) { return (ocr & MMC_OCR_VOLTAGE); } static int mmc_highest_voltage(uint32_t ocr) { int i; for (i = MMC_OCR_MAX_VOLTAGE_SHIFT; i >= MMC_OCR_MIN_VOLTAGE_SHIFT; i--) if (ocr & (1 << i)) return (i); return (-1); } static void mmc_wakeup(struct mmc_request *req) { struct mmc_softc *sc; sc = (struct mmc_softc *)req->done_data; MMC_LOCK(sc); req->flags |= MMC_REQ_DONE; MMC_UNLOCK(sc); wakeup(req); } static int mmc_wait_for_req(struct mmc_softc *sc, struct mmc_request *req) { req->done = mmc_wakeup; req->done_data = sc; if (__predict_false(mmc_debug > 1)) { device_printf(sc->dev, "REQUEST: CMD%d arg %#x flags %#x", req->cmd->opcode, req->cmd->arg, req->cmd->flags); if (req->cmd->data) { printf(" data %d\n", (int)req->cmd->data->len); } else printf("\n"); } MMCBR_REQUEST(device_get_parent(sc->dev), sc->dev, req); MMC_LOCK(sc); while ((req->flags & MMC_REQ_DONE) == 0) msleep(req, &sc->sc_mtx, 0, "mmcreq", 0); MMC_UNLOCK(sc); if (__predict_false(mmc_debug > 2 || (mmc_debug > 0 && req->cmd->error != MMC_ERR_NONE))) device_printf(sc->dev, "CMD%d RESULT: %d\n", req->cmd->opcode, req->cmd->error); return (0); } static int mmc_wait_for_request(device_t busdev, device_t dev, struct mmc_request *req) { struct mmc_softc *sc; struct mmc_ivars *ivar; int err, i; enum mmc_retune_req retune_req; sc = device_get_softc(busdev); KASSERT(sc->owner != NULL, ("%s: Request from %s without bus being acquired.", __func__, device_get_nameunit(dev))); /* * Unless no device is selected or re-tuning is already ongoing, * execute re-tuning if a) the bridge is requesting to do so and * re-tuning hasn't been otherwise paused, or b) if a child asked * to be re-tuned prior to pausing (see also mmc_retune_pause()). */ if (__predict_false(sc->last_rca != 0 && sc->retune_ongoing == 0 && (((retune_req = mmcbr_get_retune_req(busdev)) != retune_req_none && sc->retune_paused == 0) || sc->retune_needed == 1))) { if (__predict_false(mmc_debug > 1)) { device_printf(busdev, "Re-tuning with%s circuit reset required\n", retune_req == retune_req_reset ? "" : "out"); } if (device_get_parent(dev) == busdev) ivar = device_get_ivars(dev); else { for (i = 0; i < sc->child_count; i++) { ivar = device_get_ivars(sc->child_list[i]); if (ivar->rca == sc->last_rca) break; } if (ivar->rca != sc->last_rca) return (EINVAL); } sc->retune_ongoing = 1; err = mmc_retune(busdev, dev, retune_req == retune_req_reset); sc->retune_ongoing = 0; switch (err) { case MMC_ERR_NONE: case MMC_ERR_FAILED: /* Re-tune error but still might work */ break; case MMC_ERR_BADCRC: /* Switch failure on HS400 recovery */ return (ENXIO); case MMC_ERR_INVALID: /* Driver implementation b0rken */ default: /* Unknown error, should not happen */ return (EINVAL); } sc->retune_needed = 0; } return (mmc_wait_for_req(sc, req)); } static int mmc_wait_for_command(struct mmc_softc *sc, uint32_t opcode, uint32_t arg, uint32_t flags, uint32_t *resp, int retries) { struct mmc_command cmd; int err; memset(&cmd, 0, sizeof(cmd)); cmd.opcode = opcode; cmd.arg = arg; cmd.flags = flags; cmd.data = NULL; err = mmc_wait_for_cmd(sc->dev, sc->dev, &cmd, retries); if (err) return (err); if (resp) { if (flags & MMC_RSP_136) memcpy(resp, cmd.resp, 4 * sizeof(uint32_t)); else *resp = cmd.resp[0]; } return (0); } static void mmc_idle_cards(struct mmc_softc *sc) { device_t dev; struct mmc_command cmd; dev = sc->dev; mmcbr_set_chip_select(dev, cs_high); mmcbr_update_ios(dev); mmc_ms_delay(1); memset(&cmd, 0, sizeof(cmd)); cmd.opcode = MMC_GO_IDLE_STATE; cmd.arg = 0; cmd.flags = MMC_RSP_NONE | MMC_CMD_BC; cmd.data = NULL; mmc_wait_for_cmd(sc->dev, sc->dev, &cmd, CMD_RETRIES); mmc_ms_delay(1); mmcbr_set_chip_select(dev, cs_dontcare); mmcbr_update_ios(dev); mmc_ms_delay(1); } static int mmc_send_app_op_cond(struct mmc_softc *sc, uint32_t ocr, uint32_t *rocr) { struct mmc_command cmd; int err = MMC_ERR_NONE, i; memset(&cmd, 0, sizeof(cmd)); cmd.opcode = ACMD_SD_SEND_OP_COND; cmd.arg = ocr; cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR; cmd.data = NULL; for (i = 0; i < 1000; i++) { err = mmc_wait_for_app_cmd(sc->dev, sc->dev, 0, &cmd, CMD_RETRIES); if (err != MMC_ERR_NONE) break; if ((cmd.resp[0] & MMC_OCR_CARD_BUSY) || (ocr & MMC_OCR_VOLTAGE) == 0) break; err = MMC_ERR_TIMEOUT; mmc_ms_delay(10); } if (rocr && err == MMC_ERR_NONE) *rocr = cmd.resp[0]; return (err); } static int mmc_send_op_cond(struct mmc_softc *sc, uint32_t ocr, uint32_t *rocr) { struct mmc_command cmd; int err = MMC_ERR_NONE, i; memset(&cmd, 0, sizeof(cmd)); cmd.opcode = MMC_SEND_OP_COND; cmd.arg = ocr; cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR; cmd.data = NULL; for (i = 0; i < 1000; i++) { err = mmc_wait_for_cmd(sc->dev, sc->dev, &cmd, CMD_RETRIES); if (err != MMC_ERR_NONE) break; if ((cmd.resp[0] & MMC_OCR_CARD_BUSY) || (ocr & MMC_OCR_VOLTAGE) == 0) break; err = MMC_ERR_TIMEOUT; mmc_ms_delay(10); } if (rocr && err == MMC_ERR_NONE) *rocr = cmd.resp[0]; return (err); } static int mmc_send_if_cond(struct mmc_softc *sc, uint8_t vhs) { struct mmc_command cmd; int err; memset(&cmd, 0, sizeof(cmd)); cmd.opcode = SD_SEND_IF_COND; cmd.arg = (vhs << 8) + 0xAA; cmd.flags = MMC_RSP_R7 | MMC_CMD_BCR; cmd.data = NULL; err = mmc_wait_for_cmd(sc->dev, sc->dev, &cmd, CMD_RETRIES); return (err); } static void mmc_power_up(struct mmc_softc *sc) { device_t dev; enum mmc_vccq vccq; dev = sc->dev; mmcbr_set_vdd(dev, mmc_highest_voltage(mmcbr_get_host_ocr(dev))); mmcbr_set_bus_mode(dev, opendrain); mmcbr_set_chip_select(dev, cs_dontcare); mmcbr_set_bus_width(dev, bus_width_1); mmcbr_set_power_mode(dev, power_up); mmcbr_set_clock(dev, 0); mmcbr_update_ios(dev); for (vccq = vccq_330; ; vccq--) { mmcbr_set_vccq(dev, vccq); if (mmcbr_switch_vccq(dev) == 0 || vccq == vccq_120) break; } mmc_ms_delay(1); mmcbr_set_clock(dev, SD_MMC_CARD_ID_FREQUENCY); mmcbr_set_timing(dev, bus_timing_normal); mmcbr_set_power_mode(dev, power_on); mmcbr_update_ios(dev); mmc_ms_delay(2); } static void mmc_power_down(struct mmc_softc *sc) { device_t dev = sc->dev; mmcbr_set_bus_mode(dev, opendrain); mmcbr_set_chip_select(dev, cs_dontcare); mmcbr_set_bus_width(dev, bus_width_1); mmcbr_set_power_mode(dev, power_off); mmcbr_set_clock(dev, 0); mmcbr_set_timing(dev, bus_timing_normal); mmcbr_update_ios(dev); } static int mmc_select_card(struct mmc_softc *sc, uint16_t rca) { int err, flags; flags = (rca ? MMC_RSP_R1B : MMC_RSP_NONE) | MMC_CMD_AC; sc->retune_paused++; err = mmc_wait_for_command(sc, MMC_SELECT_CARD, (uint32_t)rca << 16, flags, NULL, CMD_RETRIES); sc->retune_paused--; return (err); } static int mmc_sd_switch(struct mmc_softc *sc, uint8_t mode, uint8_t grp, uint8_t value, uint8_t *res) { int err; struct mmc_command cmd; struct mmc_data data; memset(&cmd, 0, sizeof(cmd)); memset(&data, 0, sizeof(data)); memset(res, 0, 64); cmd.opcode = SD_SWITCH_FUNC; cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; cmd.arg = mode << 31; /* 0 - check, 1 - set */ cmd.arg |= 0x00FFFFFF; cmd.arg &= ~(0xF << (grp * 4)); cmd.arg |= value << (grp * 4); cmd.data = &data; data.data = res; data.len = 64; data.flags = MMC_DATA_READ; err = mmc_wait_for_cmd(sc->dev, sc->dev, &cmd, CMD_RETRIES); return (err); } static int mmc_set_card_bus_width(struct mmc_softc *sc, struct mmc_ivars *ivar, enum mmc_bus_timing timing) { struct mmc_command cmd; int err; uint8_t value; if (mmcbr_get_mode(sc->dev) == mode_sd) { memset(&cmd, 0, sizeof(cmd)); cmd.opcode = ACMD_SET_CLR_CARD_DETECT; cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; cmd.arg = SD_CLR_CARD_DETECT; err = mmc_wait_for_app_cmd(sc->dev, sc->dev, ivar->rca, &cmd, CMD_RETRIES); if (err != 0) return (err); memset(&cmd, 0, sizeof(cmd)); cmd.opcode = ACMD_SET_BUS_WIDTH; cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; switch (ivar->bus_width) { case bus_width_1: cmd.arg = SD_BUS_WIDTH_1; break; case bus_width_4: cmd.arg = SD_BUS_WIDTH_4; break; default: return (MMC_ERR_INVALID); } err = mmc_wait_for_app_cmd(sc->dev, sc->dev, ivar->rca, &cmd, CMD_RETRIES); } else { switch (ivar->bus_width) { case bus_width_1: if (timing == bus_timing_mmc_hs400 || timing == bus_timing_mmc_hs400es) return (MMC_ERR_INVALID); value = EXT_CSD_BUS_WIDTH_1; break; case bus_width_4: switch (timing) { case bus_timing_mmc_ddr52: value = EXT_CSD_BUS_WIDTH_4_DDR; break; case bus_timing_mmc_hs400: case bus_timing_mmc_hs400es: return (MMC_ERR_INVALID); default: value = EXT_CSD_BUS_WIDTH_4; break; } break; case bus_width_8: value = 0; switch (timing) { case bus_timing_mmc_hs400es: value = EXT_CSD_BUS_WIDTH_ES; /* FALLTHROUGH */ case bus_timing_mmc_ddr52: case bus_timing_mmc_hs400: value |= EXT_CSD_BUS_WIDTH_8_DDR; break; default: value = EXT_CSD_BUS_WIDTH_8; break; } break; default: return (MMC_ERR_INVALID); } err = mmc_switch(sc->dev, sc->dev, ivar->rca, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, value, ivar->cmd6_time, true); } return (err); } static int mmc_set_power_class(struct mmc_softc *sc, struct mmc_ivars *ivar) { device_t dev; const uint8_t *ext_csd; uint32_t clock; uint8_t value; enum mmc_bus_timing timing; enum mmc_bus_width bus_width; dev = sc->dev; timing = mmcbr_get_timing(dev); bus_width = ivar->bus_width; if (mmcbr_get_mode(dev) != mode_mmc || ivar->csd.spec_vers < 4 || timing == bus_timing_normal || bus_width == bus_width_1) return (MMC_ERR_NONE); value = 0; ext_csd = ivar->raw_ext_csd; clock = mmcbr_get_clock(dev); switch (1 << mmcbr_get_vdd(dev)) { case MMC_OCR_LOW_VOLTAGE: if (clock <= MMC_TYPE_HS_26_MAX) value = ext_csd[EXT_CSD_PWR_CL_26_195]; else if (clock <= MMC_TYPE_HS_52_MAX) { if (timing >= bus_timing_mmc_ddr52 && bus_width >= bus_width_4) value = ext_csd[EXT_CSD_PWR_CL_52_195_DDR]; else value = ext_csd[EXT_CSD_PWR_CL_52_195]; } else if (clock <= MMC_TYPE_HS200_HS400ES_MAX) value = ext_csd[EXT_CSD_PWR_CL_200_195]; break; case MMC_OCR_270_280: case MMC_OCR_280_290: case MMC_OCR_290_300: case MMC_OCR_300_310: case MMC_OCR_310_320: case MMC_OCR_320_330: case MMC_OCR_330_340: case MMC_OCR_340_350: case MMC_OCR_350_360: if (clock <= MMC_TYPE_HS_26_MAX) value = ext_csd[EXT_CSD_PWR_CL_26_360]; else if (clock <= MMC_TYPE_HS_52_MAX) { if (timing == bus_timing_mmc_ddr52 && bus_width >= bus_width_4) value = ext_csd[EXT_CSD_PWR_CL_52_360_DDR]; else value = ext_csd[EXT_CSD_PWR_CL_52_360]; } else if (clock <= MMC_TYPE_HS200_HS400ES_MAX) { if (bus_width == bus_width_8) value = ext_csd[EXT_CSD_PWR_CL_200_360_DDR]; else value = ext_csd[EXT_CSD_PWR_CL_200_360]; } break; default: device_printf(dev, "No power class support for VDD 0x%x\n", 1 << mmcbr_get_vdd(dev)); return (MMC_ERR_INVALID); } if (bus_width == bus_width_8) value = (value & EXT_CSD_POWER_CLASS_8BIT_MASK) >> EXT_CSD_POWER_CLASS_8BIT_SHIFT; else value = (value & EXT_CSD_POWER_CLASS_4BIT_MASK) >> EXT_CSD_POWER_CLASS_4BIT_SHIFT; if (value == 0) return (MMC_ERR_NONE); return (mmc_switch(dev, dev, ivar->rca, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_POWER_CLASS, value, ivar->cmd6_time, true)); } static int mmc_set_timing(struct mmc_softc *sc, struct mmc_ivars *ivar, enum mmc_bus_timing timing) { u_char switch_res[64]; uint8_t value; int err; if (mmcbr_get_mode(sc->dev) == mode_sd) { switch (timing) { case bus_timing_normal: value = SD_SWITCH_NORMAL_MODE; break; case bus_timing_hs: value = SD_SWITCH_HS_MODE; break; default: return (MMC_ERR_INVALID); } err = mmc_sd_switch(sc, SD_SWITCH_MODE_SET, SD_SWITCH_GROUP1, value, switch_res); if (err != MMC_ERR_NONE) return (err); if ((switch_res[16] & 0xf) != value) return (MMC_ERR_FAILED); mmcbr_set_timing(sc->dev, timing); mmcbr_update_ios(sc->dev); } else { switch (timing) { case bus_timing_normal: value = EXT_CSD_HS_TIMING_BC; break; case bus_timing_hs: case bus_timing_mmc_ddr52: value = EXT_CSD_HS_TIMING_HS; break; case bus_timing_mmc_hs200: value = EXT_CSD_HS_TIMING_HS200; break; case bus_timing_mmc_hs400: case bus_timing_mmc_hs400es: value = EXT_CSD_HS_TIMING_HS400; break; default: return (MMC_ERR_INVALID); } err = mmc_switch(sc->dev, sc->dev, ivar->rca, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, value, ivar->cmd6_time, false); if (err != MMC_ERR_NONE) return (err); mmcbr_set_timing(sc->dev, timing); mmcbr_update_ios(sc->dev); err = mmc_switch_status(sc->dev, sc->dev, ivar->rca, ivar->cmd6_time); } return (err); } static int mmc_set_vccq(struct mmc_softc *sc, struct mmc_ivars *ivar, enum mmc_bus_timing timing) { if (isset(&ivar->vccq_120, timing)) mmcbr_set_vccq(sc->dev, vccq_120); else if (isset(&ivar->vccq_180, timing)) mmcbr_set_vccq(sc->dev, vccq_180); else mmcbr_set_vccq(sc->dev, vccq_330); if (mmcbr_switch_vccq(sc->dev) != 0) return (MMC_ERR_INVALID); else return (MMC_ERR_NONE); } static const uint8_t p8[8] = { 0x55, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; static const uint8_t p8ok[8] = { 0xAA, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; static const uint8_t p4[4] = { 0x5A, 0x00, 0x00, 0x00 }; static const uint8_t p4ok[4] = { 0xA5, 0x00, 0x00, 0x00 }; static int mmc_test_bus_width(struct mmc_softc *sc) { struct mmc_command cmd; struct mmc_data data; uint8_t buf[8]; int err; if (mmcbr_get_caps(sc->dev) & MMC_CAP_8_BIT_DATA) { mmcbr_set_bus_width(sc->dev, bus_width_8); mmcbr_update_ios(sc->dev); sc->squelched++; /* Errors are expected, squelch reporting. */ memset(&cmd, 0, sizeof(cmd)); memset(&data, 0, sizeof(data)); cmd.opcode = MMC_BUSTEST_W; cmd.arg = 0; cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; cmd.data = &data; data.data = __DECONST(void *, p8); data.len = 8; data.flags = MMC_DATA_WRITE; mmc_wait_for_cmd(sc->dev, sc->dev, &cmd, 0); memset(&cmd, 0, sizeof(cmd)); memset(&data, 0, sizeof(data)); cmd.opcode = MMC_BUSTEST_R; cmd.arg = 0; cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; cmd.data = &data; data.data = buf; data.len = 8; data.flags = MMC_DATA_READ; err = mmc_wait_for_cmd(sc->dev, sc->dev, &cmd, 0); sc->squelched--; mmcbr_set_bus_width(sc->dev, bus_width_1); mmcbr_update_ios(sc->dev); if (err == MMC_ERR_NONE && memcmp(buf, p8ok, 8) == 0) return (bus_width_8); } if (mmcbr_get_caps(sc->dev) & MMC_CAP_4_BIT_DATA) { mmcbr_set_bus_width(sc->dev, bus_width_4); mmcbr_update_ios(sc->dev); sc->squelched++; /* Errors are expected, squelch reporting. */ memset(&cmd, 0, sizeof(cmd)); memset(&data, 0, sizeof(data)); cmd.opcode = MMC_BUSTEST_W; cmd.arg = 0; cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; cmd.data = &data; data.data = __DECONST(void *, p4); data.len = 4; data.flags = MMC_DATA_WRITE; mmc_wait_for_cmd(sc->dev, sc->dev, &cmd, 0); memset(&cmd, 0, sizeof(cmd)); memset(&data, 0, sizeof(data)); cmd.opcode = MMC_BUSTEST_R; cmd.arg = 0; cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; cmd.data = &data; data.data = buf; data.len = 4; data.flags = MMC_DATA_READ; err = mmc_wait_for_cmd(sc->dev, sc->dev, &cmd, 0); sc->squelched--; mmcbr_set_bus_width(sc->dev, bus_width_1); mmcbr_update_ios(sc->dev); if (err == MMC_ERR_NONE && memcmp(buf, p4ok, 4) == 0) return (bus_width_4); } return (bus_width_1); } static uint32_t mmc_get_bits(uint32_t *bits, int bit_len, int start, int size) { const int i = (bit_len / 32) - (start / 32) - 1; const int shift = start & 31; uint32_t retval = bits[i] >> shift; if (size + shift > 32) retval |= bits[i - 1] << (32 - shift); return (retval & ((1llu << size) - 1)); } static void mmc_decode_cid_sd(uint32_t *raw_cid, struct mmc_cid *cid) { int i; /* There's no version info, so we take it on faith */ memset(cid, 0, sizeof(*cid)); cid->mid = mmc_get_bits(raw_cid, 128, 120, 8); cid->oid = mmc_get_bits(raw_cid, 128, 104, 16); for (i = 0; i < 5; i++) cid->pnm[i] = mmc_get_bits(raw_cid, 128, 96 - i * 8, 8); cid->pnm[5] = 0; cid->prv = mmc_get_bits(raw_cid, 128, 56, 8); cid->psn = mmc_get_bits(raw_cid, 128, 24, 32); cid->mdt_year = mmc_get_bits(raw_cid, 128, 12, 8) + 2000; cid->mdt_month = mmc_get_bits(raw_cid, 128, 8, 4); } static void mmc_decode_cid_mmc(uint32_t *raw_cid, struct mmc_cid *cid, bool is_4_41p) { int i; /* There's no version info, so we take it on faith */ memset(cid, 0, sizeof(*cid)); cid->mid = mmc_get_bits(raw_cid, 128, 120, 8); cid->oid = mmc_get_bits(raw_cid, 128, 104, 8); for (i = 0; i < 6; i++) cid->pnm[i] = mmc_get_bits(raw_cid, 128, 96 - i * 8, 8); cid->pnm[6] = 0; cid->prv = mmc_get_bits(raw_cid, 128, 48, 8); cid->psn = mmc_get_bits(raw_cid, 128, 16, 32); cid->mdt_month = mmc_get_bits(raw_cid, 128, 12, 4); cid->mdt_year = mmc_get_bits(raw_cid, 128, 8, 4); if (is_4_41p) cid->mdt_year += 2013; else cid->mdt_year += 1997; } static void mmc_format_card_id_string(struct mmc_ivars *ivar) { char oidstr[8]; uint8_t c1; uint8_t c2; /* * Format a card ID string for use by the mmcsd driver, it's what * appears between the <> in the following: * mmcsd0: 968MB at mmc0 * 22.5MHz/4bit/128-block * * Also format just the card serial number, which the mmcsd driver will * use as the disk->d_ident string. * * The card_id_string in mmc_ivars is currently allocated as 64 bytes, * and our max formatted length is currently 55 bytes if every field * contains the largest value. * * Sometimes the oid is two printable ascii chars; when it's not, * format it as 0xnnnn instead. */ c1 = (ivar->cid.oid >> 8) & 0x0ff; c2 = ivar->cid.oid & 0x0ff; if (c1 > 0x1f && c1 < 0x7f && c2 > 0x1f && c2 < 0x7f) snprintf(oidstr, sizeof(oidstr), "%c%c", c1, c2); else snprintf(oidstr, sizeof(oidstr), "0x%04x", ivar->cid.oid); snprintf(ivar->card_sn_string, sizeof(ivar->card_sn_string), "%08X", ivar->cid.psn); snprintf(ivar->card_id_string, sizeof(ivar->card_id_string), "%s%s %s %d.%d SN %08X MFG %02d/%04d by %d %s", ivar->mode == mode_sd ? "SD" : "MMC", ivar->high_cap ? "HC" : "", ivar->cid.pnm, ivar->cid.prv >> 4, ivar->cid.prv & 0x0f, ivar->cid.psn, ivar->cid.mdt_month, ivar->cid.mdt_year, ivar->cid.mid, oidstr); } static const int exp[8] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000 }; static const int mant[16] = { 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80 }; static const int cur_min[8] = { 500, 1000, 5000, 10000, 25000, 35000, 60000, 100000 }; static const int cur_max[8] = { 1000, 5000, 10000, 25000, 35000, 45000, 800000, 200000 }; static int mmc_decode_csd_sd(uint32_t *raw_csd, struct mmc_csd *csd) { int v; int m; int e; memset(csd, 0, sizeof(*csd)); csd->csd_structure = v = mmc_get_bits(raw_csd, 128, 126, 2); if (v == 0) { m = mmc_get_bits(raw_csd, 128, 115, 4); e = mmc_get_bits(raw_csd, 128, 112, 3); csd->tacc = (exp[e] * mant[m] + 9) / 10; csd->nsac = mmc_get_bits(raw_csd, 128, 104, 8) * 100; m = mmc_get_bits(raw_csd, 128, 99, 4); e = mmc_get_bits(raw_csd, 128, 96, 3); csd->tran_speed = exp[e] * 10000 * mant[m]; csd->ccc = mmc_get_bits(raw_csd, 128, 84, 12); csd->read_bl_len = 1 << mmc_get_bits(raw_csd, 128, 80, 4); csd->read_bl_partial = mmc_get_bits(raw_csd, 128, 79, 1); csd->write_blk_misalign = mmc_get_bits(raw_csd, 128, 78, 1); csd->read_blk_misalign = mmc_get_bits(raw_csd, 128, 77, 1); csd->dsr_imp = mmc_get_bits(raw_csd, 128, 76, 1); csd->vdd_r_curr_min = cur_min[mmc_get_bits(raw_csd, 128, 59, 3)]; csd->vdd_r_curr_max = cur_max[mmc_get_bits(raw_csd, 128, 56, 3)]; csd->vdd_w_curr_min = cur_min[mmc_get_bits(raw_csd, 128, 53, 3)]; csd->vdd_w_curr_max = cur_max[mmc_get_bits(raw_csd, 128, 50, 3)]; m = mmc_get_bits(raw_csd, 128, 62, 12); e = mmc_get_bits(raw_csd, 128, 47, 3); csd->capacity = ((1 + m) << (e + 2)) * csd->read_bl_len; csd->erase_blk_en = mmc_get_bits(raw_csd, 128, 46, 1); csd->erase_sector = mmc_get_bits(raw_csd, 128, 39, 7) + 1; csd->wp_grp_size = mmc_get_bits(raw_csd, 128, 32, 7); csd->wp_grp_enable = mmc_get_bits(raw_csd, 128, 31, 1); csd->r2w_factor = 1 << mmc_get_bits(raw_csd, 128, 26, 3); csd->write_bl_len = 1 << mmc_get_bits(raw_csd, 128, 22, 4); csd->write_bl_partial = mmc_get_bits(raw_csd, 128, 21, 1); return (MMC_ERR_NONE); } else if (v == 1) { m = mmc_get_bits(raw_csd, 128, 115, 4); e = mmc_get_bits(raw_csd, 128, 112, 3); csd->tacc = (exp[e] * mant[m] + 9) / 10; csd->nsac = mmc_get_bits(raw_csd, 128, 104, 8) * 100; m = mmc_get_bits(raw_csd, 128, 99, 4); e = mmc_get_bits(raw_csd, 128, 96, 3); csd->tran_speed = exp[e] * 10000 * mant[m]; csd->ccc = mmc_get_bits(raw_csd, 128, 84, 12); csd->read_bl_len = 1 << mmc_get_bits(raw_csd, 128, 80, 4); csd->read_bl_partial = mmc_get_bits(raw_csd, 128, 79, 1); csd->write_blk_misalign = mmc_get_bits(raw_csd, 128, 78, 1); csd->read_blk_misalign = mmc_get_bits(raw_csd, 128, 77, 1); csd->dsr_imp = mmc_get_bits(raw_csd, 128, 76, 1); csd->capacity = ((uint64_t)mmc_get_bits(raw_csd, 128, 48, 22) + 1) * 512 * 1024; csd->erase_blk_en = mmc_get_bits(raw_csd, 128, 46, 1); csd->erase_sector = mmc_get_bits(raw_csd, 128, 39, 7) + 1; csd->wp_grp_size = mmc_get_bits(raw_csd, 128, 32, 7); csd->wp_grp_enable = mmc_get_bits(raw_csd, 128, 31, 1); csd->r2w_factor = 1 << mmc_get_bits(raw_csd, 128, 26, 3); csd->write_bl_len = 1 << mmc_get_bits(raw_csd, 128, 22, 4); csd->write_bl_partial = mmc_get_bits(raw_csd, 128, 21, 1); return (MMC_ERR_NONE); } return (MMC_ERR_INVALID); } static void mmc_decode_csd_mmc(uint32_t *raw_csd, struct mmc_csd *csd) { int m; int e; memset(csd, 0, sizeof(*csd)); csd->csd_structure = mmc_get_bits(raw_csd, 128, 126, 2); csd->spec_vers = mmc_get_bits(raw_csd, 128, 122, 4); m = mmc_get_bits(raw_csd, 128, 115, 4); e = mmc_get_bits(raw_csd, 128, 112, 3); csd->tacc = exp[e] * mant[m] + 9 / 10; csd->nsac = mmc_get_bits(raw_csd, 128, 104, 8) * 100; m = mmc_get_bits(raw_csd, 128, 99, 4); e = mmc_get_bits(raw_csd, 128, 96, 3); csd->tran_speed = exp[e] * 10000 * mant[m]; csd->ccc = mmc_get_bits(raw_csd, 128, 84, 12); csd->read_bl_len = 1 << mmc_get_bits(raw_csd, 128, 80, 4); csd->read_bl_partial = mmc_get_bits(raw_csd, 128, 79, 1); csd->write_blk_misalign = mmc_get_bits(raw_csd, 128, 78, 1); csd->read_blk_misalign = mmc_get_bits(raw_csd, 128, 77, 1); csd->dsr_imp = mmc_get_bits(raw_csd, 128, 76, 1); csd->vdd_r_curr_min = cur_min[mmc_get_bits(raw_csd, 128, 59, 3)]; csd->vdd_r_curr_max = cur_max[mmc_get_bits(raw_csd, 128, 56, 3)]; csd->vdd_w_curr_min = cur_min[mmc_get_bits(raw_csd, 128, 53, 3)]; csd->vdd_w_curr_max = cur_max[mmc_get_bits(raw_csd, 128, 50, 3)]; m = mmc_get_bits(raw_csd, 128, 62, 12); e = mmc_get_bits(raw_csd, 128, 47, 3); csd->capacity = ((1 + m) << (e + 2)) * csd->read_bl_len; csd->erase_blk_en = 0; csd->erase_sector = (mmc_get_bits(raw_csd, 128, 42, 5) + 1) * (mmc_get_bits(raw_csd, 128, 37, 5) + 1); csd->wp_grp_size = mmc_get_bits(raw_csd, 128, 32, 5); csd->wp_grp_enable = mmc_get_bits(raw_csd, 128, 31, 1); csd->r2w_factor = 1 << mmc_get_bits(raw_csd, 128, 26, 3); csd->write_bl_len = 1 << mmc_get_bits(raw_csd, 128, 22, 4); csd->write_bl_partial = mmc_get_bits(raw_csd, 128, 21, 1); } static void mmc_app_decode_scr(uint32_t *raw_scr, struct mmc_scr *scr) { unsigned int scr_struct; memset(scr, 0, sizeof(*scr)); scr_struct = mmc_get_bits(raw_scr, 64, 60, 4); if (scr_struct != 0) { printf("Unrecognised SCR structure version %d\n", scr_struct); return; } scr->sda_vsn = mmc_get_bits(raw_scr, 64, 56, 4); scr->bus_widths = mmc_get_bits(raw_scr, 64, 48, 4); } static void mmc_app_decode_sd_status(uint32_t *raw_sd_status, struct mmc_sd_status *sd_status) { memset(sd_status, 0, sizeof(*sd_status)); sd_status->bus_width = mmc_get_bits(raw_sd_status, 512, 510, 2); sd_status->secured_mode = mmc_get_bits(raw_sd_status, 512, 509, 1); sd_status->card_type = mmc_get_bits(raw_sd_status, 512, 480, 16); sd_status->prot_area = mmc_get_bits(raw_sd_status, 512, 448, 12); sd_status->speed_class = mmc_get_bits(raw_sd_status, 512, 440, 8); sd_status->perf_move = mmc_get_bits(raw_sd_status, 512, 432, 8); sd_status->au_size = mmc_get_bits(raw_sd_status, 512, 428, 4); sd_status->erase_size = mmc_get_bits(raw_sd_status, 512, 408, 16); sd_status->erase_timeout = mmc_get_bits(raw_sd_status, 512, 402, 6); sd_status->erase_offset = mmc_get_bits(raw_sd_status, 512, 400, 2); } static int mmc_all_send_cid(struct mmc_softc *sc, uint32_t *rawcid) { struct mmc_command cmd; int err; memset(&cmd, 0, sizeof(cmd)); cmd.opcode = MMC_ALL_SEND_CID; cmd.arg = 0; cmd.flags = MMC_RSP_R2 | MMC_CMD_BCR; cmd.data = NULL; err = mmc_wait_for_cmd(sc->dev, sc->dev, &cmd, CMD_RETRIES); memcpy(rawcid, cmd.resp, 4 * sizeof(uint32_t)); return (err); } static int mmc_send_csd(struct mmc_softc *sc, uint16_t rca, uint32_t *rawcsd) { struct mmc_command cmd; int err; memset(&cmd, 0, sizeof(cmd)); cmd.opcode = MMC_SEND_CSD; cmd.arg = rca << 16; cmd.flags = MMC_RSP_R2 | MMC_CMD_BCR; cmd.data = NULL; err = mmc_wait_for_cmd(sc->dev, sc->dev, &cmd, CMD_RETRIES); memcpy(rawcsd, cmd.resp, 4 * sizeof(uint32_t)); return (err); } static int mmc_app_send_scr(struct mmc_softc *sc, uint16_t rca, uint32_t *rawscr) { int err; struct mmc_command cmd; struct mmc_data data; memset(&cmd, 0, sizeof(cmd)); memset(&data, 0, sizeof(data)); memset(rawscr, 0, 8); cmd.opcode = ACMD_SEND_SCR; cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; cmd.arg = 0; cmd.data = &data; data.data = rawscr; data.len = 8; data.flags = MMC_DATA_READ; err = mmc_wait_for_app_cmd(sc->dev, sc->dev, rca, &cmd, CMD_RETRIES); rawscr[0] = be32toh(rawscr[0]); rawscr[1] = be32toh(rawscr[1]); return (err); } static int mmc_app_sd_status(struct mmc_softc *sc, uint16_t rca, uint32_t *rawsdstatus) { struct mmc_command cmd; struct mmc_data data; int err, i; memset(&cmd, 0, sizeof(cmd)); memset(&data, 0, sizeof(data)); memset(rawsdstatus, 0, 64); cmd.opcode = ACMD_SD_STATUS; cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; cmd.arg = 0; cmd.data = &data; data.data = rawsdstatus; data.len = 64; data.flags = MMC_DATA_READ; err = mmc_wait_for_app_cmd(sc->dev, sc->dev, rca, &cmd, CMD_RETRIES); for (i = 0; i < 16; i++) rawsdstatus[i] = be32toh(rawsdstatus[i]); return (err); } static int mmc_set_relative_addr(struct mmc_softc *sc, uint16_t resp) { struct mmc_command cmd; int err; memset(&cmd, 0, sizeof(cmd)); cmd.opcode = MMC_SET_RELATIVE_ADDR; cmd.arg = resp << 16; cmd.flags = MMC_RSP_R6 | MMC_CMD_BCR; cmd.data = NULL; err = mmc_wait_for_cmd(sc->dev, sc->dev, &cmd, CMD_RETRIES); return (err); } static int mmc_send_relative_addr(struct mmc_softc *sc, uint32_t *resp) { struct mmc_command cmd; int err; memset(&cmd, 0, sizeof(cmd)); cmd.opcode = SD_SEND_RELATIVE_ADDR; cmd.arg = 0; cmd.flags = MMC_RSP_R6 | MMC_CMD_BCR; cmd.data = NULL; err = mmc_wait_for_cmd(sc->dev, sc->dev, &cmd, CMD_RETRIES); *resp = cmd.resp[0]; return (err); } static int mmc_set_blocklen(struct mmc_softc *sc, uint32_t len) { struct mmc_command cmd; int err; memset(&cmd, 0, sizeof(cmd)); cmd.opcode = MMC_SET_BLOCKLEN; cmd.arg = len; cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; cmd.data = NULL; err = mmc_wait_for_cmd(sc->dev, sc->dev, &cmd, CMD_RETRIES); return (err); } static uint32_t mmc_timing_to_dtr(struct mmc_ivars *ivar, enum mmc_bus_timing timing) { switch (timing) { case bus_timing_normal: return (ivar->tran_speed); case bus_timing_hs: return (ivar->hs_tran_speed); case bus_timing_uhs_sdr12: return (SD_SDR12_MAX); case bus_timing_uhs_sdr25: return (SD_SDR25_MAX); case bus_timing_uhs_ddr50: return (SD_DDR50_MAX); case bus_timing_uhs_sdr50: return (SD_SDR50_MAX); case bus_timing_uhs_sdr104: return (SD_SDR104_MAX); case bus_timing_mmc_ddr52: return (MMC_TYPE_DDR52_MAX); case bus_timing_mmc_hs200: case bus_timing_mmc_hs400: case bus_timing_mmc_hs400es: return (MMC_TYPE_HS200_HS400ES_MAX); } return (0); } static const char * mmc_timing_to_string(enum mmc_bus_timing timing) { switch (timing) { case bus_timing_normal: return ("normal speed"); case bus_timing_hs: return ("high speed"); case bus_timing_uhs_sdr12: case bus_timing_uhs_sdr25: case bus_timing_uhs_sdr50: case bus_timing_uhs_sdr104: return ("single data rate"); case bus_timing_uhs_ddr50: case bus_timing_mmc_ddr52: return ("dual data rate"); case bus_timing_mmc_hs200: return ("HS200"); case bus_timing_mmc_hs400: return ("HS400"); case bus_timing_mmc_hs400es: return ("HS400 with enhanced strobe"); } return (""); } static bool mmc_host_timing(device_t dev, enum mmc_bus_timing timing) { int host_caps; host_caps = mmcbr_get_caps(dev); #define HOST_TIMING_CAP(host_caps, cap) ({ \ bool retval; \ if (((host_caps) & (cap)) == (cap)) \ retval = true; \ else \ retval = false; \ retval; \ }) switch (timing) { case bus_timing_normal: return (true); case bus_timing_hs: return (HOST_TIMING_CAP(host_caps, MMC_CAP_HSPEED)); case bus_timing_uhs_sdr12: return (HOST_TIMING_CAP(host_caps, MMC_CAP_UHS_SDR12)); case bus_timing_uhs_sdr25: return (HOST_TIMING_CAP(host_caps, MMC_CAP_UHS_SDR25)); case bus_timing_uhs_ddr50: return (HOST_TIMING_CAP(host_caps, MMC_CAP_UHS_DDR50)); case bus_timing_uhs_sdr50: return (HOST_TIMING_CAP(host_caps, MMC_CAP_UHS_SDR50)); case bus_timing_uhs_sdr104: return (HOST_TIMING_CAP(host_caps, MMC_CAP_UHS_SDR104)); case bus_timing_mmc_ddr52: return (HOST_TIMING_CAP(host_caps, MMC_CAP_MMC_DDR52)); case bus_timing_mmc_hs200: return (HOST_TIMING_CAP(host_caps, MMC_CAP_MMC_HS200)); case bus_timing_mmc_hs400: return (HOST_TIMING_CAP(host_caps, MMC_CAP_MMC_HS400)); case bus_timing_mmc_hs400es: return (HOST_TIMING_CAP(host_caps, MMC_CAP_MMC_HS400 | MMC_CAP_MMC_ENH_STROBE)); } #undef HOST_TIMING_CAP return (false); } static void mmc_log_card(device_t dev, struct mmc_ivars *ivar, int newcard) { enum mmc_bus_timing timing; device_printf(dev, "Card at relative address 0x%04x%s:\n", ivar->rca, newcard ? " added" : ""); device_printf(dev, " card: %s\n", ivar->card_id_string); for (timing = bus_timing_max; timing > bus_timing_normal; timing--) { if (isset(&ivar->timings, timing)) break; } device_printf(dev, " quirks: %b\n", ivar->quirks, MMC_QUIRKS_FMT); device_printf(dev, " bus: %ubit, %uMHz (%s timing)\n", (ivar->bus_width == bus_width_1 ? 1 : (ivar->bus_width == bus_width_4 ? 4 : 8)), mmc_timing_to_dtr(ivar, timing) / 1000000, mmc_timing_to_string(timing)); device_printf(dev, " memory: %u blocks, erase sector %u blocks%s\n", ivar->sec_count, ivar->erase_sector, ivar->read_only ? ", read-only" : ""); } static void mmc_discover_cards(struct mmc_softc *sc) { u_char switch_res[64]; uint32_t raw_cid[4]; struct mmc_ivars *ivar = NULL; const struct mmc_quirk *quirk; const uint8_t *ext_csd; device_t child; int err, host_caps, i, newcard; uint32_t resp, sec_count, status; uint16_t rca = 2; int16_t rev; uint8_t card_type; host_caps = mmcbr_get_caps(sc->dev); if (bootverbose || mmc_debug) device_printf(sc->dev, "Probing cards\n"); while (1) { child = NULL; sc->squelched++; /* Errors are expected, squelch reporting. */ err = mmc_all_send_cid(sc, raw_cid); sc->squelched--; if (err == MMC_ERR_TIMEOUT) break; if (err != MMC_ERR_NONE) { device_printf(sc->dev, "Error reading CID %d\n", err); break; } newcard = 1; for (i = 0; i < sc->child_count; i++) { ivar = device_get_ivars(sc->child_list[i]); if (memcmp(ivar->raw_cid, raw_cid, sizeof(raw_cid)) == 0) { newcard = 0; break; } } if (bootverbose || mmc_debug) { device_printf(sc->dev, "%sard detected (CID %08x%08x%08x%08x)\n", newcard ? "New c" : "C", raw_cid[0], raw_cid[1], raw_cid[2], raw_cid[3]); } if (newcard) { ivar = malloc(sizeof(struct mmc_ivars), M_DEVBUF, M_WAITOK | M_ZERO); memcpy(ivar->raw_cid, raw_cid, sizeof(raw_cid)); } if (mmcbr_get_ro(sc->dev)) ivar->read_only = 1; ivar->bus_width = bus_width_1; setbit(&ivar->timings, bus_timing_normal); ivar->mode = mmcbr_get_mode(sc->dev); if (ivar->mode == mode_sd) { mmc_decode_cid_sd(ivar->raw_cid, &ivar->cid); err = mmc_send_relative_addr(sc, &resp); if (err != MMC_ERR_NONE) { device_printf(sc->dev, "Error getting RCA %d\n", err); goto free_ivar; } ivar->rca = resp >> 16; /* Get card CSD. */ err = mmc_send_csd(sc, ivar->rca, ivar->raw_csd); if (err != MMC_ERR_NONE) { device_printf(sc->dev, "Error getting CSD %d\n", err); goto free_ivar; } if (bootverbose || mmc_debug) device_printf(sc->dev, "%sard detected (CSD %08x%08x%08x%08x)\n", newcard ? "New c" : "C", ivar->raw_csd[0], ivar->raw_csd[1], ivar->raw_csd[2], ivar->raw_csd[3]); err = mmc_decode_csd_sd(ivar->raw_csd, &ivar->csd); if (err != MMC_ERR_NONE) { device_printf(sc->dev, "Error decoding CSD\n"); goto free_ivar; } ivar->sec_count = ivar->csd.capacity / MMC_SECTOR_SIZE; if (ivar->csd.csd_structure > 0) ivar->high_cap = 1; ivar->tran_speed = ivar->csd.tran_speed; ivar->erase_sector = ivar->csd.erase_sector * ivar->csd.write_bl_len / MMC_SECTOR_SIZE; err = mmc_send_status(sc->dev, sc->dev, ivar->rca, &status); if (err != MMC_ERR_NONE) { device_printf(sc->dev, "Error reading card status %d\n", err); goto free_ivar; } if ((status & R1_CARD_IS_LOCKED) != 0) { device_printf(sc->dev, "Card is password protected, skipping\n"); goto free_ivar; } /* Get card SCR. Card must be selected to fetch it. */ err = mmc_select_card(sc, ivar->rca); if (err != MMC_ERR_NONE) { device_printf(sc->dev, "Error selecting card %d\n", err); goto free_ivar; } err = mmc_app_send_scr(sc, ivar->rca, ivar->raw_scr); if (err != MMC_ERR_NONE) { device_printf(sc->dev, "Error reading SCR %d\n", err); goto free_ivar; } mmc_app_decode_scr(ivar->raw_scr, &ivar->scr); /* Get card switch capabilities (command class 10). */ if ((ivar->scr.sda_vsn >= 1) && (ivar->csd.ccc & (1 << 10))) { err = mmc_sd_switch(sc, SD_SWITCH_MODE_CHECK, SD_SWITCH_GROUP1, SD_SWITCH_NOCHANGE, switch_res); if (err == MMC_ERR_NONE && switch_res[13] & (1 << SD_SWITCH_HS_MODE)) { setbit(&ivar->timings, bus_timing_hs); ivar->hs_tran_speed = SD_HS_MAX; } } /* * We deselect then reselect the card here. Some cards * become unselected and timeout with the above two * commands, although the state tables / diagrams in the * standard suggest they go back to the transfer state. * Other cards don't become deselected, and if we * attempt to blindly re-select them, we get timeout * errors from some controllers. So we deselect then * reselect to handle all situations. The only thing we * use from the sd_status is the erase sector size, but * it is still nice to get that right. */ (void)mmc_select_card(sc, 0); (void)mmc_select_card(sc, ivar->rca); (void)mmc_app_sd_status(sc, ivar->rca, ivar->raw_sd_status); mmc_app_decode_sd_status(ivar->raw_sd_status, &ivar->sd_status); if (ivar->sd_status.au_size != 0) { ivar->erase_sector = 16 << ivar->sd_status.au_size; } /* Find maximum supported bus width. */ if ((host_caps & MMC_CAP_4_BIT_DATA) && (ivar->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) ivar->bus_width = bus_width_4; goto child_common; } ivar->rca = rca++; err = mmc_set_relative_addr(sc, ivar->rca); if (err != MMC_ERR_NONE) { device_printf(sc->dev, "Error setting RCA %d\n", err); goto free_ivar; } /* Get card CSD. */ err = mmc_send_csd(sc, ivar->rca, ivar->raw_csd); if (err != MMC_ERR_NONE) { device_printf(sc->dev, "Error getting CSD %d\n", err); goto free_ivar; } if (bootverbose || mmc_debug) device_printf(sc->dev, "%sard detected (CSD %08x%08x%08x%08x)\n", newcard ? "New c" : "C", ivar->raw_csd[0], ivar->raw_csd[1], ivar->raw_csd[2], ivar->raw_csd[3]); mmc_decode_csd_mmc(ivar->raw_csd, &ivar->csd); ivar->sec_count = ivar->csd.capacity / MMC_SECTOR_SIZE; ivar->tran_speed = ivar->csd.tran_speed; ivar->erase_sector = ivar->csd.erase_sector * ivar->csd.write_bl_len / MMC_SECTOR_SIZE; err = mmc_send_status(sc->dev, sc->dev, ivar->rca, &status); if (err != MMC_ERR_NONE) { device_printf(sc->dev, "Error reading card status %d\n", err); goto free_ivar; } if ((status & R1_CARD_IS_LOCKED) != 0) { device_printf(sc->dev, "Card is password protected, skipping\n"); goto free_ivar; } err = mmc_select_card(sc, ivar->rca); if (err != MMC_ERR_NONE) { device_printf(sc->dev, "Error selecting card %d\n", err); goto free_ivar; } rev = -1; /* Only MMC >= 4.x devices support EXT_CSD. */ if (ivar->csd.spec_vers >= 4) { err = mmc_send_ext_csd(sc->dev, sc->dev, ivar->raw_ext_csd); if (err != MMC_ERR_NONE) { device_printf(sc->dev, "Error reading EXT_CSD %d\n", err); goto free_ivar; } ext_csd = ivar->raw_ext_csd; rev = ext_csd[EXT_CSD_REV]; /* Handle extended capacity from EXT_CSD */ sec_count = le32dec(&ext_csd[EXT_CSD_SEC_CNT]); if (sec_count != 0) { ivar->sec_count = sec_count; ivar->high_cap = 1; } /* Find maximum supported bus width. */ ivar->bus_width = mmc_test_bus_width(sc); /* Get device speeds beyond normal mode. */ card_type = ext_csd[EXT_CSD_CARD_TYPE]; if ((card_type & EXT_CSD_CARD_TYPE_HS_52) != 0) { setbit(&ivar->timings, bus_timing_hs); ivar->hs_tran_speed = MMC_TYPE_HS_52_MAX; } else if ((card_type & EXT_CSD_CARD_TYPE_HS_26) != 0) { setbit(&ivar->timings, bus_timing_hs); ivar->hs_tran_speed = MMC_TYPE_HS_26_MAX; } if ((card_type & EXT_CSD_CARD_TYPE_DDR_52_1_2V) != 0 && (host_caps & MMC_CAP_SIGNALING_120) != 0) { setbit(&ivar->timings, bus_timing_mmc_ddr52); setbit(&ivar->vccq_120, bus_timing_mmc_ddr52); } if ((card_type & EXT_CSD_CARD_TYPE_DDR_52_1_8V) != 0 && (host_caps & MMC_CAP_SIGNALING_180) != 0) { setbit(&ivar->timings, bus_timing_mmc_ddr52); setbit(&ivar->vccq_180, bus_timing_mmc_ddr52); } if ((card_type & EXT_CSD_CARD_TYPE_HS200_1_2V) != 0 && (host_caps & MMC_CAP_SIGNALING_120) != 0) { setbit(&ivar->timings, bus_timing_mmc_hs200); setbit(&ivar->vccq_120, bus_timing_mmc_hs200); } if ((card_type & EXT_CSD_CARD_TYPE_HS200_1_8V) != 0 && (host_caps & MMC_CAP_SIGNALING_180) != 0) { setbit(&ivar->timings, bus_timing_mmc_hs200); setbit(&ivar->vccq_180, bus_timing_mmc_hs200); } if ((card_type & EXT_CSD_CARD_TYPE_HS400_1_2V) != 0 && (host_caps & MMC_CAP_SIGNALING_120) != 0 && ivar->bus_width == bus_width_8) { setbit(&ivar->timings, bus_timing_mmc_hs400); setbit(&ivar->vccq_120, bus_timing_mmc_hs400); } if ((card_type & EXT_CSD_CARD_TYPE_HS400_1_8V) != 0 && (host_caps & MMC_CAP_SIGNALING_180) != 0 && ivar->bus_width == bus_width_8) { setbit(&ivar->timings, bus_timing_mmc_hs400); setbit(&ivar->vccq_180, bus_timing_mmc_hs400); } if ((card_type & EXT_CSD_CARD_TYPE_HS400_1_2V) != 0 && (ext_csd[EXT_CSD_STROBE_SUPPORT] & EXT_CSD_STROBE_SUPPORT_EN) != 0 && (host_caps & MMC_CAP_SIGNALING_120) != 0 && ivar->bus_width == bus_width_8) { setbit(&ivar->timings, bus_timing_mmc_hs400es); setbit(&ivar->vccq_120, bus_timing_mmc_hs400es); } if ((card_type & EXT_CSD_CARD_TYPE_HS400_1_8V) != 0 && (ext_csd[EXT_CSD_STROBE_SUPPORT] & EXT_CSD_STROBE_SUPPORT_EN) != 0 && (host_caps & MMC_CAP_SIGNALING_180) != 0 && ivar->bus_width == bus_width_8) { setbit(&ivar->timings, bus_timing_mmc_hs400es); setbit(&ivar->vccq_180, bus_timing_mmc_hs400es); } /* * Determine generic switch timeout (provided in * units of 10 ms), defaulting to 500 ms. */ ivar->cmd6_time = 500 * 1000; if (rev >= 6) ivar->cmd6_time = 10 * ext_csd[EXT_CSD_GEN_CMD6_TIME]; /* Handle HC erase sector size. */ if (ext_csd[EXT_CSD_ERASE_GRP_SIZE] != 0) { ivar->erase_sector = 1024 * ext_csd[EXT_CSD_ERASE_GRP_SIZE]; err = mmc_switch(sc->dev, sc->dev, ivar->rca, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_ERASE_GRP_DEF, EXT_CSD_ERASE_GRP_DEF_EN, ivar->cmd6_time, true); if (err != MMC_ERR_NONE) { device_printf(sc->dev, "Error setting erase group %d\n", err); goto free_ivar; } } } mmc_decode_cid_mmc(ivar->raw_cid, &ivar->cid, rev >= 5); child_common: for (quirk = &mmc_quirks[0]; quirk->mid != 0x0; quirk++) { if ((quirk->mid == MMC_QUIRK_MID_ANY || quirk->mid == ivar->cid.mid) && (quirk->oid == MMC_QUIRK_OID_ANY || quirk->oid == ivar->cid.oid) && strncmp(quirk->pnm, ivar->cid.pnm, sizeof(ivar->cid.pnm)) == 0) { ivar->quirks = quirk->quirks; break; } } /* * Some cards that report maximum I/O block sizes greater * than 512 require the block length to be set to 512, even * though that is supposed to be the default. Example: * * Transcend 2GB SDSC card, CID: * mid=0x1b oid=0x534d pnm="00000" prv=1.0 mdt=00.2000 */ if (ivar->csd.read_bl_len != MMC_SECTOR_SIZE || ivar->csd.write_bl_len != MMC_SECTOR_SIZE) mmc_set_blocklen(sc, MMC_SECTOR_SIZE); mmc_format_card_id_string(ivar); if (bootverbose || mmc_debug) mmc_log_card(sc->dev, ivar, newcard); if (newcard) { /* Add device. */ child = device_add_child(sc->dev, NULL, -1); if (child != NULL) { device_set_ivars(child, ivar); sc->child_list = realloc(sc->child_list, sizeof(device_t) * sc->child_count + 1, M_DEVBUF, M_WAITOK); sc->child_list[sc->child_count++] = child; } else device_printf(sc->dev, "Error adding child\n"); } free_ivar: if (newcard && child == NULL) free(ivar, M_DEVBUF); (void)mmc_select_card(sc, 0); /* * Not returning here when one MMC device could no be added * potentially would mean looping forever when that device * is broken (in which case it also may impact the remainder * of the bus anyway, though). */ if ((newcard && child == NULL) || mmcbr_get_mode(sc->dev) == mode_sd) return; } } static void mmc_update_child_list(struct mmc_softc *sc) { device_t child; int i, j; if (sc->child_count == 0) { free(sc->child_list, M_DEVBUF); return; } for (i = j = 0; i < sc->child_count; i++) { for (;;) { child = sc->child_list[j++]; if (child != NULL) break; } if (i != j) sc->child_list[i] = child; } sc->child_list = realloc(sc->child_list, sizeof(device_t) * sc->child_count, M_DEVBUF, M_WAITOK); } static void mmc_rescan_cards(struct mmc_softc *sc) { struct mmc_ivars *ivar; int err, i, j; for (i = j = 0; i < sc->child_count; i++) { ivar = device_get_ivars(sc->child_list[i]); if (mmc_select_card(sc, ivar->rca) != MMC_ERR_NONE) { if (bootverbose || mmc_debug) device_printf(sc->dev, "Card at relative address %d lost\n", ivar->rca); err = device_delete_child(sc->dev, sc->child_list[i]); if (err != 0) { j++; continue; } free(ivar, M_DEVBUF); } else j++; } if (sc->child_count == j) goto out; sc->child_count = j; mmc_update_child_list(sc); out: (void)mmc_select_card(sc, 0); } static int mmc_delete_cards(struct mmc_softc *sc, bool final) { struct mmc_ivars *ivar; int err, i, j; err = 0; for (i = j = 0; i < sc->child_count; i++) { ivar = device_get_ivars(sc->child_list[i]); if (bootverbose || mmc_debug) device_printf(sc->dev, "Card at relative address %d deleted\n", ivar->rca); err = device_delete_child(sc->dev, sc->child_list[i]); if (err != 0) { j++; if (final == false) continue; else break; } free(ivar, M_DEVBUF); } sc->child_count = j; mmc_update_child_list(sc); return (err); } static void mmc_go_discovery(struct mmc_softc *sc) { uint32_t ocr; device_t dev; int err; dev = sc->dev; if (mmcbr_get_power_mode(dev) != power_on) { /* * First, try SD modes */ sc->squelched++; /* Errors are expected, squelch reporting. */ mmcbr_set_mode(dev, mode_sd); mmc_power_up(sc); mmcbr_set_bus_mode(dev, pushpull); if (bootverbose || mmc_debug) device_printf(sc->dev, "Probing bus\n"); mmc_idle_cards(sc); err = mmc_send_if_cond(sc, 1); if ((bootverbose || mmc_debug) && err == 0) device_printf(sc->dev, "SD 2.0 interface conditions: OK\n"); if (mmc_send_app_op_cond(sc, 0, &ocr) != MMC_ERR_NONE) { if (bootverbose || mmc_debug) device_printf(sc->dev, "SD probe: failed\n"); /* * Failed, try MMC */ mmcbr_set_mode(dev, mode_mmc); if (mmc_send_op_cond(sc, 0, &ocr) != MMC_ERR_NONE) { if (bootverbose || mmc_debug) device_printf(sc->dev, "MMC probe: failed\n"); ocr = 0; /* Failed both, powerdown. */ } else if (bootverbose || mmc_debug) device_printf(sc->dev, "MMC probe: OK (OCR: 0x%08x)\n", ocr); } else if (bootverbose || mmc_debug) device_printf(sc->dev, "SD probe: OK (OCR: 0x%08x)\n", ocr); sc->squelched--; mmcbr_set_ocr(dev, mmc_select_vdd(sc, ocr)); if (mmcbr_get_ocr(dev) != 0) mmc_idle_cards(sc); } else { mmcbr_set_bus_mode(dev, opendrain); mmcbr_set_clock(dev, SD_MMC_CARD_ID_FREQUENCY); mmcbr_update_ios(dev); /* XXX recompute vdd based on new cards? */ } /* * Make sure that we have a mutually agreeable voltage to at least * one card on the bus. */ if (bootverbose || mmc_debug) device_printf(sc->dev, "Current OCR: 0x%08x\n", mmcbr_get_ocr(dev)); if (mmcbr_get_ocr(dev) == 0) { device_printf(sc->dev, "No compatible cards found on bus\n"); (void)mmc_delete_cards(sc, false); mmc_power_down(sc); return; } /* * Reselect the cards after we've idled them above. */ if (mmcbr_get_mode(dev) == mode_sd) { err = mmc_send_if_cond(sc, 1); mmc_send_app_op_cond(sc, (err ? 0 : MMC_OCR_CCS) | mmcbr_get_ocr(dev), NULL); } else mmc_send_op_cond(sc, MMC_OCR_CCS | mmcbr_get_ocr(dev), NULL); mmc_discover_cards(sc); mmc_rescan_cards(sc); mmcbr_set_bus_mode(dev, pushpull); mmcbr_update_ios(dev); mmc_calculate_clock(sc); } static int mmc_calculate_clock(struct mmc_softc *sc) { device_t dev; struct mmc_ivars *ivar; int i; uint32_t dtr, max_dtr; uint16_t rca; enum mmc_bus_timing max_timing, timing; bool changed, hs400; dev = sc->dev; max_dtr = mmcbr_get_f_max(dev); max_timing = bus_timing_max; do { changed = false; for (i = 0; i < sc->child_count; i++) { ivar = device_get_ivars(sc->child_list[i]); if (isclr(&ivar->timings, max_timing) || !mmc_host_timing(dev, max_timing)) { for (timing = max_timing - 1; timing >= bus_timing_normal; timing--) { if (isset(&ivar->timings, timing) && mmc_host_timing(dev, timing)) { max_timing = timing; break; } } changed = true; } dtr = mmc_timing_to_dtr(ivar, max_timing); if (dtr < max_dtr) { max_dtr = dtr; changed = true; } } } while (changed == true); if (bootverbose || mmc_debug) { device_printf(dev, "setting transfer rate to %d.%03dMHz (%s timing)\n", max_dtr / 1000000, (max_dtr / 1000) % 1000, mmc_timing_to_string(max_timing)); } /* * HS400 must be tuned in HS200 mode, so in case of HS400 we begin * with HS200 following the sequence as described in "6.6.2.2 HS200 * timing mode selection" of the eMMC specification v5.1, too, and * switch to max_timing later. HS400ES requires no tuning and, thus, * can be switch to directly, but requires the same detour via high * speed mode as does HS400 (see mmc_switch_to_hs400()). */ hs400 = max_timing == bus_timing_mmc_hs400; timing = hs400 == true ? bus_timing_mmc_hs200 : max_timing; for (i = 0; i < sc->child_count; i++) { ivar = device_get_ivars(sc->child_list[i]); if ((ivar->timings & ~(1 << bus_timing_normal)) == 0) goto clock; rca = ivar->rca; if (mmc_select_card(sc, rca) != MMC_ERR_NONE) { device_printf(dev, "Card at relative address %d " "failed to select\n", rca); continue; } if (timing == bus_timing_mmc_hs200 || /* includes HS400 */ timing == bus_timing_mmc_hs400es) { if (mmc_set_vccq(sc, ivar, timing) != MMC_ERR_NONE) { device_printf(dev, "Failed to set VCCQ for " "card at relative address %d\n", rca); continue; } } if (timing == bus_timing_mmc_hs200) { /* includes HS400 */ /* Set bus width (required for initial tuning). */ if (mmc_set_card_bus_width(sc, ivar, timing) != MMC_ERR_NONE) { device_printf(dev, "Card at relative address " "%d failed to set bus width\n", rca); continue; } mmcbr_set_bus_width(dev, ivar->bus_width); mmcbr_update_ios(dev); } else if (timing == bus_timing_mmc_hs400es) { if (mmc_switch_to_hs400(sc, ivar, max_dtr, timing) != MMC_ERR_NONE) { device_printf(dev, "Card at relative address " "%d failed to set %s timing\n", rca, mmc_timing_to_string(timing)); continue; } goto power_class; } if (mmc_set_timing(sc, ivar, timing) != MMC_ERR_NONE) { device_printf(dev, "Card at relative address %d " "failed to set %s timing\n", rca, mmc_timing_to_string(timing)); continue; } if (timing == bus_timing_mmc_ddr52) { /* * Set EXT_CSD_BUS_WIDTH_n_DDR in EXT_CSD_BUS_WIDTH * (must be done after switching to EXT_CSD_HS_TIMING). */ if (mmc_set_card_bus_width(sc, ivar, timing) != MMC_ERR_NONE) { device_printf(dev, "Card at relative address " "%d failed to set bus width\n", rca); continue; } mmcbr_set_bus_width(dev, ivar->bus_width); mmcbr_update_ios(dev); if (mmc_set_vccq(sc, ivar, timing) != MMC_ERR_NONE) { device_printf(dev, "Failed to set VCCQ for " "card at relative address %d\n", rca); continue; } } clock: /* Set clock (must be done before initial tuning). */ mmcbr_set_clock(dev, max_dtr); mmcbr_update_ios(dev); if (mmcbr_tune(dev, hs400) != 0) { device_printf(dev, "Card at relative address %d " "failed to execute initial tuning\n", rca); continue; } if (hs400 == true && mmc_switch_to_hs400(sc, ivar, max_dtr, max_timing) != MMC_ERR_NONE) { device_printf(dev, "Card at relative address %d " "failed to set %s timing\n", rca, mmc_timing_to_string(max_timing)); continue; } power_class: if (mmc_set_power_class(sc, ivar) != MMC_ERR_NONE) { device_printf(dev, "Card at relative address %d " "failed to set power class\n", rca); } } (void)mmc_select_card(sc, 0); return (max_dtr); } /* * Switch from HS200 to HS400 (either initially or for re-tuning) or directly * to HS400ES. This follows the sequences described in "6.6.2.3 HS400 timing * mode selection" of the eMMC specification v5.1. */ static int mmc_switch_to_hs400(struct mmc_softc *sc, struct mmc_ivars *ivar, uint32_t clock, enum mmc_bus_timing max_timing) { device_t dev; int err; uint16_t rca; dev = sc->dev; rca = ivar->rca; /* * Both clock and timing must be set as appropriate for high speed * before eventually switching to HS400/HS400ES; mmc_set_timing() * will issue mmcbr_update_ios(). */ mmcbr_set_clock(dev, ivar->hs_tran_speed); err = mmc_set_timing(sc, ivar, bus_timing_hs); if (err != MMC_ERR_NONE) return (err); /* * Set EXT_CSD_BUS_WIDTH_8_DDR in EXT_CSD_BUS_WIDTH (and additionally * EXT_CSD_BUS_WIDTH_ES for HS400ES). */ err = mmc_set_card_bus_width(sc, ivar, max_timing); if (err != MMC_ERR_NONE) return (err); mmcbr_set_bus_width(dev, ivar->bus_width); mmcbr_update_ios(dev); /* Finally, switch to HS400/HS400ES mode. */ err = mmc_set_timing(sc, ivar, max_timing); if (err != MMC_ERR_NONE) return (err); mmcbr_set_clock(dev, clock); mmcbr_update_ios(dev); return (MMC_ERR_NONE); } /* * Switch from HS400 to HS200 (for re-tuning). */ static int mmc_switch_to_hs200(struct mmc_softc *sc, struct mmc_ivars *ivar, uint32_t clock) { device_t dev; int err; uint16_t rca; dev = sc->dev; rca = ivar->rca; /* * Both clock and timing must initially be set as appropriate for * DDR52 before eventually switching to HS200; mmc_set_timing() * will issue mmcbr_update_ios(). */ mmcbr_set_clock(dev, ivar->hs_tran_speed); err = mmc_set_timing(sc, ivar, bus_timing_mmc_ddr52); if (err != MMC_ERR_NONE) return (err); /* * Next, switch to high speed. Thus, clear EXT_CSD_BUS_WIDTH_n_DDR * in EXT_CSD_BUS_WIDTH and update bus width and timing in ios. */ err = mmc_set_card_bus_width(sc, ivar, bus_timing_hs); if (err != MMC_ERR_NONE) return (err); mmcbr_set_bus_width(dev, ivar->bus_width); mmcbr_set_timing(sc->dev, bus_timing_hs); mmcbr_update_ios(dev); /* Finally, switch to HS200 mode. */ err = mmc_set_timing(sc, ivar, bus_timing_mmc_hs200); if (err != MMC_ERR_NONE) return (err); mmcbr_set_clock(dev, clock); mmcbr_update_ios(dev); return (MMC_ERR_NONE); } static int mmc_retune(device_t busdev, device_t dev, bool reset) { struct mmc_softc *sc; struct mmc_ivars *ivar; int err; uint32_t clock; enum mmc_bus_timing timing; if (device_get_parent(dev) != busdev) return (MMC_ERR_INVALID); sc = device_get_softc(busdev); if (sc->retune_needed != 1 && sc->retune_paused != 0) return (MMC_ERR_INVALID); timing = mmcbr_get_timing(busdev); if (timing == bus_timing_mmc_hs400) { /* * Controllers use the data strobe line to latch data from * the devices in HS400 mode so periodic re-tuning isn't * expected to be required, i. e. only if a CRC or tuning * error is signaled to the bridge. In these latter cases * we are asked to reset the tuning circuit and need to do * the switch timing dance. */ if (reset == false) return (0); ivar = device_get_ivars(dev); clock = mmcbr_get_clock(busdev); if (mmc_switch_to_hs200(sc, ivar, clock) != MMC_ERR_NONE) return (MMC_ERR_BADCRC); } err = mmcbr_retune(busdev, reset); if (err != 0 && timing == bus_timing_mmc_hs400) return (MMC_ERR_BADCRC); switch (err) { case 0: break; case EIO: return (MMC_ERR_FAILED); default: return (MMC_ERR_INVALID); } if (timing == bus_timing_mmc_hs400) { if (mmc_switch_to_hs400(sc, ivar, clock, timing) != MMC_ERR_NONE) return (MMC_ERR_BADCRC); } return (MMC_ERR_NONE); } static void mmc_retune_pause(device_t busdev, device_t dev, bool retune) { struct mmc_softc *sc; sc = device_get_softc(busdev); KASSERT(device_get_parent(dev) == busdev, ("%s: %s is not a child of %s", __func__, device_get_nameunit(dev), device_get_nameunit(busdev))); KASSERT(sc->owner != NULL, ("%s: Request from %s without bus being acquired.", __func__, device_get_nameunit(dev))); if (retune == true && sc->retune_paused == 0) sc->retune_needed = 1; sc->retune_paused++; } static void mmc_retune_unpause(device_t busdev, device_t dev) { struct mmc_softc *sc; sc = device_get_softc(busdev); KASSERT(device_get_parent(dev) == busdev, ("%s: %s is not a child of %s", __func__, device_get_nameunit(dev), device_get_nameunit(busdev))); KASSERT(sc->owner != NULL, ("%s: Request from %s without bus being acquired.", __func__, device_get_nameunit(dev))); KASSERT(sc->retune_paused != 0, ("%s: Re-tune pause count already at 0", __func__)); sc->retune_paused--; } static void mmc_scan(struct mmc_softc *sc) { device_t dev = sc->dev; int err; err = mmc_acquire_bus(dev, dev); if (err != 0) { device_printf(dev, "Failed to acquire bus for scanning\n"); return; } mmc_go_discovery(sc); err = mmc_release_bus(dev, dev); if (err != 0) { device_printf(dev, "Failed to release bus after scanning\n"); return; } (void)bus_generic_attach(dev); } static int mmc_read_ivar(device_t bus, device_t child, int which, uintptr_t *result) { struct mmc_ivars *ivar = device_get_ivars(child); switch (which) { default: return (EINVAL); case MMC_IVAR_SPEC_VERS: *result = ivar->csd.spec_vers; break; case MMC_IVAR_DSR_IMP: *result = ivar->csd.dsr_imp; break; case MMC_IVAR_MEDIA_SIZE: *result = ivar->sec_count; break; case MMC_IVAR_RCA: *result = ivar->rca; break; case MMC_IVAR_SECTOR_SIZE: *result = MMC_SECTOR_SIZE; break; case MMC_IVAR_TRAN_SPEED: *result = mmcbr_get_clock(bus); break; case MMC_IVAR_READ_ONLY: *result = ivar->read_only; break; case MMC_IVAR_HIGH_CAP: *result = ivar->high_cap; break; case MMC_IVAR_CARD_TYPE: *result = ivar->mode; break; case MMC_IVAR_BUS_WIDTH: *result = ivar->bus_width; break; case MMC_IVAR_ERASE_SECTOR: *result = ivar->erase_sector; break; case MMC_IVAR_MAX_DATA: *result = mmcbr_get_max_data(bus); break; case MMC_IVAR_CMD6_TIMEOUT: *result = ivar->cmd6_time; break; case MMC_IVAR_QUIRKS: *result = ivar->quirks; break; case MMC_IVAR_CARD_ID_STRING: *(char **)result = ivar->card_id_string; break; case MMC_IVAR_CARD_SN_STRING: *(char **)result = ivar->card_sn_string; break; } return (0); } static int mmc_write_ivar(device_t bus, device_t child, int which, uintptr_t value) { /* * None are writable ATM */ return (EINVAL); } static void mmc_delayed_attach(void *xsc) { struct mmc_softc *sc = xsc; mmc_scan(sc); config_intrhook_disestablish(&sc->config_intrhook); } static int mmc_child_location_str(device_t dev, device_t child, char *buf, size_t buflen) { snprintf(buf, buflen, "rca=0x%04x", mmc_get_rca(child)); return (0); } static device_method_t mmc_methods[] = { /* device_if */ DEVMETHOD(device_probe, mmc_probe), DEVMETHOD(device_attach, mmc_attach), DEVMETHOD(device_detach, mmc_detach), DEVMETHOD(device_suspend, mmc_suspend), DEVMETHOD(device_resume, mmc_resume), /* Bus interface */ DEVMETHOD(bus_read_ivar, mmc_read_ivar), DEVMETHOD(bus_write_ivar, mmc_write_ivar), DEVMETHOD(bus_child_location_str, mmc_child_location_str), /* MMC Bus interface */ DEVMETHOD(mmcbus_retune_pause, mmc_retune_pause), DEVMETHOD(mmcbus_retune_unpause, mmc_retune_unpause), DEVMETHOD(mmcbus_wait_for_request, mmc_wait_for_request), DEVMETHOD(mmcbus_acquire_bus, mmc_acquire_bus), DEVMETHOD(mmcbus_release_bus, mmc_release_bus), DEVMETHOD_END }; driver_t mmc_driver = { "mmc", mmc_methods, sizeof(struct mmc_softc), }; devclass_t mmc_devclass; MODULE_VERSION(mmc, MMC_VERSION); Index: head/sys/dev/mmc/mmc_private.h =================================================================== --- head/sys/dev/mmc/mmc_private.h (revision 355393) +++ head/sys/dev/mmc/mmc_private.h (revision 355394) @@ -1,74 +1,74 @@ /*- * Copyright (c) 2006 Bernd Walter. All rights reserved. - * Copyright (c) 2006 M. Warner Losh. + * Copyright (c) 2006 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Portions of this software may have been developed with reference to * the SD Simplified Specification. The following disclaimer may apply: * * The following conditions apply to the release of the simplified * specification ("Simplified Specification") by the SD Card Association and * the SD Group. The Simplified Specification is a subset of the complete SD * Specification which is owned by the SD Card Association and the SD * Group. This Simplified Specification is provided on a non-confidential * basis subject to the disclaimers below. Any implementation of the * Simplified Specification may require a license from the SD Card * Association, SD Group, SD-3C LLC or other third parties. * * Disclaimers: * * The information contained in the Simplified Specification is presented only * as a standard specification for SD Cards and SD Host/Ancillary products and * is provided "AS-IS" without any representations or warranties of any * kind. No responsibility is assumed by the SD Group, SD-3C LLC or the SD * Card Association for any damages, any infringements of patents or other * right of the SD Group, SD-3C LLC, the SD Card Association or any third * parties, which may result from its use. No license is granted by * implication, estoppel or otherwise under any patent or other rights of the * SD Group, SD-3C LLC, the SD Card Association or any third party. Nothing * herein shall be construed as an obligation by the SD Group, the SD-3C LLC * or the SD Card Association to disclose or distribute any technical * information, know-how or other confidential information to any third party. * * $FreeBSD$ */ #ifndef DEV_MMC_PRIVATE_H #define DEV_MMC_PRIVATE_H struct mmc_softc { device_t dev; struct mtx sc_mtx; struct intr_config_hook config_intrhook; device_t owner; device_t *child_list; int child_count; uint16_t last_rca; uint16_t retune_paused; uint8_t retune_needed; uint8_t retune_ongoing; uint16_t squelched; /* suppress reporting of (expected) errors */ int log_count; struct timeval log_time; }; #endif /* DEV_MMC_PRIVATE_H */ Index: head/sys/dev/mmc/mmc_subr.c =================================================================== --- head/sys/dev/mmc/mmc_subr.c (revision 355393) +++ head/sys/dev/mmc/mmc_subr.c (revision 355394) @@ -1,264 +1,264 @@ /*- * Copyright (c) 2006 Bernd Walter. All rights reserved. - * Copyright (c) 2006 M. Warner Losh. + * Copyright (c) 2006 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Portions of this software may have been developed with reference to * the SD Simplified Specification. The following disclaimer may apply: * * The following conditions apply to the release of the simplified * specification ("Simplified Specification") by the SD Card Association and * the SD Group. The Simplified Specification is a subset of the complete SD * Specification which is owned by the SD Card Association and the SD * Group. This Simplified Specification is provided on a non-confidential * basis subject to the disclaimers below. Any implementation of the * Simplified Specification may require a license from the SD Card * Association, SD Group, SD-3C LLC or other third parties. * * Disclaimers: * * The information contained in the Simplified Specification is presented only * as a standard specification for SD Cards and SD Host/Ancillary products and * is provided "AS-IS" without any representations or warranties of any * kind. No responsibility is assumed by the SD Group, SD-3C LLC or the SD * Card Association for any damages, any infringements of patents or other * right of the SD Group, SD-3C LLC, the SD Card Association or any third * parties, which may result from its use. No license is granted by * implication, estoppel or otherwise under any patent or other rights of the * SD Group, SD-3C LLC, the SD Card Association or any third party. Nothing * herein shall be construed as an obligation by the SD Group, the SD-3C LLC * or the SD Card Association to disclose or distribute any technical * information, know-how or other confidential information to any third party. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include "mmcbus_if.h" #define CMD_RETRIES 3 #define LOG_PPS 5 /* Log no more than 5 errors per second. */ int mmc_wait_for_cmd(device_t busdev, device_t dev, struct mmc_command *cmd, int retries) { struct mmc_request mreq; struct mmc_softc *sc; int err; do { memset(&mreq, 0, sizeof(mreq)); memset(cmd->resp, 0, sizeof(cmd->resp)); cmd->retries = 0; /* Retries done here, not in hardware. */ cmd->mrq = &mreq; if (cmd->data != NULL) cmd->data->mrq = &mreq; mreq.cmd = cmd; if (MMCBUS_WAIT_FOR_REQUEST(busdev, dev, &mreq) != 0) err = MMC_ERR_FAILED; else err = cmd->error; } while (err != MMC_ERR_NONE && retries-- > 0); if (err != MMC_ERR_NONE && busdev == dev) { sc = device_get_softc(busdev); if (sc->squelched == 0 && ppsratecheck(&sc->log_time, &sc->log_count, LOG_PPS)) { device_printf(sc->dev, "CMD%d failed, RESULT: %d\n", cmd->opcode, err); } } return (err); } int mmc_wait_for_app_cmd(device_t busdev, device_t dev, uint16_t rca, struct mmc_command *cmd, int retries) { struct mmc_command appcmd; struct mmc_softc *sc; int err; sc = device_get_softc(busdev); /* Squelch error reporting at lower levels, we report below. */ sc->squelched++; do { memset(&appcmd, 0, sizeof(appcmd)); appcmd.opcode = MMC_APP_CMD; appcmd.arg = (uint32_t)rca << 16; appcmd.flags = MMC_RSP_R1 | MMC_CMD_AC; if (mmc_wait_for_cmd(busdev, dev, &appcmd, 0) != 0) err = MMC_ERR_FAILED; else err = appcmd.error; if (err == MMC_ERR_NONE) { if (!(appcmd.resp[0] & R1_APP_CMD)) err = MMC_ERR_FAILED; else if (mmc_wait_for_cmd(busdev, dev, cmd, 0) != 0) err = MMC_ERR_FAILED; else err = cmd->error; } } while (err != MMC_ERR_NONE && retries-- > 0); sc->squelched--; if (err != MMC_ERR_NONE && busdev == dev) { if (sc->squelched == 0 && ppsratecheck(&sc->log_time, &sc->log_count, LOG_PPS)) { device_printf(sc->dev, "ACMD%d failed, RESULT: %d\n", cmd->opcode, err); } } return (err); } int mmc_switch(device_t busdev, device_t dev, uint16_t rca, uint8_t set, uint8_t index, uint8_t value, u_int timeout, bool status) { struct mmc_command cmd; struct mmc_softc *sc; int err; KASSERT(timeout != 0, ("%s: no timeout", __func__)); sc = device_get_softc(busdev); memset(&cmd, 0, sizeof(cmd)); cmd.opcode = MMC_SWITCH_FUNC; cmd.arg = (MMC_SWITCH_FUNC_WR << 24) | (index << 16) | (value << 8) | set; /* * If the hardware supports busy detection but the switch timeout * exceeds the maximum host timeout, use a R1 instead of a R1B * response in order to keep the hardware from timing out. */ if (mmcbr_get_caps(busdev) & MMC_CAP_WAIT_WHILE_BUSY && timeout > mmcbr_get_max_busy_timeout(busdev)) cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; else cmd.flags = MMC_RSP_R1B | MMC_CMD_AC; /* * Pause re-tuning so it won't interfere with the busy state and also * so that the result of CMD13 will always refer to switching rather * than to a tuning command that may have snuck in between. */ sc->retune_paused++; err = mmc_wait_for_cmd(busdev, dev, &cmd, CMD_RETRIES); if (err != MMC_ERR_NONE || status == false) goto out; err = mmc_switch_status(busdev, dev, rca, timeout); out: sc->retune_paused--; return (err); } int mmc_switch_status(device_t busdev, device_t dev, uint16_t rca, u_int timeout) { struct timeval cur, end; int err; uint32_t status; KASSERT(timeout != 0, ("%s: no timeout", __func__)); /* * Note that when using a R1B response in mmc_switch(), bridges of * type MMC_CAP_WAIT_WHILE_BUSY will issue mmc_send_status() only * once and then exit the loop. */ end.tv_sec = end.tv_usec = 0; for (;;) { err = mmc_send_status(busdev, dev, rca, &status); if (err != MMC_ERR_NONE) break; if (R1_CURRENT_STATE(status) == R1_STATE_TRAN) break; getmicrouptime(&cur); if (end.tv_sec == 0 && end.tv_usec == 0) { end.tv_usec = timeout; timevaladd(&end, &cur); } if (timevalcmp(&cur, &end, >)) { err = MMC_ERR_TIMEOUT; break; } } if (err == MMC_ERR_NONE && (status & R1_SWITCH_ERROR) != 0) return (MMC_ERR_FAILED); return (err); } int mmc_send_ext_csd(device_t busdev, device_t dev, uint8_t *rawextcsd) { struct mmc_command cmd; struct mmc_data data; int err; memset(&cmd, 0, sizeof(cmd)); memset(&data, 0, sizeof(data)); memset(rawextcsd, 0, MMC_EXTCSD_SIZE); cmd.opcode = MMC_SEND_EXT_CSD; cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; cmd.data = &data; data.data = rawextcsd; data.len = MMC_EXTCSD_SIZE; data.flags = MMC_DATA_READ; err = mmc_wait_for_cmd(busdev, dev, &cmd, CMD_RETRIES); return (err); } int mmc_send_status(device_t busdev, device_t dev, uint16_t rca, uint32_t *status) { struct mmc_command cmd; int err; memset(&cmd, 0, sizeof(cmd)); cmd.opcode = MMC_SEND_STATUS; cmd.arg = (uint32_t)rca << 16; cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; err = mmc_wait_for_cmd(busdev, dev, &cmd, CMD_RETRIES); *status = cmd.resp[0]; return (err); } Index: head/sys/dev/mmc/mmc_subr.h =================================================================== --- head/sys/dev/mmc/mmc_subr.h (revision 355393) +++ head/sys/dev/mmc/mmc_subr.h (revision 355394) @@ -1,72 +1,72 @@ /*- * Copyright (c) 2006 Bernd Walter. All rights reserved. - * Copyright (c) 2006 M. Warner Losh. + * Copyright (c) 2006 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Portions of this software may have been developed with reference to * the SD Simplified Specification. The following disclaimer may apply: * * The following conditions apply to the release of the simplified * specification ("Simplified Specification") by the SD Card Association and * the SD Group. The Simplified Specification is a subset of the complete SD * Specification which is owned by the SD Card Association and the SD * Group. This Simplified Specification is provided on a non-confidential * basis subject to the disclaimers below. Any implementation of the * Simplified Specification may require a license from the SD Card * Association, SD Group, SD-3C LLC or other third parties. * * Disclaimers: * * The information contained in the Simplified Specification is presented only * as a standard specification for SD Cards and SD Host/Ancillary products and * is provided "AS-IS" without any representations or warranties of any * kind. No responsibility is assumed by the SD Group, SD-3C LLC or the SD * Card Association for any damages, any infringements of patents or other * right of the SD Group, SD-3C LLC, the SD Card Association or any third * parties, which may result from its use. No license is granted by * implication, estoppel or otherwise under any patent or other rights of the * SD Group, SD-3C LLC, the SD Card Association or any third party. Nothing * herein shall be construed as an obligation by the SD Group, the SD-3C LLC * or the SD Card Association to disclose or distribute any technical * information, know-how or other confidential information to any third party. * * $FreeBSD$ */ #ifndef DEV_MMC_SUBR_H #define DEV_MMC_SUBR_H struct mmc_command; int mmc_send_ext_csd(device_t busdev, device_t dev, uint8_t *rawextcsd); int mmc_send_status(device_t busdev, device_t dev, uint16_t rca, uint32_t *status); int mmc_switch(device_t busdev, device_t dev, uint16_t rca, uint8_t set, uint8_t index, uint8_t value, u_int timeout, bool send_status); int mmc_switch_status(device_t busdev, device_t dev, uint16_t rca, u_int timeout); int mmc_wait_for_app_cmd(device_t busdev, device_t dev, uint16_t rca, struct mmc_command *cmd, int retries); int mmc_wait_for_cmd(device_t busdev, device_t dev, struct mmc_command *cmd, int retries); #endif /* DEV_MMC_SUBR_H */ Index: head/sys/dev/mmc/mmcbr_if.m =================================================================== --- head/sys/dev/mmc/mmcbr_if.m (revision 355393) +++ head/sys/dev/mmc/mmcbr_if.m (revision 355394) @@ -1,166 +1,165 @@ #- -# Copyright (c) 2006 M. Warner Losh -# All rights reserved. +# Copyright (c) 2006 M. Warner Losh # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # Portions of this software may have been developed with reference to # the SD Simplified Specification. The following disclaimer may apply: # # The following conditions apply to the release of the simplified # specification ("Simplified Specification") by the SD Card Association and # the SD Group. The Simplified Specification is a subset of the complete SD # Specification which is owned by the SD Card Association and the SD # Group. This Simplified Specification is provided on a non-confidential # basis subject to the disclaimers below. Any implementation of the # Simplified Specification may require a license from the SD Card # Association, SD Group, SD-3C LLC or other third parties. # # Disclaimers: # # The information contained in the Simplified Specification is presented only # as a standard specification for SD Cards and SD Host/Ancillary products and # is provided "AS-IS" without any representations or warranties of any # kind. No responsibility is assumed by the SD Group, SD-3C LLC or the SD # Card Association for any damages, any infringements of patents or other # right of the SD Group, SD-3C LLC, the SD Card Association or any third # parties, which may result from its use. No license is granted by # implication, estoppel or otherwise under any patent or other rights of the # SD Group, SD-3C LLC, the SD Card Association or any third party. Nothing # herein shall be construed as an obligation by the SD Group, the SD-3C LLC # or the SD Card Association to disclose or distribute any technical # information, know-how or other confidential information to any third party. # # $FreeBSD$ # #include #include # # This is the interface that a mmc bridge chip gives to the mmc bus # that attaches to the mmc bridge. # INTERFACE mmcbr; # # Default implementations of some methods. # CODE { static int null_switch_vccq(device_t brdev __unused, device_t reqdev __unused) { return (0); } static int null_retune(device_t brdev __unused, device_t reqdev __unused, bool reset __unused) { return (0); } static int null_tune(device_t brdev __unused, device_t reqdev __unused, bool hs400 __unused) { return (0); } }; # # Called by the mmcbus to set up the IO pins correctly, the common/core # supply voltage (VDD/VCC) to use for the device, the clock frequency, the # type of SPI chip select, power mode and bus width. # METHOD int update_ios { device_t brdev; device_t reqdev; }; # # Called by the mmcbus to switch the signaling voltage (VCCQ). # METHOD int switch_vccq { device_t brdev; device_t reqdev; } DEFAULT null_switch_vccq; # # Called by the mmcbus with the bridge claimed to execute initial tuning. # METHOD int tune { device_t brdev; device_t reqdev; bool hs400; } DEFAULT null_tune; # # Called by the mmcbus with the bridge claimed to execute re-tuning. # METHOD int retune { device_t brdev; device_t reqdev; bool reset; } DEFAULT null_retune; # # Called by the mmcbus or its children to schedule a mmc request. These # requests are queued. Time passes. The bridge then gets notification # of the status of the request, who then notifies the requesting device # by calling the completion function supplied as part of the request. # Requires the bridge to be claimed. # METHOD int request { device_t brdev; device_t reqdev; struct mmc_request *req; }; # # Called by mmcbus to get the read only status bits. # METHOD int get_ro { device_t brdev; device_t reqdev; }; # # Claim the current bridge, blocking the current thread until the host # is no longer busy. # METHOD int acquire_host { device_t brdev; device_t reqdev; }; # # Release the current bridge. # METHOD int release_host { device_t brdev; device_t reqdev; }; Index: head/sys/dev/mmc/mmcbrvar.h =================================================================== --- head/sys/dev/mmc/mmcbrvar.h (revision 355393) +++ head/sys/dev/mmc/mmcbrvar.h (revision 355394) @@ -1,156 +1,156 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2006 Bernd Walter. All rights reserved. - * Copyright (c) 2006 M. Warner Losh. + * Copyright (c) 2006 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Portions of this software may have been developed with reference to * the SD Simplified Specification. The following disclaimer may apply: * * The following conditions apply to the release of the simplified * specification ("Simplified Specification") by the SD Card Association and * the SD Group. The Simplified Specification is a subset of the complete SD * Specification which is owned by the SD Card Association and the SD * Group. This Simplified Specification is provided on a non-confidential * basis subject to the disclaimers below. Any implementation of the * Simplified Specification may require a license from the SD Card * Association, SD Group, SD-3C LLC or other third parties. * * Disclaimers: * * The information contained in the Simplified Specification is presented only * as a standard specification for SD Cards and SD Host/Ancillary products and * is provided "AS-IS" without any representations or warranties of any * kind. No responsibility is assumed by the SD Group, SD-3C LLC or the SD * Card Association for any damages, any infringements of patents or other * right of the SD Group, SD-3C LLC, the SD Card Association or any third * parties, which may result from its use. No license is granted by * implication, estoppel or otherwise under any patent or other rights of the * SD Group, SD-3C LLC, the SD Card Association or any third party. Nothing * herein shall be construed as an obligation by the SD Group, the SD-3C LLC * or the SD Card Association to disclose or distribute any technical * information, know-how or other confidential information to any third party. * * $FreeBSD$ */ #ifndef DEV_MMC_MMCBRVAR_H #define DEV_MMC_MMCBRVAR_H #include #include "mmcbr_if.h" enum mmcbr_device_ivars { MMCBR_IVAR_BUS_MODE, MMCBR_IVAR_BUS_WIDTH, MMCBR_IVAR_CHIP_SELECT, MMCBR_IVAR_CLOCK, MMCBR_IVAR_F_MIN, MMCBR_IVAR_F_MAX, MMCBR_IVAR_HOST_OCR, MMCBR_IVAR_MODE, MMCBR_IVAR_OCR, MMCBR_IVAR_POWER_MODE, MMCBR_IVAR_RETUNE_REQ, MMCBR_IVAR_VDD, MMCBR_IVAR_VCCQ, MMCBR_IVAR_CAPS, MMCBR_IVAR_TIMING, MMCBR_IVAR_MAX_DATA, MMCBR_IVAR_MAX_BUSY_TIMEOUT }; /* * Simplified accessors for bridge devices */ #define MMCBR_ACCESSOR(var, ivar, type) \ __BUS_ACCESSOR(mmcbr, var, MMCBR, ivar, type) MMCBR_ACCESSOR(bus_mode, BUS_MODE, int) MMCBR_ACCESSOR(bus_width, BUS_WIDTH, int) MMCBR_ACCESSOR(chip_select, CHIP_SELECT, int) MMCBR_ACCESSOR(clock, CLOCK, int) MMCBR_ACCESSOR(f_max, F_MAX, int) MMCBR_ACCESSOR(f_min, F_MIN, int) MMCBR_ACCESSOR(host_ocr, HOST_OCR, int) MMCBR_ACCESSOR(mode, MODE, int) MMCBR_ACCESSOR(ocr, OCR, int) MMCBR_ACCESSOR(power_mode, POWER_MODE, int) MMCBR_ACCESSOR(vdd, VDD, int) MMCBR_ACCESSOR(vccq, VCCQ, int) MMCBR_ACCESSOR(caps, CAPS, int) MMCBR_ACCESSOR(timing, TIMING, int) MMCBR_ACCESSOR(max_data, MAX_DATA, int) MMCBR_ACCESSOR(max_busy_timeout, MAX_BUSY_TIMEOUT, u_int) static int __inline mmcbr_get_retune_req(device_t dev) { uintptr_t v; if (__predict_false(BUS_READ_IVAR(device_get_parent(dev), dev, MMCBR_IVAR_RETUNE_REQ, &v) != 0)) return (retune_req_none); return ((int)v); } /* * Convenience wrappers for the mmcbr interface */ static int __inline mmcbr_update_ios(device_t dev) { return (MMCBR_UPDATE_IOS(device_get_parent(dev), dev)); } static int __inline mmcbr_tune(device_t dev, bool hs400) { return (MMCBR_TUNE(device_get_parent(dev), dev, hs400)); } static int __inline mmcbr_retune(device_t dev, bool reset) { return (MMCBR_RETUNE(device_get_parent(dev), dev, reset)); } static int __inline mmcbr_switch_vccq(device_t dev) { return (MMCBR_SWITCH_VCCQ(device_get_parent(dev), dev)); } static int __inline mmcbr_get_ro(device_t dev) { return (MMCBR_GET_RO(device_get_parent(dev), dev)); } #endif /* DEV_MMC_MMCBRVAR_H */ Index: head/sys/dev/mmc/mmcbus_if.m =================================================================== --- head/sys/dev/mmc/mmcbus_if.m (revision 355393) +++ head/sys/dev/mmc/mmcbus_if.m (revision 355394) @@ -1,108 +1,107 @@ #- -# Copyright (c) 2006 M. Warner Losh -# All rights reserved. +# Copyright (c) 2006 M. Warner Losh # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # Portions of this software may have been developed with reference to # the SD Simplified Specification. The following disclaimer may apply: # # The following conditions apply to the release of the simplified # specification ("Simplified Specification") by the SD Card Association and # the SD Group. The Simplified Specification is a subset of the complete SD # Specification which is owned by the SD Card Association and the SD # Group. This Simplified Specification is provided on a non-confidential # basis subject to the disclaimers below. Any implementation of the # Simplified Specification may require a license from the SD Card # Association, SD Group, SD-3C LLC or other third parties. # # Disclaimers: # # The information contained in the Simplified Specification is presented only # as a standard specification for SD Cards and SD Host/Ancillary products and # is provided "AS-IS" without any representations or warranties of any # kind. No responsibility is assumed by the SD Group, SD-3C LLC or the SD # Card Association for any damages, any infringements of patents or other # right of the SD Group, SD-3C LLC, the SD Card Association or any third # parties, which may result from its use. No license is granted by # implication, estoppel or otherwise under any patent or other rights of the # SD Group, SD-3C LLC, the SD Card Association or any third party. Nothing # herein shall be construed as an obligation by the SD Group, the SD-3C LLC # or the SD Card Association to disclose or distribute any technical # information, know-how or other confidential information to any third party. # # $FreeBSD$ # #include #include # # This is the set of callbacks that the MMC subroutines and the mmc/sd card # driver call into the bus to make requests. # INTERFACE mmcbus; # # Pause re-tuning, optionally with triggering re-tuning up-front. Requires # the bus to be claimed. # METHOD void retune_pause { device_t busdev; device_t reqdev; bool retune; }; # # Unpause re-tuning. Requires the bus to be claimed. # METHOD void retune_unpause { device_t busdev; device_t reqdev; }; # # Queue and wait for a request. Requires the bus to be claimed. # METHOD int wait_for_request { device_t busdev; device_t reqdev; struct mmc_request *req; }; # # Claim the current bus, blocking the current thread until the host is no # longer busy. # METHOD int acquire_bus { device_t busdev; device_t reqdev; }; # # Release the current bus. # METHOD int release_bus { device_t busdev; device_t reqdev; }; Index: head/sys/dev/mmc/mmcreg.h =================================================================== --- head/sys/dev/mmc/mmcreg.h (revision 355393) +++ head/sys/dev/mmc/mmcreg.h (revision 355394) @@ -1,734 +1,734 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2006 M. Warner Losh. + * Copyright (c) 2006 M. Warner Losh * Copyright (c) 2017 Marius Strobl * Copyright (c) 2015-2016 Ilya Bakulin * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Portions of this software may have been developed with reference to * the SD Simplified Specification. The following disclaimer may apply: * * The following conditions apply to the release of the simplified * specification ("Simplified Specification") by the SD Card Association and * the SD Group. The Simplified Specification is a subset of the complete SD * Specification which is owned by the SD Card Association and the SD * Group. This Simplified Specification is provided on a non-confidential * basis subject to the disclaimers below. Any implementation of the * Simplified Specification may require a license from the SD Card * Association, SD Group, SD-3C LLC or other third parties. * * Disclaimers: * * The information contained in the Simplified Specification is presented only * as a standard specification for SD Cards and SD Host/Ancillary products and * is provided "AS-IS" without any representations or warranties of any * kind. No responsibility is assumed by the SD Group, SD-3C LLC or the SD * Card Association for any damages, any infringements of patents or other * right of the SD Group, SD-3C LLC, the SD Card Association or any third * parties, which may result from its use. No license is granted by * implication, estoppel or otherwise under any patent or other rights of the * SD Group, SD-3C LLC, the SD Card Association or any third party. Nothing * herein shall be construed as an obligation by the SD Group, the SD-3C LLC * or the SD Card Association to disclose or distribute any technical * information, know-how or other confidential information to any third party. * * $FreeBSD$ */ #ifndef DEV_MMC_MMCREG_H #define DEV_MMC_MMCREG_H /* * This file contains the register definitions for the mmc and sd buses. * They are taken from publicly available sources. */ struct mmc_data; struct mmc_request; struct mmc_command { uint32_t opcode; uint32_t arg; uint32_t resp[4]; uint32_t flags; /* Expected responses */ #define MMC_RSP_PRESENT (1ul << 0) /* Response */ #define MMC_RSP_136 (1ul << 1) /* 136 bit response */ #define MMC_RSP_CRC (1ul << 2) /* Expect valid crc */ #define MMC_RSP_BUSY (1ul << 3) /* Card may send busy */ #define MMC_RSP_OPCODE (1ul << 4) /* Response include opcode */ #define MMC_RSP_MASK 0x1ful #define MMC_CMD_AC (0ul << 5) /* Addressed Command, no data */ #define MMC_CMD_ADTC (1ul << 5) /* Addressed Data transfer cmd */ #define MMC_CMD_BC (2ul << 5) /* Broadcast command, no response */ #define MMC_CMD_BCR (3ul << 5) /* Broadcast command with response */ #define MMC_CMD_MASK (3ul << 5) /* Possible response types defined in the standard: */ #define MMC_RSP_NONE (0) #define MMC_RSP_R1 (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE) #define MMC_RSP_R1B (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE | MMC_RSP_BUSY) #define MMC_RSP_R2 (MMC_RSP_PRESENT | MMC_RSP_136 | MMC_RSP_CRC) #define MMC_RSP_R3 (MMC_RSP_PRESENT) #define MMC_RSP_R4 (MMC_RSP_PRESENT) #define MMC_RSP_R5 (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE) #define MMC_RSP_R5B (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE | MMC_RSP_BUSY) #define MMC_RSP_R6 (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE) #define MMC_RSP_R7 (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE) #define MMC_RSP(x) ((x) & MMC_RSP_MASK) uint32_t retries; uint32_t error; #define MMC_ERR_NONE 0 #define MMC_ERR_TIMEOUT 1 #define MMC_ERR_BADCRC 2 #define MMC_ERR_FIFO 3 #define MMC_ERR_FAILED 4 #define MMC_ERR_INVALID 5 #define MMC_ERR_NO_MEMORY 6 #define MMC_ERR_MAX 6 struct mmc_data *data; /* Data segment with cmd */ struct mmc_request *mrq; /* backpointer to request */ }; /* * R1 responses * * Types (per SD 2.0 standard) * e : error bit * s : status bit * r : detected and set for the actual command response * x : Detected and set during command execution. The host can get * the status by issuing a command with R1 response. * * Clear Condition (per SD 2.0 standard) * a : according to the card current state. * b : always related to the previous command. reception of a valid * command will clear it (with a delay of one command). * c : clear by read */ #define R1_OUT_OF_RANGE (1u << 31) /* erx, c */ #define R1_ADDRESS_ERROR (1u << 30) /* erx, c */ #define R1_BLOCK_LEN_ERROR (1u << 29) /* erx, c */ #define R1_ERASE_SEQ_ERROR (1u << 28) /* er, c */ #define R1_ERASE_PARAM (1u << 27) /* erx, c */ #define R1_WP_VIOLATION (1u << 26) /* erx, c */ #define R1_CARD_IS_LOCKED (1u << 25) /* sx, a */ #define R1_LOCK_UNLOCK_FAILED (1u << 24) /* erx, c */ #define R1_COM_CRC_ERROR (1u << 23) /* er, b */ #define R1_ILLEGAL_COMMAND (1u << 22) /* er, b */ #define R1_CARD_ECC_FAILED (1u << 21) /* erx, c */ #define R1_CC_ERROR (1u << 20) /* erx, c */ #define R1_ERROR (1u << 19) /* erx, c */ #define R1_CSD_OVERWRITE (1u << 16) /* erx, c */ #define R1_WP_ERASE_SKIP (1u << 15) /* erx, c */ #define R1_CARD_ECC_DISABLED (1u << 14) /* sx, a */ #define R1_ERASE_RESET (1u << 13) /* sr, c */ #define R1_CURRENT_STATE_MASK (0xfu << 9) /* sx, b */ #define R1_READY_FOR_DATA (1u << 8) /* sx, a */ #define R1_SWITCH_ERROR (1u << 7) /* sx, c */ #define R1_APP_CMD (1u << 5) /* sr, c */ #define R1_AKE_SEQ_ERROR (1u << 3) /* er, c */ #define R1_STATUS(x) ((x) & 0xFFFFE000) #define R1_CURRENT_STATE(x) (((x) & R1_CURRENT_STATE_MASK) >> 9) #define R1_STATE_IDLE 0 #define R1_STATE_READY 1 #define R1_STATE_IDENT 2 #define R1_STATE_STBY 3 #define R1_STATE_TRAN 4 #define R1_STATE_DATA 5 #define R1_STATE_RCV 6 #define R1_STATE_PRG 7 #define R1_STATE_DIS 8 /* R4 responses (SDIO) */ #define R4_IO_NUM_FUNCTIONS(ocr) (((ocr) >> 28) & 0x3) #define R4_IO_MEM_PRESENT (0x1 << 27) #define R4_IO_OCR_MASK 0x00fffff0 /* * R5 responses * * Types (per SD 2.0 standard) * e : error bit * s : status bit * r : detected and set for the actual command response * x : Detected and set during command execution. The host can get * the status by issuing a command with R1 response. * * Clear Condition (per SD 2.0 standard) * a : according to the card current state. * b : always related to the previous command. reception of a valid * command will clear it (with a delay of one command). * c : clear by read */ #define R5_COM_CRC_ERROR (1u << 15) /* er, b */ #define R5_ILLEGAL_COMMAND (1u << 14) /* er, b */ #define R5_IO_CURRENT_STATE_MASK (3u << 12) /* s, b */ #define R5_IO_CURRENT_STATE(x) (((x) & R5_IO_CURRENT_STATE_MASK) >> 12) #define R5_ERROR (1u << 11) /* erx, c */ #define R5_FUNCTION_NUMBER (1u << 9) /* er, c */ #define R5_OUT_OF_RANGE (1u << 8) /* er, c */ struct mmc_data { size_t len; /* size of the data */ size_t xfer_len; void *data; /* data buffer */ uint32_t flags; #define MMC_DATA_WRITE (1UL << 0) #define MMC_DATA_READ (1UL << 1) #define MMC_DATA_STREAM (1UL << 2) #define MMC_DATA_MULTI (1UL << 3) #define MMC_DATA_BLOCK_SIZE (1UL << 4) struct mmc_request *mrq; size_t block_size; /* block size for CMD53 */ size_t block_count; /* block count for CMD53 */ }; struct mmc_request { struct mmc_command *cmd; struct mmc_command *stop; void (*done)(struct mmc_request *); /* Completion function */ void *done_data; /* requestor set data */ uint32_t flags; #define MMC_REQ_DONE 1 #define MMC_TUNE_DONE 2 }; /* Command definitions */ /* Class 0 and 1: Basic commands & read stream commands */ #define MMC_GO_IDLE_STATE 0 #define MMC_SEND_OP_COND 1 #define MMC_ALL_SEND_CID 2 #define MMC_SET_RELATIVE_ADDR 3 #define SD_SEND_RELATIVE_ADDR 3 #define MMC_SET_DSR 4 #define MMC_SLEEP_AWAKE 5 #define IO_SEND_OP_COND 5 #define MMC_SWITCH_FUNC 6 #define MMC_SWITCH_FUNC_CMDS 0 #define MMC_SWITCH_FUNC_SET 1 #define MMC_SWITCH_FUNC_CLR 2 #define MMC_SWITCH_FUNC_WR 3 #define MMC_SELECT_CARD 7 #define MMC_DESELECT_CARD 7 #define MMC_SEND_EXT_CSD 8 #define SD_SEND_IF_COND 8 #define MMC_SEND_CSD 9 #define MMC_SEND_CID 10 #define MMC_READ_DAT_UNTIL_STOP 11 #define MMC_STOP_TRANSMISSION 12 #define MMC_SEND_STATUS 13 #define MMC_BUSTEST_R 14 #define MMC_GO_INACTIVE_STATE 15 #define MMC_BUSTEST_W 19 /* Class 2: Block oriented read commands */ #define MMC_SET_BLOCKLEN 16 #define MMC_READ_SINGLE_BLOCK 17 #define MMC_READ_MULTIPLE_BLOCK 18 #define MMC_SEND_TUNING_BLOCK 19 #define MMC_SEND_TUNING_BLOCK_HS200 21 /* Class 3: Stream write commands */ #define MMC_WRITE_DAT_UNTIL_STOP 20 /* reserved: 22 */ /* Class 4: Block oriented write commands */ #define MMC_SET_BLOCK_COUNT 23 #define MMC_WRITE_BLOCK 24 #define MMC_WRITE_MULTIPLE_BLOCK 25 #define MMC_PROGARM_CID 26 #define MMC_PROGRAM_CSD 27 /* Class 6: Block oriented write protection commands */ #define MMC_SET_WRITE_PROT 28 #define MMC_CLR_WRITE_PROT 29 #define MMC_SEND_WRITE_PROT 30 /* reserved: 31 */ /* Class 5: Erase commands */ #define SD_ERASE_WR_BLK_START 32 #define SD_ERASE_WR_BLK_END 33 /* 34 -- reserved old command */ #define MMC_ERASE_GROUP_START 35 #define MMC_ERASE_GROUP_END 36 /* 37 -- reserved old command */ #define MMC_ERASE 38 #define MMC_ERASE_ERASE 0x00000000 #define MMC_ERASE_TRIM 0x00000001 #define MMC_ERASE_FULE 0x00000002 #define MMC_ERASE_DISCARD 0x00000003 #define MMC_ERASE_SECURE_ERASE 0x80000000 #define MMC_ERASE_SECURE_TRIM1 0x80000001 #define MMC_ERASE_SECURE_TRIM2 0x80008000 /* Class 9: I/O mode commands */ #define MMC_FAST_IO 39 #define MMC_GO_IRQ_STATE 40 /* reserved: 41 */ /* Class 7: Lock card */ #define MMC_LOCK_UNLOCK 42 /* reserved: 43 */ /* reserved: 44 */ /* reserved: 45 */ /* reserved: 46 */ /* reserved: 47 */ /* reserved: 48 */ /* reserved: 49 */ /* reserved: 50 */ /* reserved: 51 */ /* reserved: 54 */ /* Class 8: Application specific commands */ #define MMC_APP_CMD 55 #define MMC_GEN_CMD 56 /* reserved: 57 */ /* reserved: 58 */ /* reserved: 59 */ /* reserved for mfg: 60 */ /* reserved for mfg: 61 */ /* reserved for mfg: 62 */ /* reserved for mfg: 63 */ /* Class 9: I/O cards (sd) */ #define SD_IO_RW_DIRECT 52 /* CMD52 arguments */ #define SD_ARG_CMD52_READ (0 << 31) #define SD_ARG_CMD52_WRITE (1 << 31) #define SD_ARG_CMD52_FUNC_SHIFT 28 #define SD_ARG_CMD52_FUNC_MASK 0x7 #define SD_ARG_CMD52_EXCHANGE (1 << 27) #define SD_ARG_CMD52_REG_SHIFT 9 #define SD_ARG_CMD52_REG_MASK 0x1ffff #define SD_ARG_CMD52_DATA_SHIFT 0 #define SD_ARG_CMD52_DATA_MASK 0xff #define SD_R5_DATA(resp) ((resp)[0] & 0xff) #define SD_IO_RW_EXTENDED 53 /* CMD53 arguments */ #define SD_ARG_CMD53_READ (0 << 31) #define SD_ARG_CMD53_WRITE (1 << 31) #define SD_ARG_CMD53_FUNC_SHIFT 28 #define SD_ARG_CMD53_FUNC_MASK 0x7 #define SD_ARG_CMD53_BLOCK_MODE (1 << 27) #define SD_ARG_CMD53_INCREMENT (1 << 26) #define SD_ARG_CMD53_REG_SHIFT 9 #define SD_ARG_CMD53_REG_MASK 0x1ffff #define SD_ARG_CMD53_LENGTH_SHIFT 0 #define SD_ARG_CMD53_LENGTH_MASK 0x1ff #define SD_ARG_CMD53_LENGTH_MAX 64 /* XXX should be 511? */ /* Class 10: Switch function commands */ #define SD_SWITCH_FUNC 6 /* reserved: 34 */ /* reserved: 35 */ /* reserved: 36 */ /* reserved: 37 */ /* reserved: 50 */ /* reserved: 57 */ /* Application specific commands for SD */ #define ACMD_SET_BUS_WIDTH 6 #define ACMD_SD_STATUS 13 #define ACMD_SEND_NUM_WR_BLOCKS 22 #define ACMD_SET_WR_BLK_ERASE_COUNT 23 #define ACMD_SD_SEND_OP_COND 41 #define ACMD_SET_CLR_CARD_DETECT 42 #define ACMD_SEND_SCR 51 /* * EXT_CSD fields */ #define EXT_CSD_FLUSH_CACHE 32 /* W/E */ #define EXT_CSD_CACHE_CTRL 33 /* R/W/E */ #define EXT_CSD_EXT_PART_ATTR 52 /* R/W, 2 bytes */ #define EXT_CSD_ENH_START_ADDR 136 /* R/W, 4 bytes */ #define EXT_CSD_ENH_SIZE_MULT 140 /* R/W, 3 bytes */ #define EXT_CSD_GP_SIZE_MULT 143 /* R/W, 12 bytes */ #define EXT_CSD_PART_SET 155 /* R/W */ #define EXT_CSD_PART_ATTR 156 /* R/W */ #define EXT_CSD_PART_SUPPORT 160 /* RO */ #define EXT_CSD_RPMB_MULT 168 /* RO */ #define EXT_CSD_BOOT_WP_STATUS 174 /* RO */ #define EXT_CSD_ERASE_GRP_DEF 175 /* R/W */ #define EXT_CSD_PART_CONFIG 179 /* R/W */ #define EXT_CSD_BUS_WIDTH 183 /* R/W */ #define EXT_CSD_STROBE_SUPPORT 184 /* RO */ #define EXT_CSD_HS_TIMING 185 /* R/W */ #define EXT_CSD_POWER_CLASS 187 /* R/W */ #define EXT_CSD_CARD_TYPE 196 /* RO */ #define EXT_CSD_DRIVER_STRENGTH 197 /* RO */ #define EXT_CSD_REV 192 /* RO */ #define EXT_CSD_PART_SWITCH_TO 199 /* RO */ #define EXT_CSD_PWR_CL_52_195 200 /* RO */ #define EXT_CSD_PWR_CL_26_195 201 /* RO */ #define EXT_CSD_PWR_CL_52_360 202 /* RO */ #define EXT_CSD_PWR_CL_26_360 203 /* RO */ #define EXT_CSD_SEC_CNT 212 /* RO, 4 bytes */ #define EXT_CSD_HC_WP_GRP_SIZE 221 /* RO */ #define EXT_CSD_ERASE_TO_MULT 223 /* RO */ #define EXT_CSD_ERASE_GRP_SIZE 224 /* RO */ #define EXT_CSD_BOOT_SIZE_MULT 226 /* RO */ #define EXT_CSD_SEC_FEATURE_SUPPORT 231 /* RO */ #define EXT_CSD_PWR_CL_200_195 236 /* RO */ #define EXT_CSD_PWR_CL_200_360 237 /* RO */ #define EXT_CSD_PWR_CL_52_195_DDR 238 /* RO */ #define EXT_CSD_PWR_CL_52_360_DDR 239 /* RO */ #define EXT_CSD_CACHE_FLUSH_POLICY 249 /* RO */ #define EXT_CSD_GEN_CMD6_TIME 248 /* RO */ #define EXT_CSD_CACHE_SIZE 249 /* RO, 4 bytes */ #define EXT_CSD_PWR_CL_200_360_DDR 253 /* RO */ /* * EXT_CSD field definitions */ #define EXT_CSD_FLUSH_CACHE_FLUSH 0x01 #define EXT_CSD_FLUSH_CACHE_BARRIER 0x02 #define EXT_CSD_CACHE_CTRL_CACHE_EN 0x01 #define EXT_CSD_EXT_PART_ATTR_DEFAULT 0x0 #define EXT_CSD_EXT_PART_ATTR_SYSTEMCODE 0x1 #define EXT_CSD_EXT_PART_ATTR_NPERSISTENT 0x2 #define EXT_CSD_PART_SET_COMPLETED 0x01 #define EXT_CSD_PART_ATTR_ENH_USR 0x01 #define EXT_CSD_PART_ATTR_ENH_GP0 0x02 #define EXT_CSD_PART_ATTR_ENH_GP1 0x04 #define EXT_CSD_PART_ATTR_ENH_GP2 0x08 #define EXT_CSD_PART_ATTR_ENH_GP3 0x10 #define EXT_CSD_PART_ATTR_ENH_MASK 0x1f #define EXT_CSD_PART_SUPPORT_EN 0x01 #define EXT_CSD_PART_SUPPORT_ENH_ATTR_EN 0x02 #define EXT_CSD_PART_SUPPORT_EXT_ATTR_EN 0x04 #define EXT_CSD_BOOT_WP_STATUS_BOOT0_PWR 0x01 #define EXT_CSD_BOOT_WP_STATUS_BOOT0_PERM 0x02 #define EXT_CSD_BOOT_WP_STATUS_BOOT0_MASK 0x03 #define EXT_CSD_BOOT_WP_STATUS_BOOT1_PWR 0x04 #define EXT_CSD_BOOT_WP_STATUS_BOOT1_PERM 0x08 #define EXT_CSD_BOOT_WP_STATUS_BOOT1_MASK 0x0c #define EXT_CSD_ERASE_GRP_DEF_EN 0x01 #define EXT_CSD_PART_CONFIG_ACC_DEFAULT 0x00 #define EXT_CSD_PART_CONFIG_ACC_BOOT0 0x01 #define EXT_CSD_PART_CONFIG_ACC_BOOT1 0x02 #define EXT_CSD_PART_CONFIG_ACC_RPMB 0x03 #define EXT_CSD_PART_CONFIG_ACC_GP0 0x04 #define EXT_CSD_PART_CONFIG_ACC_GP1 0x05 #define EXT_CSD_PART_CONFIG_ACC_GP2 0x06 #define EXT_CSD_PART_CONFIG_ACC_GP3 0x07 #define EXT_CSD_PART_CONFIG_ACC_MASK 0x07 #define EXT_CSD_PART_CONFIG_BOOT0 0x08 #define EXT_CSD_PART_CONFIG_BOOT1 0x10 #define EXT_CSD_PART_CONFIG_BOOT_USR 0x38 #define EXT_CSD_PART_CONFIG_BOOT_MASK 0x38 #define EXT_CSD_PART_CONFIG_BOOT_ACK 0x40 #define EXT_CSD_CMD_SET_NORMAL 1 #define EXT_CSD_CMD_SET_SECURE 2 #define EXT_CSD_CMD_SET_CPSECURE 4 #define EXT_CSD_HS_TIMING_BC 0 #define EXT_CSD_HS_TIMING_HS 1 #define EXT_CSD_HS_TIMING_HS200 2 #define EXT_CSD_HS_TIMING_HS400 3 #define EXT_CSD_HS_TIMING_DRV_STR_SHIFT 4 #define EXT_CSD_POWER_CLASS_8BIT_MASK 0xf0 #define EXT_CSD_POWER_CLASS_8BIT_SHIFT 4 #define EXT_CSD_POWER_CLASS_4BIT_MASK 0x0f #define EXT_CSD_POWER_CLASS_4BIT_SHIFT 0 #define EXT_CSD_CARD_TYPE_HS_26 0x0001 #define EXT_CSD_CARD_TYPE_HS_52 0x0002 #define EXT_CSD_CARD_TYPE_DDR_52_1_8V 0x0004 #define EXT_CSD_CARD_TYPE_DDR_52_1_2V 0x0008 #define EXT_CSD_CARD_TYPE_HS200_1_8V 0x0010 #define EXT_CSD_CARD_TYPE_HS200_1_2V 0x0020 #define EXT_CSD_CARD_TYPE_HS400_1_8V 0x0040 #define EXT_CSD_CARD_TYPE_HS400_1_2V 0x0080 #define EXT_CSD_BUS_WIDTH_1 0 #define EXT_CSD_BUS_WIDTH_4 1 #define EXT_CSD_BUS_WIDTH_8 2 #define EXT_CSD_BUS_WIDTH_4_DDR 5 #define EXT_CSD_BUS_WIDTH_8_DDR 6 #define EXT_CSD_BUS_WIDTH_ES 0x80 #define EXT_CSD_STROBE_SUPPORT_EN 0x01 #define EXT_CSD_SEC_FEATURE_SUPPORT_ER_EN 0x01 #define EXT_CSD_SEC_FEATURE_SUPPORT_BD_BLK_EN 0x04 #define EXT_CSD_SEC_FEATURE_SUPPORT_GB_CL_EN 0x10 #define EXT_CSD_SEC_FEATURE_SUPPORT_SANITIZE 0x40 #define EXT_CSD_CACHE_FLUSH_POLICY_FIFO 0x01 /* * Vendor specific EXT_CSD fields */ /* SanDisk iNAND */ #define EXT_CSD_INAND_CMD38 113 #define EXT_CSD_INAND_CMD38_ERASE 0x00 #define EXT_CSD_INAND_CMD38_TRIM 0x01 #define EXT_CSD_INAND_CMD38_SECURE_ERASE 0x80 #define EXT_CSD_INAND_CMD38_SECURE_TRIM1 0x81 #define EXT_CSD_INAND_CMD38_SECURE_TRIM2 0x82 #define MMC_TYPE_HS_26_MAX 26000000 #define MMC_TYPE_HS_52_MAX 52000000 #define MMC_TYPE_DDR52_MAX 52000000 #define MMC_TYPE_HS200_HS400ES_MAX 200000000 /* * SD bus widths */ #define SD_BUS_WIDTH_1 0 #define SD_BUS_WIDTH_4 2 /* * SD Switch */ #define SD_SWITCH_MODE_CHECK 0 #define SD_SWITCH_MODE_SET 1 #define SD_SWITCH_GROUP1 0 #define SD_SWITCH_NORMAL_MODE 0 #define SD_SWITCH_HS_MODE 1 #define SD_SWITCH_SDR50_MODE 2 #define SD_SWITCH_SDR104_MODE 3 #define SD_SWITCH_DDR50 4 #define SD_SWITCH_NOCHANGE 0xF #define SD_CLR_CARD_DETECT 0 #define SD_SET_CARD_DETECT 1 #define SD_HS_MAX 50000000 #define SD_DDR50_MAX 50000000 #define SD_SDR12_MAX 25000000 #define SD_SDR25_MAX 50000000 #define SD_SDR50_MAX 100000000 #define SD_SDR104_MAX 208000000 /* Specifications require 400 kHz max. during ID phase. */ #define SD_MMC_CARD_ID_FREQUENCY 400000 /* * SDIO Direct & Extended I/O */ #define SD_IO_RW_WR (1u << 31) #define SD_IO_RW_FUNC(x) (((x) & 0x7) << 28) #define SD_IO_RW_RAW (1u << 27) #define SD_IO_RW_INCR (1u << 26) #define SD_IO_RW_ADR(x) (((x) & 0x1FFFF) << 9) #define SD_IO_RW_DAT(x) (((x) & 0xFF) << 0) #define SD_IO_RW_LEN(x) (((x) & 0xFF) << 0) #define SD_IOE_RW_LEN(x) (((x) & 0x1FF) << 0) #define SD_IOE_RW_ADR(x) (((x) & 0x1FFFF) << 9) #define SD_IOE_RW_INCR (1u << 26) #define SD_IOE_RW_BLK (1u << 27) #define SD_IOE_RW_FUNC(x) (((x) & 0x7) << 28) #define SD_IOE_RW_WR (1u << 31) /* Card Common Control Registers (CCCR) */ #define SD_IO_CCCR_START 0x00000 /* Offset in F0 address space */ #define SD_IO_CCCR_SIZE 0x100 /* Total size of CCCR */ #define SD_IO_CCCR_FN_ENABLE 0x02 /* Enabled functions */ #define SD_IO_CCCR_FN_READY 0x03 /* Function ready status */ #define SD_IO_CCCR_INT_ENABLE 0x04 /* Per-function interrupt enable */ #define SD_IO_CCCR_INT_PENDING 0x05 /* Per-function interrupt pending */ #define SD_IO_CCCR_CTL 0x06 /* I/O Abort register */ #define CCCR_CTL_RES (1 << 3) /* Perform SDIO reset */ #define SD_IO_CCCR_BUS_WIDTH 0x07 /* Bus Width register */ #define CCCR_BUS_WIDTH_4 (1 << 1) #define CCCR_BUS_WIDTH_1 (1 << 0) #define SD_IO_CCCR_CARDCAP 0x08 /* SDIO card capabilities */ #define CCCR_CC_SMB (1 << 1) /* CMD53 block mode support */ #define SD_IO_CCCR_CISPTR 0x09 /* 0x09 - 0x0B */ #define SD_IO_CCCR_FN0_BLKSZ 0x10 /* 0x10 - 0x11 */ /* Function Basic Registers (FBR) */ #define SD_IO_FBR_START 0x00100 /* Offset in F0 address space */ #define SD_IO_FBR_SIZE 0x00700 /* Total size of FBR */ #define SD_IO_FBR_F_SIZE 0x00100 /* Size of each function */ #define SD_IO_FBR_START_F(n) (SD_IO_FBR_START + (n-1) * SD_IO_FBR_F_SIZE) #define SD_IO_FBR_CIS_OFFSET 0x9 /* Offset of this function's info block within CIS area */ #define SD_IO_FBR_IOBLKSZ 0x10 /* Block size for CMD53 block mode operations */ /* Card Information Structure (CIS) */ #define SD_IO_CIS_START 0x01000 /* Offset in F0 address space */ #define SD_IO_CIS_SIZE 0x17000 /* Total size of CIS */ /* CIS tuple codes (based on PC Card 16) */ #define SD_IO_CISTPL_VERS_1 0x15 #define SD_IO_CISTPL_MANFID 0x20 #define SD_IO_CISTPL_FUNCID 0x21 #define SD_IO_CISTPL_FUNCE 0x22 #define SD_IO_CISTPL_END 0xff /* CISTPL_FUNCID codes */ /* OpenBSD incorrectly defines 0x0c as FUNCTION_WLAN */ /* #define SDMMC_FUNCTION_WLAN 0x0c */ /* OCR bits */ /* * in SD 2.0 spec, bits 8-14 are now marked reserved * Low voltage in SD2.0 spec is bit 7, TBD voltage * Low voltage in MC 3.31 spec is bit 7, 1.65-1.95V * Specs prior to MMC 3.31 defined bits 0-7 as voltages down to 1.5V. * 3.31 redefined them to be reserved and also said that cards had to * support the 2.7-3.6V and fixed the OCR to be 0xfff8000 for high voltage * cards. MMC 4.0 says that a dual voltage card responds with 0xfff8080. * Looks like the fine-grained control of the voltage tolerance ranges * was abandoned. * * The MMC_OCR_CCS appears to be valid for only SD cards. */ #define MMC_OCR_VOLTAGE 0x3fffffffU /* Vdd Voltage mask */ #define MMC_OCR_LOW_VOLTAGE (1u << 7) /* Low Voltage Range -- tbd */ #define MMC_OCR_MIN_VOLTAGE_SHIFT 7 #define MMC_OCR_200_210 (1U << 8) /* Vdd voltage 2.00 ~ 2.10 */ #define MMC_OCR_210_220 (1U << 9) /* Vdd voltage 2.10 ~ 2.20 */ #define MMC_OCR_220_230 (1U << 10) /* Vdd voltage 2.20 ~ 2.30 */ #define MMC_OCR_230_240 (1U << 11) /* Vdd voltage 2.30 ~ 2.40 */ #define MMC_OCR_240_250 (1U << 12) /* Vdd voltage 2.40 ~ 2.50 */ #define MMC_OCR_250_260 (1U << 13) /* Vdd voltage 2.50 ~ 2.60 */ #define MMC_OCR_260_270 (1U << 14) /* Vdd voltage 2.60 ~ 2.70 */ #define MMC_OCR_270_280 (1U << 15) /* Vdd voltage 2.70 ~ 2.80 */ #define MMC_OCR_280_290 (1U << 16) /* Vdd voltage 2.80 ~ 2.90 */ #define MMC_OCR_290_300 (1U << 17) /* Vdd voltage 2.90 ~ 3.00 */ #define MMC_OCR_300_310 (1U << 18) /* Vdd voltage 3.00 ~ 3.10 */ #define MMC_OCR_310_320 (1U << 19) /* Vdd voltage 3.10 ~ 3.20 */ #define MMC_OCR_320_330 (1U << 20) /* Vdd voltage 3.20 ~ 3.30 */ #define MMC_OCR_330_340 (1U << 21) /* Vdd voltage 3.30 ~ 3.40 */ #define MMC_OCR_340_350 (1U << 22) /* Vdd voltage 3.40 ~ 3.50 */ #define MMC_OCR_350_360 (1U << 23) /* Vdd voltage 3.50 ~ 3.60 */ #define MMC_OCR_MAX_VOLTAGE_SHIFT 23 #define MMC_OCR_S18R (1U << 24) /* Switching to 1.8 V requested (SD) */ #define MMC_OCR_S18A MMC_OCR_S18R /* Switching to 1.8 V accepted (SD) */ #define MMC_OCR_XPC (1U << 28) /* SDXC Power Control */ #define MMC_OCR_ACCESS_MODE_BYTE (0U << 29) /* Access Mode Byte (MMC) */ #define MMC_OCR_ACCESS_MODE_SECT (1U << 29) /* Access Mode Sector (MMC) */ #define MMC_OCR_ACCESS_MODE_MASK (3U << 29) #define MMC_OCR_CCS (1u << 30) /* Card Capacity status (SD vs SDHC) */ #define MMC_OCR_CARD_BUSY (1U << 31) /* Card Power up status */ /* CSD -- decoded structure */ struct mmc_cid { uint32_t mid; char pnm[8]; uint32_t psn; uint16_t oid; uint16_t mdt_year; uint8_t mdt_month; uint8_t prv; uint8_t fwrev; }; struct mmc_csd { uint8_t csd_structure; uint8_t spec_vers; uint16_t ccc; uint16_t tacc; uint32_t nsac; uint32_t r2w_factor; uint32_t tran_speed; uint32_t read_bl_len; uint32_t write_bl_len; uint32_t vdd_r_curr_min; uint32_t vdd_r_curr_max; uint32_t vdd_w_curr_min; uint32_t vdd_w_curr_max; uint32_t wp_grp_size; uint32_t erase_sector; uint64_t capacity; unsigned int read_bl_partial:1, read_blk_misalign:1, write_bl_partial:1, write_blk_misalign:1, dsr_imp:1, erase_blk_en:1, wp_grp_enable:1; }; struct mmc_scr { unsigned char sda_vsn; unsigned char bus_widths; #define SD_SCR_BUS_WIDTH_1 (1 << 0) #define SD_SCR_BUS_WIDTH_4 (1 << 2) }; struct mmc_sd_status { uint8_t bus_width; uint8_t secured_mode; uint16_t card_type; uint16_t prot_area; uint8_t speed_class; uint8_t perf_move; uint8_t au_size; uint16_t erase_size; uint8_t erase_timeout; uint8_t erase_offset; }; struct mmc_quirk { uint32_t mid; #define MMC_QUIRK_MID_ANY ((uint32_t)-1) uint16_t oid; #define MMC_QUIRK_OID_ANY ((uint16_t)-1) const char *pnm; uint32_t quirks; #define MMC_QUIRK_INAND_CMD38 0x0001 #define MMC_QUIRK_BROKEN_TRIM 0x0002 }; #define MMC_QUIRKS_FMT "\020" "\001INAND_CMD38" "\002BROKEN_TRIM" /* * Various MMC/SD constants */ #define MMC_BOOT_RPMB_BLOCK_SIZE (128 * 1024) #define MMC_EXTCSD_SIZE 512 #define MMC_PART_GP_MAX 4 #define MMC_PART_MAX 8 #define MMC_TUNING_MAX 64 /* Maximum tuning iterations */ #define MMC_TUNING_LEN 64 /* Size of tuning data */ #define MMC_TUNING_LEN_HS200 128 /* Size of tuning data in HS200 mode */ /* * Older versions of the MMC standard had a variable sector size. However, * I've been able to find no old MMC or SD cards that have a non 512 * byte sector size anywhere, so we assume that such cards are very rare * and only note their existence in passing here... */ #define MMC_SECTOR_SIZE 512 #endif /* DEV_MMCREG_H */ Index: head/sys/dev/mmc/mmcsd.c =================================================================== --- head/sys/dev/mmc/mmcsd.c (revision 355393) +++ head/sys/dev/mmc/mmcsd.c (revision 355394) @@ -1,1576 +1,1576 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2006 Bernd Walter. All rights reserved. - * Copyright (c) 2006 M. Warner Losh. + * Copyright (c) 2006 M. Warner Losh * Copyright (c) 2017 Marius Strobl * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Portions of this software may have been developed with reference to * the SD Simplified Specification. The following disclaimer may apply: * * The following conditions apply to the release of the simplified * specification ("Simplified Specification") by the SD Card Association and * the SD Group. The Simplified Specification is a subset of the complete SD * Specification which is owned by the SD Card Association and the SD * Group. This Simplified Specification is provided on a non-confidential * basis subject to the disclaimers below. Any implementation of the * Simplified Specification may require a license from the SD Card * Association, SD Group, SD-3C LLC or other third parties. * * Disclaimers: * * The information contained in the Simplified Specification is presented only * as a standard specification for SD Cards and SD Host/Ancillary products and * is provided "AS-IS" without any representations or warranties of any * kind. No responsibility is assumed by the SD Group, SD-3C LLC or the SD * Card Association for any damages, any infringements of patents or other * right of the SD Group, SD-3C LLC, the SD Card Association or any third * parties, which may result from its use. No license is granted by * implication, estoppel or otherwise under any patent or other rights of the * SD Group, SD-3C LLC, the SD Card Association or any third party. Nothing * herein shall be construed as an obligation by the SD Group, the SD-3C LLC * or the SD Card Association to disclose or distribute any technical * information, know-how or other confidential information to any third party. */ #include __FBSDID("$FreeBSD$"); #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 "mmcbus_if.h" #if __FreeBSD_version < 800002 #define kproc_create kthread_create #define kproc_exit kthread_exit #endif #define MMCSD_CMD_RETRIES 5 #define MMCSD_FMT_BOOT "mmcsd%dboot" #define MMCSD_FMT_GP "mmcsd%dgp" #define MMCSD_FMT_RPMB "mmcsd%drpmb" #define MMCSD_LABEL_ENH "enh" #define MMCSD_PART_NAMELEN (16 + 1) struct mmcsd_softc; struct mmcsd_part { struct mtx disk_mtx; struct mtx ioctl_mtx; struct mmcsd_softc *sc; struct disk *disk; struct proc *p; struct bio_queue_head bio_queue; daddr_t eblock, eend; /* Range remaining after the last erase. */ u_int cnt; u_int type; int running; int suspend; int ioctl; bool ro; char name[MMCSD_PART_NAMELEN]; }; struct mmcsd_softc { device_t dev; device_t mmcbus; struct mmcsd_part *part[MMC_PART_MAX]; enum mmc_card_mode mode; u_int max_data; /* Maximum data size [blocks] */ u_int erase_sector; /* Device native erase sector size [blocks] */ uint8_t high_cap; /* High Capacity device (block addressed) */ uint8_t part_curr; /* Partition currently switched to */ uint8_t ext_csd[MMC_EXTCSD_SIZE]; uint16_t rca; uint32_t flags; #define MMCSD_INAND_CMD38 0x0001 #define MMCSD_USE_TRIM 0x0002 #define MMCSD_FLUSH_CACHE 0x0004 #define MMCSD_DIRTY 0x0008 uint32_t cmd6_time; /* Generic switch timeout [us] */ uint32_t part_time; /* Partition switch timeout [us] */ off_t enh_base; /* Enhanced user data area slice base ... */ off_t enh_size; /* ... and size [bytes] */ int log_count; struct timeval log_time; struct cdev *rpmb_dev; }; static const char *errmsg[] = { "None", "Timeout", "Bad CRC", "Fifo", "Failed", "Invalid", "NO MEMORY" }; static SYSCTL_NODE(_hw, OID_AUTO, mmcsd, CTLFLAG_RD, NULL, "mmcsd driver"); static int mmcsd_cache = 1; SYSCTL_INT(_hw_mmcsd, OID_AUTO, cache, CTLFLAG_RDTUN, &mmcsd_cache, 0, "Device R/W cache enabled if present"); #define LOG_PPS 5 /* Log no more than 5 errors per second. */ /* bus entry points */ static int mmcsd_attach(device_t dev); static int mmcsd_detach(device_t dev); static int mmcsd_probe(device_t dev); static int mmcsd_shutdown(device_t dev); /* disk routines */ static int mmcsd_close(struct disk *dp); static int mmcsd_dump(void *arg, void *virtual, vm_offset_t physical, off_t offset, size_t length); static int mmcsd_getattr(struct bio *); static int mmcsd_ioctl_disk(struct disk *disk, u_long cmd, void *data, int fflag, struct thread *td); static void mmcsd_strategy(struct bio *bp); static void mmcsd_task(void *arg); /* RMPB cdev interface */ static int mmcsd_ioctl_rpmb(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread *td); static void mmcsd_add_part(struct mmcsd_softc *sc, u_int type, const char *name, u_int cnt, off_t media_size, bool ro); static int mmcsd_bus_bit_width(device_t dev); static daddr_t mmcsd_delete(struct mmcsd_part *part, struct bio *bp); static const char *mmcsd_errmsg(int e); static int mmcsd_flush_cache(struct mmcsd_softc *sc); static int mmcsd_ioctl(struct mmcsd_part *part, u_long cmd, void *data, int fflag, struct thread *td); static int mmcsd_ioctl_cmd(struct mmcsd_part *part, struct mmc_ioc_cmd *mic, int fflag); static uintmax_t mmcsd_pretty_size(off_t size, char *unit); static daddr_t mmcsd_rw(struct mmcsd_part *part, struct bio *bp); static int mmcsd_set_blockcount(struct mmcsd_softc *sc, u_int count, bool rel); static int mmcsd_slicer(device_t dev, const char *provider, struct flash_slice *slices, int *nslices); static int mmcsd_switch_part(device_t bus, device_t dev, uint16_t rca, u_int part); #define MMCSD_DISK_LOCK(_part) mtx_lock(&(_part)->disk_mtx) #define MMCSD_DISK_UNLOCK(_part) mtx_unlock(&(_part)->disk_mtx) #define MMCSD_DISK_LOCK_INIT(_part) \ mtx_init(&(_part)->disk_mtx, (_part)->name, "mmcsd disk", MTX_DEF) #define MMCSD_DISK_LOCK_DESTROY(_part) mtx_destroy(&(_part)->disk_mtx); #define MMCSD_DISK_ASSERT_LOCKED(_part) \ mtx_assert(&(_part)->disk_mtx, MA_OWNED); #define MMCSD_DISK_ASSERT_UNLOCKED(_part) \ mtx_assert(&(_part)->disk_mtx, MA_NOTOWNED); #define MMCSD_IOCTL_LOCK(_part) mtx_lock(&(_part)->ioctl_mtx) #define MMCSD_IOCTL_UNLOCK(_part) mtx_unlock(&(_part)->ioctl_mtx) #define MMCSD_IOCTL_LOCK_INIT(_part) \ mtx_init(&(_part)->ioctl_mtx, (_part)->name, "mmcsd IOCTL", MTX_DEF) #define MMCSD_IOCTL_LOCK_DESTROY(_part) mtx_destroy(&(_part)->ioctl_mtx); #define MMCSD_IOCTL_ASSERT_LOCKED(_part) \ mtx_assert(&(_part)->ioctl_mtx, MA_OWNED); #define MMCSD_IOCLT_ASSERT_UNLOCKED(_part) \ mtx_assert(&(_part)->ioctl_mtx, MA_NOTOWNED); static int mmcsd_probe(device_t dev) { device_quiet(dev); device_set_desc(dev, "MMC/SD Memory Card"); return (0); } static int mmcsd_attach(device_t dev) { device_t mmcbus; struct mmcsd_softc *sc; const uint8_t *ext_csd; off_t erase_size, sector_size, size, wp_size; uintmax_t bytes; int err, i; uint32_t quirks; uint8_t rev; bool comp, ro; char unit[2]; sc = device_get_softc(dev); sc->dev = dev; sc->mmcbus = mmcbus = device_get_parent(dev); sc->mode = mmc_get_card_type(dev); /* * Note that in principle with an SDHCI-like re-tuning implementation, * the maximum data size can change at runtime due to a device removal/ * insertion that results in switches to/from a transfer mode involving * re-tuning, iff there are multiple devices on a given bus. Until now * mmc(4) lacks support for rescanning already attached buses, however, * and sdhci(4) to date has no support for shared buses in the first * place either. */ sc->max_data = mmc_get_max_data(dev); sc->high_cap = mmc_get_high_cap(dev); sc->rca = mmc_get_rca(dev); sc->cmd6_time = mmc_get_cmd6_timeout(dev); quirks = mmc_get_quirks(dev); /* Only MMC >= 4.x devices support EXT_CSD. */ if (mmc_get_spec_vers(dev) >= 4) { MMCBUS_ACQUIRE_BUS(mmcbus, dev); err = mmc_send_ext_csd(mmcbus, dev, sc->ext_csd); MMCBUS_RELEASE_BUS(mmcbus, dev); if (err != MMC_ERR_NONE) { device_printf(dev, "Error reading EXT_CSD %s\n", mmcsd_errmsg(err)); return (ENXIO); } } ext_csd = sc->ext_csd; if ((quirks & MMC_QUIRK_INAND_CMD38) != 0) { if (mmc_get_spec_vers(dev) < 4) { device_printf(dev, "MMC_QUIRK_INAND_CMD38 set but no EXT_CSD\n"); return (EINVAL); } sc->flags |= MMCSD_INAND_CMD38; } /* * EXT_CSD_SEC_FEATURE_SUPPORT_GB_CL_EN denotes support for both * insecure and secure TRIM. */ if ((ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT] & EXT_CSD_SEC_FEATURE_SUPPORT_GB_CL_EN) != 0 && (quirks & MMC_QUIRK_BROKEN_TRIM) == 0) { if (bootverbose) device_printf(dev, "taking advantage of TRIM\n"); sc->flags |= MMCSD_USE_TRIM; sc->erase_sector = 1; } else sc->erase_sector = mmc_get_erase_sector(dev); /* * Enhanced user data area and general purpose partitions are only * supported in revision 1.4 (EXT_CSD_REV == 4) and later, the RPMB * partition in revision 1.5 (MMC v4.41, EXT_CSD_REV == 5) and later. */ rev = ext_csd[EXT_CSD_REV]; /* * With revision 1.5 (MMC v4.5, EXT_CSD_REV == 6) and later, take * advantage of the device R/W cache if present and useage is not * disabled. */ if (rev >= 6 && mmcsd_cache != 0) { size = le32dec(&ext_csd[EXT_CSD_CACHE_SIZE]); if (bootverbose) device_printf(dev, "cache size %juKB\n", size); if (size > 0) { MMCBUS_ACQUIRE_BUS(mmcbus, dev); err = mmc_switch(mmcbus, dev, sc->rca, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_CACHE_CTRL, EXT_CSD_CACHE_CTRL_CACHE_EN, sc->cmd6_time, true); MMCBUS_RELEASE_BUS(mmcbus, dev); if (err != MMC_ERR_NONE) device_printf(dev, "failed to enable cache\n"); else sc->flags |= MMCSD_FLUSH_CACHE; } } /* * Ignore user-creatable enhanced user data area and general purpose * partitions partitions as long as partitioning hasn't been finished. */ comp = (ext_csd[EXT_CSD_PART_SET] & EXT_CSD_PART_SET_COMPLETED) != 0; /* * Add enhanced user data area slice, unless it spans the entirety of * the user data area. The enhanced area is of a multiple of high * capacity write protect groups ((ERASE_GRP_SIZE + HC_WP_GRP_SIZE) * * 512 KB) and its offset given in either sectors or bytes, depending * on whether it's a high capacity device or not. * NB: The slicer and its slices need to be registered before adding * the disk for the corresponding user data area as re-tasting is * racy. */ sector_size = mmc_get_sector_size(dev); size = ext_csd[EXT_CSD_ENH_SIZE_MULT] + (ext_csd[EXT_CSD_ENH_SIZE_MULT + 1] << 8) + (ext_csd[EXT_CSD_ENH_SIZE_MULT + 2] << 16); if (rev >= 4 && comp == TRUE && size > 0 && (ext_csd[EXT_CSD_PART_SUPPORT] & EXT_CSD_PART_SUPPORT_ENH_ATTR_EN) != 0 && (ext_csd[EXT_CSD_PART_ATTR] & (EXT_CSD_PART_ATTR_ENH_USR)) != 0) { erase_size = ext_csd[EXT_CSD_ERASE_GRP_SIZE] * 1024 * MMC_SECTOR_SIZE; wp_size = ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; size *= erase_size * wp_size; if (size != mmc_get_media_size(dev) * sector_size) { sc->enh_size = size; sc->enh_base = le32dec(&ext_csd[EXT_CSD_ENH_START_ADDR]) * (sc->high_cap == 0 ? MMC_SECTOR_SIZE : 1); } else if (bootverbose) device_printf(dev, "enhanced user data area spans entire device\n"); } /* * Add default partition. This may be the only one or the user * data area in case partitions are supported. */ ro = mmc_get_read_only(dev); mmcsd_add_part(sc, EXT_CSD_PART_CONFIG_ACC_DEFAULT, "mmcsd", device_get_unit(dev), mmc_get_media_size(dev) * sector_size, ro); if (mmc_get_spec_vers(dev) < 3) return (0); /* Belatedly announce enhanced user data slice. */ if (sc->enh_size != 0) { bytes = mmcsd_pretty_size(size, unit); printf(FLASH_SLICES_FMT ": %ju%sB enhanced user data area " "slice offset 0x%jx at %s\n", device_get_nameunit(dev), MMCSD_LABEL_ENH, bytes, unit, (uintmax_t)sc->enh_base, device_get_nameunit(dev)); } /* * Determine partition switch timeout (provided in units of 10 ms) * and ensure it's at least 300 ms as some eMMC chips lie. */ sc->part_time = max(ext_csd[EXT_CSD_PART_SWITCH_TO] * 10 * 1000, 300 * 1000); /* Add boot partitions, which are of a fixed multiple of 128 KB. */ size = ext_csd[EXT_CSD_BOOT_SIZE_MULT] * MMC_BOOT_RPMB_BLOCK_SIZE; if (size > 0 && (mmcbr_get_caps(mmcbus) & MMC_CAP_BOOT_NOACC) == 0) { mmcsd_add_part(sc, EXT_CSD_PART_CONFIG_ACC_BOOT0, MMCSD_FMT_BOOT, 0, size, ro | ((ext_csd[EXT_CSD_BOOT_WP_STATUS] & EXT_CSD_BOOT_WP_STATUS_BOOT0_MASK) != 0)); mmcsd_add_part(sc, EXT_CSD_PART_CONFIG_ACC_BOOT1, MMCSD_FMT_BOOT, 1, size, ro | ((ext_csd[EXT_CSD_BOOT_WP_STATUS] & EXT_CSD_BOOT_WP_STATUS_BOOT1_MASK) != 0)); } /* Add RPMB partition, which also is of a fixed multiple of 128 KB. */ size = ext_csd[EXT_CSD_RPMB_MULT] * MMC_BOOT_RPMB_BLOCK_SIZE; if (rev >= 5 && size > 0) mmcsd_add_part(sc, EXT_CSD_PART_CONFIG_ACC_RPMB, MMCSD_FMT_RPMB, 0, size, ro); if (rev <= 3 || comp == FALSE) return (0); /* * Add general purpose partitions, which are of a multiple of high * capacity write protect groups, too. */ if ((ext_csd[EXT_CSD_PART_SUPPORT] & EXT_CSD_PART_SUPPORT_EN) != 0) { erase_size = ext_csd[EXT_CSD_ERASE_GRP_SIZE] * 1024 * MMC_SECTOR_SIZE; wp_size = ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; for (i = 0; i < MMC_PART_GP_MAX; i++) { size = ext_csd[EXT_CSD_GP_SIZE_MULT + i * 3] + (ext_csd[EXT_CSD_GP_SIZE_MULT + i * 3 + 1] << 8) + (ext_csd[EXT_CSD_GP_SIZE_MULT + i * 3 + 2] << 16); if (size == 0) continue; mmcsd_add_part(sc, EXT_CSD_PART_CONFIG_ACC_GP0 + i, MMCSD_FMT_GP, i, size * erase_size * wp_size, ro); } } return (0); } static uintmax_t mmcsd_pretty_size(off_t size, char *unit) { uintmax_t bytes; int i; /* * Display in most natural units. There's no card < 1MB. However, * RPMB partitions occasionally are smaller than that, though. The * SD standard goes to 2 GiB due to its reliance on FAT, but the data * format supports up to 4 GiB and some card makers push it up to this * limit. The SDHC standard only goes to 32 GiB due to FAT32, but the * data format supports up to 2 TiB however. 2048 GB isn't too ugly, * so we note it in passing here and don't add the code to print TB). * Since these cards are sold in terms of MB and GB not MiB and GiB, * report them like that. We also round to the nearest unit, since * many cards are a few percent short, even of the power of 10 size. */ bytes = size; unit[0] = unit[1] = '\0'; for (i = 0; i <= 2 && bytes >= 1000; i++) { bytes = (bytes + 1000 / 2 - 1) / 1000; switch (i) { case 0: unit[0] = 'k'; break; case 1: unit[0] = 'M'; break; case 2: unit[0] = 'G'; break; default: break; } } return (bytes); } static struct cdevsw mmcsd_rpmb_cdevsw = { .d_version = D_VERSION, .d_name = "mmcsdrpmb", .d_ioctl = mmcsd_ioctl_rpmb }; static void mmcsd_add_part(struct mmcsd_softc *sc, u_int type, const char *name, u_int cnt, off_t media_size, bool ro) { struct make_dev_args args; device_t dev, mmcbus; const char *ext; const uint8_t *ext_csd; struct mmcsd_part *part; struct disk *d; uintmax_t bytes; u_int gp; uint32_t speed; uint8_t extattr; bool enh; char unit[2]; dev = sc->dev; mmcbus = sc->mmcbus; part = sc->part[type] = malloc(sizeof(*part), M_DEVBUF, M_WAITOK | M_ZERO); part->sc = sc; part->cnt = cnt; part->type = type; part->ro = ro; snprintf(part->name, sizeof(part->name), name, device_get_unit(dev)); MMCSD_IOCTL_LOCK_INIT(part); /* * For the RPMB partition, allow IOCTL access only. * NB: If ever attaching RPMB partitions to disk(9), the re-tuning * implementation and especially its pausing need to be revisited, * because then re-tuning requests may be issued by the IOCTL half * of this driver while re-tuning is already paused by the disk(9) * one and vice versa. */ if (type == EXT_CSD_PART_CONFIG_ACC_RPMB) { make_dev_args_init(&args); args.mda_flags = MAKEDEV_CHECKNAME | MAKEDEV_WAITOK; args.mda_devsw = &mmcsd_rpmb_cdevsw; args.mda_uid = UID_ROOT; args.mda_gid = GID_OPERATOR; args.mda_mode = 0640; args.mda_si_drv1 = part; if (make_dev_s(&args, &sc->rpmb_dev, "%s", part->name) != 0) { device_printf(dev, "Failed to make RPMB device\n"); free(part, M_DEVBUF); return; } } else { MMCSD_DISK_LOCK_INIT(part); d = part->disk = disk_alloc(); d->d_close = mmcsd_close; d->d_strategy = mmcsd_strategy; d->d_ioctl = mmcsd_ioctl_disk; d->d_dump = mmcsd_dump; d->d_getattr = mmcsd_getattr; d->d_name = part->name; d->d_drv1 = part; d->d_sectorsize = mmc_get_sector_size(dev); d->d_maxsize = sc->max_data * d->d_sectorsize; d->d_mediasize = media_size; d->d_stripesize = sc->erase_sector * d->d_sectorsize; d->d_unit = cnt; d->d_flags = DISKFLAG_CANDELETE; if ((sc->flags & MMCSD_FLUSH_CACHE) != 0) d->d_flags |= DISKFLAG_CANFLUSHCACHE; d->d_delmaxsize = mmc_get_erase_sector(dev) * d->d_sectorsize; strlcpy(d->d_ident, mmc_get_card_sn_string(dev), sizeof(d->d_ident)); strlcpy(d->d_descr, mmc_get_card_id_string(dev), sizeof(d->d_descr)); d->d_rotation_rate = DISK_RR_NON_ROTATING; disk_create(d, DISK_VERSION); bioq_init(&part->bio_queue); part->running = 1; kproc_create(&mmcsd_task, part, &part->p, 0, 0, "%s%d: mmc/sd card", part->name, cnt); } bytes = mmcsd_pretty_size(media_size, unit); if (type == EXT_CSD_PART_CONFIG_ACC_DEFAULT) { speed = mmcbr_get_clock(mmcbus); printf("%s%d: %ju%sB <%s>%s at %s %d.%01dMHz/%dbit/%d-block\n", part->name, cnt, bytes, unit, mmc_get_card_id_string(dev), ro ? " (read-only)" : "", device_get_nameunit(mmcbus), speed / 1000000, (speed / 100000) % 10, mmcsd_bus_bit_width(dev), sc->max_data); } else if (type == EXT_CSD_PART_CONFIG_ACC_RPMB) { printf("%s: %ju%sB partition %d%s at %s\n", part->name, bytes, unit, type, ro ? " (read-only)" : "", device_get_nameunit(dev)); } else { enh = false; ext = NULL; extattr = 0; if (type >= EXT_CSD_PART_CONFIG_ACC_GP0 && type <= EXT_CSD_PART_CONFIG_ACC_GP3) { ext_csd = sc->ext_csd; gp = type - EXT_CSD_PART_CONFIG_ACC_GP0; if ((ext_csd[EXT_CSD_PART_SUPPORT] & EXT_CSD_PART_SUPPORT_ENH_ATTR_EN) != 0 && (ext_csd[EXT_CSD_PART_ATTR] & (EXT_CSD_PART_ATTR_ENH_GP0 << gp)) != 0) enh = true; else if ((ext_csd[EXT_CSD_PART_SUPPORT] & EXT_CSD_PART_SUPPORT_EXT_ATTR_EN) != 0) { extattr = (ext_csd[EXT_CSD_EXT_PART_ATTR + (gp / 2)] >> (4 * (gp % 2))) & 0xF; switch (extattr) { case EXT_CSD_EXT_PART_ATTR_DEFAULT: break; case EXT_CSD_EXT_PART_ATTR_SYSTEMCODE: ext = "system code"; break; case EXT_CSD_EXT_PART_ATTR_NPERSISTENT: ext = "non-persistent"; break; default: ext = "reserved"; break; } } } if (ext == NULL) printf("%s%d: %ju%sB partition %d%s%s at %s\n", part->name, cnt, bytes, unit, type, enh ? " enhanced" : "", ro ? " (read-only)" : "", device_get_nameunit(dev)); else printf("%s%d: %ju%sB partition %d extended 0x%x " "(%s)%s at %s\n", part->name, cnt, bytes, unit, type, extattr, ext, ro ? " (read-only)" : "", device_get_nameunit(dev)); } } static int mmcsd_slicer(device_t dev, const char *provider, struct flash_slice *slices, int *nslices) { char name[MMCSD_PART_NAMELEN]; struct mmcsd_softc *sc; struct mmcsd_part *part; *nslices = 0; if (slices == NULL) return (ENOMEM); sc = device_get_softc(dev); if (sc->enh_size == 0) return (ENXIO); part = sc->part[EXT_CSD_PART_CONFIG_ACC_DEFAULT]; snprintf(name, sizeof(name), "%s%d", part->disk->d_name, part->disk->d_unit); if (strcmp(name, provider) != 0) return (ENXIO); *nslices = 1; slices[0].base = sc->enh_base; slices[0].size = sc->enh_size; slices[0].label = MMCSD_LABEL_ENH; return (0); } static int mmcsd_detach(device_t dev) { struct mmcsd_softc *sc = device_get_softc(dev); struct mmcsd_part *part; int i; for (i = 0; i < MMC_PART_MAX; i++) { part = sc->part[i]; if (part != NULL) { if (part->disk != NULL) { MMCSD_DISK_LOCK(part); part->suspend = 0; if (part->running > 0) { /* kill thread */ part->running = 0; wakeup(part); /* wait for thread to finish. */ while (part->running != -1) msleep(part, &part->disk_mtx, 0, "mmcsd disk detach", 0); } MMCSD_DISK_UNLOCK(part); } MMCSD_IOCTL_LOCK(part); while (part->ioctl > 0) msleep(part, &part->ioctl_mtx, 0, "mmcsd IOCTL detach", 0); part->ioctl = -1; MMCSD_IOCTL_UNLOCK(part); } } if (sc->rpmb_dev != NULL) destroy_dev(sc->rpmb_dev); for (i = 0; i < MMC_PART_MAX; i++) { part = sc->part[i]; if (part != NULL) { if (part->disk != NULL) { /* Flush the request queue. */ bioq_flush(&part->bio_queue, NULL, ENXIO); /* kill disk */ disk_destroy(part->disk); MMCSD_DISK_LOCK_DESTROY(part); } MMCSD_IOCTL_LOCK_DESTROY(part); free(part, M_DEVBUF); } } if (mmcsd_flush_cache(sc) != MMC_ERR_NONE) device_printf(dev, "failed to flush cache\n"); return (0); } static int mmcsd_shutdown(device_t dev) { struct mmcsd_softc *sc = device_get_softc(dev); if (mmcsd_flush_cache(sc) != MMC_ERR_NONE) device_printf(dev, "failed to flush cache\n"); return (0); } static int mmcsd_suspend(device_t dev) { struct mmcsd_softc *sc = device_get_softc(dev); struct mmcsd_part *part; int i; for (i = 0; i < MMC_PART_MAX; i++) { part = sc->part[i]; if (part != NULL) { if (part->disk != NULL) { MMCSD_DISK_LOCK(part); part->suspend = 1; if (part->running > 0) { /* kill thread */ part->running = 0; wakeup(part); /* wait for thread to finish. */ while (part->running != -1) msleep(part, &part->disk_mtx, 0, "mmcsd disk suspension", 0); } MMCSD_DISK_UNLOCK(part); } MMCSD_IOCTL_LOCK(part); while (part->ioctl > 0) msleep(part, &part->ioctl_mtx, 0, "mmcsd IOCTL suspension", 0); part->ioctl = -1; MMCSD_IOCTL_UNLOCK(part); } } if (mmcsd_flush_cache(sc) != MMC_ERR_NONE) device_printf(dev, "failed to flush cache\n"); return (0); } static int mmcsd_resume(device_t dev) { struct mmcsd_softc *sc = device_get_softc(dev); struct mmcsd_part *part; int i; for (i = 0; i < MMC_PART_MAX; i++) { part = sc->part[i]; if (part != NULL) { if (part->disk != NULL) { MMCSD_DISK_LOCK(part); part->suspend = 0; if (part->running <= 0) { part->running = 1; MMCSD_DISK_UNLOCK(part); kproc_create(&mmcsd_task, part, &part->p, 0, 0, "%s%d: mmc/sd card", part->name, part->cnt); } else MMCSD_DISK_UNLOCK(part); } MMCSD_IOCTL_LOCK(part); part->ioctl = 0; MMCSD_IOCTL_UNLOCK(part); } } return (0); } static int mmcsd_close(struct disk *dp) { struct mmcsd_softc *sc; if ((dp->d_flags & DISKFLAG_OPEN) != 0) { sc = ((struct mmcsd_part *)dp->d_drv1)->sc; if (mmcsd_flush_cache(sc) != MMC_ERR_NONE) device_printf(sc->dev, "failed to flush cache\n"); } return (0); } static void mmcsd_strategy(struct bio *bp) { struct mmcsd_part *part; part = bp->bio_disk->d_drv1; MMCSD_DISK_LOCK(part); if (part->running > 0 || part->suspend > 0) { bioq_disksort(&part->bio_queue, bp); MMCSD_DISK_UNLOCK(part); wakeup(part); } else { MMCSD_DISK_UNLOCK(part); biofinish(bp, NULL, ENXIO); } } static int mmcsd_ioctl_rpmb(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread *td) { return (mmcsd_ioctl(dev->si_drv1, cmd, data, fflag, td)); } static int mmcsd_ioctl_disk(struct disk *disk, u_long cmd, void *data, int fflag, struct thread *td) { return (mmcsd_ioctl(disk->d_drv1, cmd, data, fflag, td)); } static int mmcsd_ioctl(struct mmcsd_part *part, u_long cmd, void *data, int fflag, struct thread *td) { struct mmc_ioc_cmd *mic; struct mmc_ioc_multi_cmd *mimc; int i, err; u_long cnt, size; if ((fflag & FREAD) == 0) return (EBADF); err = priv_check(td, PRIV_DRIVER); if (err != 0) return (err); err = 0; switch (cmd) { case MMC_IOC_CMD: mic = data; err = mmcsd_ioctl_cmd(part, mic, fflag); break; case MMC_IOC_MULTI_CMD: mimc = data; if (mimc->num_of_cmds == 0) break; if (mimc->num_of_cmds > MMC_IOC_MAX_CMDS) return (EINVAL); cnt = mimc->num_of_cmds; size = sizeof(*mic) * cnt; mic = malloc(size, M_TEMP, M_WAITOK); err = copyin((const void *)mimc->cmds, mic, size); if (err == 0) { for (i = 0; i < cnt; i++) { err = mmcsd_ioctl_cmd(part, &mic[i], fflag); if (err != 0) break; } } free(mic, M_TEMP); break; default: return (ENOIOCTL); } return (err); } static int mmcsd_ioctl_cmd(struct mmcsd_part *part, struct mmc_ioc_cmd *mic, int fflag) { struct mmc_command cmd; struct mmc_data data; struct mmcsd_softc *sc; device_t dev, mmcbus; void *dp; u_long len; int err, retries; uint32_t status; uint16_t rca; if ((fflag & FWRITE) == 0 && mic->write_flag != 0) return (EBADF); if (part->ro == TRUE && mic->write_flag != 0) return (EROFS); /* * We don't need to explicitly lock against the disk(9) half of this * driver as MMCBUS_ACQUIRE_BUS() will serialize us. However, it's * necessary to protect against races with detachment and suspension, * especially since it's required to switch away from RPMB partitions * again after an access (see mmcsd_switch_part()). */ MMCSD_IOCTL_LOCK(part); while (part->ioctl != 0) { if (part->ioctl < 0) { MMCSD_IOCTL_UNLOCK(part); return (ENXIO); } msleep(part, &part->ioctl_mtx, 0, "mmcsd IOCTL", 0); } part->ioctl = 1; MMCSD_IOCTL_UNLOCK(part); err = 0; dp = NULL; len = mic->blksz * mic->blocks; if (len > MMC_IOC_MAX_BYTES) { err = EOVERFLOW; goto out; } if (len != 0) { dp = malloc(len, M_TEMP, M_WAITOK); err = copyin((void *)(uintptr_t)mic->data_ptr, dp, len); if (err != 0) goto out; } memset(&cmd, 0, sizeof(cmd)); memset(&data, 0, sizeof(data)); cmd.opcode = mic->opcode; cmd.arg = mic->arg; cmd.flags = mic->flags; if (len != 0) { data.len = len; data.data = dp; data.flags = mic->write_flag != 0 ? MMC_DATA_WRITE : MMC_DATA_READ; cmd.data = &data; } sc = part->sc; rca = sc->rca; if (mic->is_acmd == 0) { /* Enforce/patch/restrict RCA-based commands */ switch (cmd.opcode) { case MMC_SET_RELATIVE_ADDR: case MMC_SELECT_CARD: err = EPERM; goto out; case MMC_STOP_TRANSMISSION: if ((cmd.arg & 0x1) == 0) break; /* FALLTHROUGH */ case MMC_SLEEP_AWAKE: case MMC_SEND_CSD: case MMC_SEND_CID: case MMC_SEND_STATUS: case MMC_GO_INACTIVE_STATE: case MMC_FAST_IO: case MMC_APP_CMD: cmd.arg = (cmd.arg & 0x0000FFFF) | (rca << 16); break; default: break; } /* * No partition switching in userland; it's almost impossible * to recover from that, especially if things go wrong. */ if (cmd.opcode == MMC_SWITCH_FUNC && dp != NULL && (((uint8_t *)dp)[EXT_CSD_PART_CONFIG] & EXT_CSD_PART_CONFIG_ACC_MASK) != part->type) { err = EINVAL; goto out; } } dev = sc->dev; mmcbus = sc->mmcbus; MMCBUS_ACQUIRE_BUS(mmcbus, dev); err = mmcsd_switch_part(mmcbus, dev, rca, part->type); if (err != MMC_ERR_NONE) goto release; if (part->type == EXT_CSD_PART_CONFIG_ACC_RPMB) { err = mmcsd_set_blockcount(sc, mic->blocks, mic->write_flag & (1 << 31)); if (err != MMC_ERR_NONE) goto switch_back; } if (mic->write_flag != 0) sc->flags |= MMCSD_DIRTY; if (mic->is_acmd != 0) (void)mmc_wait_for_app_cmd(mmcbus, dev, rca, &cmd, 0); else (void)mmc_wait_for_cmd(mmcbus, dev, &cmd, 0); if (part->type == EXT_CSD_PART_CONFIG_ACC_RPMB) { /* * If the request went to the RPMB partition, try to ensure * that the command actually has completed. */ retries = MMCSD_CMD_RETRIES; do { err = mmc_send_status(mmcbus, dev, rca, &status); if (err != MMC_ERR_NONE) break; if (R1_STATUS(status) == 0 && R1_CURRENT_STATE(status) != R1_STATE_PRG) break; DELAY(1000); } while (retries-- > 0); } /* * If EXT_CSD was changed, our copy is outdated now. Specifically, * the upper bits of EXT_CSD_PART_CONFIG used in mmcsd_switch_part(), * so retrieve EXT_CSD again. */ if (cmd.opcode == MMC_SWITCH_FUNC) { err = mmc_send_ext_csd(mmcbus, dev, sc->ext_csd); if (err != MMC_ERR_NONE) goto release; } switch_back: if (part->type == EXT_CSD_PART_CONFIG_ACC_RPMB) { /* * If the request went to the RPMB partition, always switch * back to the default partition (see mmcsd_switch_part()). */ err = mmcsd_switch_part(mmcbus, dev, rca, EXT_CSD_PART_CONFIG_ACC_DEFAULT); if (err != MMC_ERR_NONE) goto release; } MMCBUS_RELEASE_BUS(mmcbus, dev); if (cmd.error != MMC_ERR_NONE) { switch (cmd.error) { case MMC_ERR_TIMEOUT: err = ETIMEDOUT; break; case MMC_ERR_BADCRC: err = EILSEQ; break; case MMC_ERR_INVALID: err = EINVAL; break; case MMC_ERR_NO_MEMORY: err = ENOMEM; break; default: err = EIO; break; } goto out; } memcpy(mic->response, cmd.resp, 4 * sizeof(uint32_t)); if (mic->write_flag == 0 && len != 0) { err = copyout(dp, (void *)(uintptr_t)mic->data_ptr, len); if (err != 0) goto out; } goto out; release: MMCBUS_RELEASE_BUS(mmcbus, dev); err = EIO; out: MMCSD_IOCTL_LOCK(part); part->ioctl = 0; MMCSD_IOCTL_UNLOCK(part); wakeup(part); if (dp != NULL) free(dp, M_TEMP); return (err); } static int mmcsd_getattr(struct bio *bp) { struct mmcsd_part *part; device_t dev; if (strcmp(bp->bio_attribute, "MMC::device") == 0) { if (bp->bio_length != sizeof(dev)) return (EFAULT); part = bp->bio_disk->d_drv1; dev = part->sc->dev; bcopy(&dev, bp->bio_data, sizeof(dev)); bp->bio_completed = bp->bio_length; return (0); } return (-1); } static int mmcsd_set_blockcount(struct mmcsd_softc *sc, u_int count, bool reliable) { struct mmc_command cmd; struct mmc_request req; memset(&req, 0, sizeof(req)); memset(&cmd, 0, sizeof(cmd)); cmd.mrq = &req; req.cmd = &cmd; cmd.opcode = MMC_SET_BLOCK_COUNT; cmd.arg = count & 0x0000FFFF; if (reliable) cmd.arg |= 1 << 31; cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; MMCBUS_WAIT_FOR_REQUEST(sc->mmcbus, sc->dev, &req); return (cmd.error); } static int mmcsd_switch_part(device_t bus, device_t dev, uint16_t rca, u_int part) { struct mmcsd_softc *sc; int err; uint8_t value; sc = device_get_softc(dev); if (sc->mode == mode_sd) return (MMC_ERR_NONE); /* * According to section "6.2.2 Command restrictions" of the eMMC * specification v5.1, CMD19/CMD21 aren't allowed to be used with * RPMB partitions. So we pause re-tuning along with triggering * it up-front to decrease the likelihood of re-tuning becoming * necessary while accessing an RPMB partition. Consequently, an * RPMB partition should immediately be switched away from again * after an access in order to allow for re-tuning to take place * anew. */ if (part == EXT_CSD_PART_CONFIG_ACC_RPMB) MMCBUS_RETUNE_PAUSE(sc->mmcbus, sc->dev, true); if (sc->part_curr == part) return (MMC_ERR_NONE); value = (sc->ext_csd[EXT_CSD_PART_CONFIG] & ~EXT_CSD_PART_CONFIG_ACC_MASK) | part; /* Jump! */ err = mmc_switch(bus, dev, rca, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONFIG, value, sc->part_time, true); if (err != MMC_ERR_NONE) { if (part == EXT_CSD_PART_CONFIG_ACC_RPMB) MMCBUS_RETUNE_UNPAUSE(sc->mmcbus, sc->dev); return (err); } sc->ext_csd[EXT_CSD_PART_CONFIG] = value; if (sc->part_curr == EXT_CSD_PART_CONFIG_ACC_RPMB) MMCBUS_RETUNE_UNPAUSE(sc->mmcbus, sc->dev); sc->part_curr = part; return (MMC_ERR_NONE); } static const char * mmcsd_errmsg(int e) { if (e < 0 || e > MMC_ERR_MAX) return "Bad error code"; return (errmsg[e]); } static daddr_t mmcsd_rw(struct mmcsd_part *part, struct bio *bp) { daddr_t block, end; struct mmc_command cmd; struct mmc_command stop; struct mmc_request req; struct mmc_data data; struct mmcsd_softc *sc; device_t dev, mmcbus; u_int numblocks, sz; char *vaddr; sc = part->sc; dev = sc->dev; mmcbus = sc->mmcbus; block = bp->bio_pblkno; sz = part->disk->d_sectorsize; end = bp->bio_pblkno + (bp->bio_bcount / sz); while (block < end) { vaddr = bp->bio_data + (block - bp->bio_pblkno) * sz; numblocks = min(end - block, sc->max_data); memset(&req, 0, sizeof(req)); memset(&cmd, 0, sizeof(cmd)); memset(&stop, 0, sizeof(stop)); memset(&data, 0, sizeof(data)); cmd.mrq = &req; req.cmd = &cmd; cmd.data = &data; if (bp->bio_cmd == BIO_READ) { if (numblocks > 1) cmd.opcode = MMC_READ_MULTIPLE_BLOCK; else cmd.opcode = MMC_READ_SINGLE_BLOCK; } else { sc->flags |= MMCSD_DIRTY; if (numblocks > 1) cmd.opcode = MMC_WRITE_MULTIPLE_BLOCK; else cmd.opcode = MMC_WRITE_BLOCK; } cmd.arg = block; if (sc->high_cap == 0) cmd.arg <<= 9; cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; data.data = vaddr; data.mrq = &req; if (bp->bio_cmd == BIO_READ) data.flags = MMC_DATA_READ; else data.flags = MMC_DATA_WRITE; data.len = numblocks * sz; if (numblocks > 1) { data.flags |= MMC_DATA_MULTI; stop.opcode = MMC_STOP_TRANSMISSION; stop.arg = 0; stop.flags = MMC_RSP_R1B | MMC_CMD_AC; stop.mrq = &req; req.stop = &stop; } MMCBUS_WAIT_FOR_REQUEST(mmcbus, dev, &req); if (req.cmd->error != MMC_ERR_NONE) { if (ppsratecheck(&sc->log_time, &sc->log_count, LOG_PPS)) device_printf(dev, "Error indicated: %d %s\n", req.cmd->error, mmcsd_errmsg(req.cmd->error)); break; } block += numblocks; } return (block); } static daddr_t mmcsd_delete(struct mmcsd_part *part, struct bio *bp) { daddr_t block, end, start, stop; struct mmc_command cmd; struct mmc_request req; struct mmcsd_softc *sc; device_t dev, mmcbus; u_int erase_sector, sz; int err; bool use_trim; sc = part->sc; dev = sc->dev; mmcbus = sc->mmcbus; block = bp->bio_pblkno; sz = part->disk->d_sectorsize; end = bp->bio_pblkno + (bp->bio_bcount / sz); use_trim = sc->flags & MMCSD_USE_TRIM; if (use_trim == true) { start = block; stop = end; } else { /* Coalesce with the remainder of the previous request. */ if (block > part->eblock && block <= part->eend) block = part->eblock; if (end >= part->eblock && end < part->eend) end = part->eend; /* Safely round to the erase sector boundaries. */ erase_sector = sc->erase_sector; start = block + erase_sector - 1; /* Round up. */ start -= start % erase_sector; stop = end; /* Round down. */ stop -= end % erase_sector; /* * We can't erase an area smaller than an erase sector, so * store it for later. */ if (start >= stop) { part->eblock = block; part->eend = end; return (end); } } if ((sc->flags & MMCSD_INAND_CMD38) != 0) { err = mmc_switch(mmcbus, dev, sc->rca, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_INAND_CMD38, use_trim == true ? EXT_CSD_INAND_CMD38_TRIM : EXT_CSD_INAND_CMD38_ERASE, sc->cmd6_time, true); if (err != MMC_ERR_NONE) { device_printf(dev, "Setting iNAND erase command failed %s\n", mmcsd_errmsg(err)); return (block); } } /* * Pause re-tuning so it won't interfere with the order of erase * commands. Note that these latter don't use the data lines, so * re-tuning shouldn't actually become necessary during erase. */ MMCBUS_RETUNE_PAUSE(mmcbus, dev, false); /* Set erase start position. */ memset(&req, 0, sizeof(req)); memset(&cmd, 0, sizeof(cmd)); cmd.mrq = &req; req.cmd = &cmd; if (sc->mode == mode_sd) cmd.opcode = SD_ERASE_WR_BLK_START; else cmd.opcode = MMC_ERASE_GROUP_START; cmd.arg = start; if (sc->high_cap == 0) cmd.arg <<= 9; cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; MMCBUS_WAIT_FOR_REQUEST(mmcbus, dev, &req); if (req.cmd->error != MMC_ERR_NONE) { device_printf(dev, "Setting erase start position failed %s\n", mmcsd_errmsg(req.cmd->error)); block = bp->bio_pblkno; goto unpause; } /* Set erase stop position. */ memset(&req, 0, sizeof(req)); memset(&cmd, 0, sizeof(cmd)); req.cmd = &cmd; if (sc->mode == mode_sd) cmd.opcode = SD_ERASE_WR_BLK_END; else cmd.opcode = MMC_ERASE_GROUP_END; cmd.arg = stop; if (sc->high_cap == 0) cmd.arg <<= 9; cmd.arg--; cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; MMCBUS_WAIT_FOR_REQUEST(mmcbus, dev, &req); if (req.cmd->error != MMC_ERR_NONE) { device_printf(dev, "Setting erase stop position failed %s\n", mmcsd_errmsg(req.cmd->error)); block = bp->bio_pblkno; goto unpause; } /* Erase range. */ memset(&req, 0, sizeof(req)); memset(&cmd, 0, sizeof(cmd)); req.cmd = &cmd; cmd.opcode = MMC_ERASE; cmd.arg = use_trim == true ? MMC_ERASE_TRIM : MMC_ERASE_ERASE; cmd.flags = MMC_RSP_R1B | MMC_CMD_AC; MMCBUS_WAIT_FOR_REQUEST(mmcbus, dev, &req); if (req.cmd->error != MMC_ERR_NONE) { device_printf(dev, "Issuing erase command failed %s\n", mmcsd_errmsg(req.cmd->error)); block = bp->bio_pblkno; goto unpause; } if (use_trim == false) { /* Store one of the remaining parts for the next call. */ if (bp->bio_pblkno >= part->eblock || block == start) { part->eblock = stop; /* Predict next forward. */ part->eend = end; } else { part->eblock = block; /* Predict next backward. */ part->eend = start; } } block = end; unpause: MMCBUS_RETUNE_UNPAUSE(mmcbus, dev); return (block); } static int mmcsd_dump(void *arg, void *virtual, vm_offset_t physical, off_t offset, size_t length) { struct bio bp; daddr_t block, end; struct disk *disk; struct mmcsd_softc *sc; struct mmcsd_part *part; device_t dev, mmcbus; int err; disk = arg; part = disk->d_drv1; sc = part->sc; /* length zero is special and really means flush buffers to media */ if (length == 0) { err = mmcsd_flush_cache(sc); if (err != MMC_ERR_NONE) return (EIO); return (0); } dev = sc->dev; mmcbus = sc->mmcbus; g_reset_bio(&bp); bp.bio_disk = disk; bp.bio_pblkno = offset / disk->d_sectorsize; bp.bio_bcount = length; bp.bio_data = virtual; bp.bio_cmd = BIO_WRITE; end = bp.bio_pblkno + bp.bio_bcount / disk->d_sectorsize; MMCBUS_ACQUIRE_BUS(mmcbus, dev); err = mmcsd_switch_part(mmcbus, dev, sc->rca, part->type); if (err != MMC_ERR_NONE) { if (ppsratecheck(&sc->log_time, &sc->log_count, LOG_PPS)) device_printf(dev, "Partition switch error\n"); MMCBUS_RELEASE_BUS(mmcbus, dev); return (EIO); } block = mmcsd_rw(part, &bp); MMCBUS_RELEASE_BUS(mmcbus, dev); return ((end < block) ? EIO : 0); } static void mmcsd_task(void *arg) { daddr_t block, end; struct mmcsd_part *part; struct mmcsd_softc *sc; struct bio *bp; device_t dev, mmcbus; int err, sz; part = arg; sc = part->sc; dev = sc->dev; mmcbus = sc->mmcbus; while (1) { MMCSD_DISK_LOCK(part); do { if (part->running == 0) goto out; bp = bioq_takefirst(&part->bio_queue); if (bp == NULL) msleep(part, &part->disk_mtx, PRIBIO, "mmcsd disk jobqueue", 0); } while (bp == NULL); MMCSD_DISK_UNLOCK(part); if (__predict_false(bp->bio_cmd == BIO_FLUSH)) { if (mmcsd_flush_cache(sc) != MMC_ERR_NONE) { bp->bio_error = EIO; bp->bio_flags |= BIO_ERROR; } biodone(bp); continue; } if (bp->bio_cmd != BIO_READ && part->ro) { bp->bio_error = EROFS; bp->bio_resid = bp->bio_bcount; bp->bio_flags |= BIO_ERROR; biodone(bp); continue; } MMCBUS_ACQUIRE_BUS(mmcbus, dev); sz = part->disk->d_sectorsize; block = bp->bio_pblkno; end = bp->bio_pblkno + (bp->bio_bcount / sz); err = mmcsd_switch_part(mmcbus, dev, sc->rca, part->type); if (err != MMC_ERR_NONE) { if (ppsratecheck(&sc->log_time, &sc->log_count, LOG_PPS)) device_printf(dev, "Partition switch error\n"); goto release; } if (bp->bio_cmd == BIO_READ || bp->bio_cmd == BIO_WRITE) { /* Access to the remaining erase block obsoletes it. */ if (block < part->eend && end > part->eblock) part->eblock = part->eend = 0; block = mmcsd_rw(part, bp); } else if (bp->bio_cmd == BIO_DELETE) { block = mmcsd_delete(part, bp); } release: MMCBUS_RELEASE_BUS(mmcbus, dev); if (block < end) { bp->bio_error = EIO; bp->bio_resid = (end - block) * sz; bp->bio_flags |= BIO_ERROR; } else { bp->bio_resid = 0; } biodone(bp); } out: /* tell parent we're done */ part->running = -1; MMCSD_DISK_UNLOCK(part); wakeup(part); kproc_exit(0); } static int mmcsd_bus_bit_width(device_t dev) { if (mmc_get_bus_width(dev) == bus_width_1) return (1); if (mmc_get_bus_width(dev) == bus_width_4) return (4); return (8); } static int mmcsd_flush_cache(struct mmcsd_softc *sc) { device_t dev, mmcbus; int err; if ((sc->flags & MMCSD_FLUSH_CACHE) == 0) return (MMC_ERR_NONE); dev = sc->dev; mmcbus = sc->mmcbus; MMCBUS_ACQUIRE_BUS(mmcbus, dev); if ((sc->flags & MMCSD_DIRTY) == 0) { MMCBUS_RELEASE_BUS(mmcbus, dev); return (MMC_ERR_NONE); } err = mmc_switch(mmcbus, dev, sc->rca, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_FLUSH_CACHE, EXT_CSD_FLUSH_CACHE_FLUSH, 60 * 1000, true); if (err == MMC_ERR_NONE) sc->flags &= ~MMCSD_DIRTY; MMCBUS_RELEASE_BUS(mmcbus, dev); return (err); } static device_method_t mmcsd_methods[] = { DEVMETHOD(device_probe, mmcsd_probe), DEVMETHOD(device_attach, mmcsd_attach), DEVMETHOD(device_detach, mmcsd_detach), DEVMETHOD(device_shutdown, mmcsd_shutdown), DEVMETHOD(device_suspend, mmcsd_suspend), DEVMETHOD(device_resume, mmcsd_resume), DEVMETHOD_END }; static driver_t mmcsd_driver = { "mmcsd", mmcsd_methods, sizeof(struct mmcsd_softc), }; static devclass_t mmcsd_devclass; static int mmcsd_handler(module_t mod __unused, int what, void *arg __unused) { switch (what) { case MOD_LOAD: flash_register_slicer(mmcsd_slicer, FLASH_SLICES_TYPE_MMC, TRUE); return (0); case MOD_UNLOAD: flash_register_slicer(NULL, FLASH_SLICES_TYPE_MMC, TRUE); return (0); } return (0); } DRIVER_MODULE(mmcsd, mmc, mmcsd_driver, mmcsd_devclass, mmcsd_handler, NULL); MODULE_DEPEND(mmcsd, g_flashmap, 0, 0, 0); MMC_DEPEND(mmcsd); Index: head/sys/dev/mmc/mmcvar.h =================================================================== --- head/sys/dev/mmc/mmcvar.h (revision 355393) +++ head/sys/dev/mmc/mmcvar.h (revision 355394) @@ -1,102 +1,102 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2006 Bernd Walter. All rights reserved. - * Copyright (c) 2006 M. Warner Losh. + * Copyright (c) 2006 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Portions of this software may have been developed with reference to * the SD Simplified Specification. The following disclaimer may apply: * * The following conditions apply to the release of the simplified * specification ("Simplified Specification") by the SD Card Association and * the SD Group. The Simplified Specification is a subset of the complete SD * Specification which is owned by the SD Card Association and the SD * Group. This Simplified Specification is provided on a non-confidential * basis subject to the disclaimers below. Any implementation of the * Simplified Specification may require a license from the SD Card * Association, SD Group, SD-3C LLC or other third parties. * * Disclaimers: * * The information contained in the Simplified Specification is presented only * as a standard specification for SD Cards and SD Host/Ancillary products and * is provided "AS-IS" without any representations or warranties of any * kind. No responsibility is assumed by the SD Group, SD-3C LLC or the SD * Card Association for any damages, any infringements of patents or other * right of the SD Group, SD-3C LLC, the SD Card Association or any third * parties, which may result from its use. No license is granted by * implication, estoppel or otherwise under any patent or other rights of the * SD Group, SD-3C LLC, the SD Card Association or any third party. Nothing * herein shall be construed as an obligation by the SD Group, the SD-3C LLC * or the SD Card Association to disclose or distribute any technical * information, know-how or other confidential information to any third party. * * $FreeBSD$ */ #ifndef DEV_MMC_MMCVAR_H #define DEV_MMC_MMCVAR_H enum mmc_device_ivars { MMC_IVAR_SPEC_VERS, MMC_IVAR_DSR_IMP, MMC_IVAR_MEDIA_SIZE, MMC_IVAR_RCA, MMC_IVAR_SECTOR_SIZE, MMC_IVAR_TRAN_SPEED, MMC_IVAR_READ_ONLY, MMC_IVAR_HIGH_CAP, MMC_IVAR_CARD_TYPE, MMC_IVAR_BUS_WIDTH, MMC_IVAR_ERASE_SECTOR, MMC_IVAR_MAX_DATA, MMC_IVAR_CMD6_TIMEOUT, MMC_IVAR_QUIRKS, MMC_IVAR_CARD_ID_STRING, MMC_IVAR_CARD_SN_STRING, }; /* * Simplified accessors for mmc devices */ #define MMC_ACCESSOR(var, ivar, type) \ __BUS_ACCESSOR(mmc, var, MMC, ivar, type) MMC_ACCESSOR(spec_vers, SPEC_VERS, uint8_t) MMC_ACCESSOR(dsr_imp, DSR_IMP, int) MMC_ACCESSOR(media_size, MEDIA_SIZE, long) MMC_ACCESSOR(rca, RCA, int) MMC_ACCESSOR(sector_size, SECTOR_SIZE, int) MMC_ACCESSOR(tran_speed, TRAN_SPEED, int) MMC_ACCESSOR(read_only, READ_ONLY, int) MMC_ACCESSOR(high_cap, HIGH_CAP, int) MMC_ACCESSOR(card_type, CARD_TYPE, int) MMC_ACCESSOR(bus_width, BUS_WIDTH, int) MMC_ACCESSOR(erase_sector, ERASE_SECTOR, int) MMC_ACCESSOR(max_data, MAX_DATA, int) MMC_ACCESSOR(cmd6_timeout, CMD6_TIMEOUT, u_int) MMC_ACCESSOR(quirks, QUIRKS, u_int) MMC_ACCESSOR(card_id_string, CARD_ID_STRING, const char *) MMC_ACCESSOR(card_sn_string, CARD_SN_STRING, const char *) #endif /* DEV_MMC_MMCVAR_H */ Index: head/sys/dev/ow/ow.c =================================================================== --- head/sys/dev/ow/ow.c (revision 355393) +++ head/sys/dev/ow/ow.c (revision 355394) @@ -1,746 +1,745 @@ /*- - * Copyright (c) 2015 M. Warner Losh - * All rights reserved. + * Copyright (c) 2015 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice unmodified, this list of conditions, and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * lldev - link level device * ndev - network / transport device (this module) * pdev - presentation device (children of this module) */ typedef int ow_enum_fn(device_t, device_t); typedef int ow_found_fn(device_t, romid_t); struct ow_softc { device_t dev; /* Newbus driver back pointer */ struct mtx mtx; /* bus mutex */ device_t owner; /* bus owner, if != NULL */ }; struct ow_devinfo { romid_t romid; }; static int ow_acquire_bus(device_t ndev, device_t pdev, int how); static void ow_release_bus(device_t ndev, device_t pdev); #define OW_LOCK(_sc) mtx_lock(&(_sc)->mtx) #define OW_UNLOCK(_sc) mtx_unlock(&(_sc)->mtx) #define OW_LOCK_DESTROY(_sc) mtx_destroy(&_sc->mtx) #define OW_ASSERT_LOCKED(_sc) mtx_assert(&_sc->mtx, MA_OWNED) #define OW_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->mtx, MA_NOTOWNED) static MALLOC_DEFINE(M_OW, "ow", "House keeping data for 1wire bus"); static const struct ow_timing timing_regular_min = { .t_slot = 60, .t_low0 = 60, .t_low1 = 1, .t_release = 0, .t_rec = 1, .t_rdv = 15, /* fixed */ .t_rstl = 480, .t_rsth = 480, .t_pdl = 60, .t_pdh = 15, .t_lowr = 1, }; static const struct ow_timing timing_regular_max = { .t_slot = 120, .t_low0 = 120, .t_low1 = 15, .t_release = 45, .t_rec = 960, /* infinity */ .t_rdv = 15, /* fixed */ .t_rstl = 960, /* infinity */ .t_rsth = 960, /* infinity */ .t_pdl = 240, /* 60us to 240us */ .t_pdh = 60, /* 15us to 60us */ .t_lowr = 15, /* 1us */ }; static struct ow_timing timing_regular = { .t_slot = 60, /* 60 <= t < 120 */ .t_low0 = 60, /* 60 <= t < t_slot < 120 */ .t_low1 = 1, /* 1 <= t < 15 */ .t_release = 45, /* 0 <= t < 45 */ .t_rec = 15, /* 1 <= t < inf */ .t_rdv = 15, /* t == 15 */ .t_rstl = 480, /* 480 <= t < inf */ .t_rsth = 480, /* 480 <= t < inf */ .t_pdl = 60, /* 60 <= t < 240 */ .t_pdh = 60, /* 15 <= t < 60 */ .t_lowr = 1, /* 1 <= t < 15 */ }; /* NB: Untested */ static const struct ow_timing timing_overdrive_min = { .t_slot = 6, .t_low0 = 6, .t_low1 = 1, .t_release = 0, .t_rec = 1, .t_rdv = 2, /* fixed */ .t_rstl = 48, .t_rsth = 48, .t_pdl = 8, .t_pdh = 2, .t_lowr = 1, }; static const struct ow_timing timing_overdrive_max = { .t_slot = 16, .t_low0 = 16, .t_low1 = 2, .t_release = 4, .t_rec = 960, /* infinity */ .t_rdv = 2, /* fixed */ .t_rstl = 80, .t_rsth = 960, /* infinity */ .t_pdl = 24, .t_pdh = 6, .t_lowr = 2, }; static struct ow_timing timing_overdrive = { .t_slot = 11, /* 6 <= t < 16 */ .t_low0 = 6, /* 6 <= t < t_slot < 16 */ .t_low1 = 1, /* 1 <= t < 2 */ .t_release = 4, /* 0 <= t < 4 */ .t_rec = 1, /* 1 <= t < inf */ .t_rdv = 2, /* t == 2 */ .t_rstl = 48, /* 48 <= t < 80 */ .t_rsth = 48, /* 48 <= t < inf */ .t_pdl = 8, /* 8 <= t < 24 */ .t_pdh = 2, /* 2 <= t < 6 */ .t_lowr = 1, /* 1 <= t < 2 */ }; SYSCTL_NODE(_hw, OID_AUTO, ow, CTLFLAG_RD, 0, "1-Wire protocol"); SYSCTL_NODE(_hw_ow, OID_AUTO, regular, CTLFLAG_RD, 0, "Regular mode timings"); SYSCTL_NODE(_hw_ow, OID_AUTO, overdrive, CTLFLAG_RD, 0, "Overdrive mode timings"); #define _OW_TIMING_SYSCTL(mode, param) \ static int \ sysctl_ow_timing_ ## mode ## _ ## param(SYSCTL_HANDLER_ARGS) \ { \ int val = timing_ ## mode.param; \ int err; \ err = sysctl_handle_int(oidp, &val, 0, req); \ if (err != 0 || req->newptr == NULL) \ return (err); \ if (val < timing_ ## mode ## _min.param) \ return (EINVAL); \ else if (val >= timing_ ## mode ## _max.param) \ return (EINVAL); \ timing_ ## mode.param = val; \ return (0); \ } \ SYSCTL_PROC(_hw_ow_ ## mode, OID_AUTO, param, \ CTLTYPE_INT | CTLFLAG_RWTUN, 0, sizeof(int), \ sysctl_ow_timing_ ## mode ## _ ## param, "I", \ "1-Wire timing parameter in microseconds (-1 resets to default)") #define OW_TIMING_SYSCTL(param) \ _OW_TIMING_SYSCTL(regular, param); \ _OW_TIMING_SYSCTL(overdrive, param) OW_TIMING_SYSCTL(t_slot); OW_TIMING_SYSCTL(t_low0); OW_TIMING_SYSCTL(t_low1); OW_TIMING_SYSCTL(t_release); OW_TIMING_SYSCTL(t_rec); OW_TIMING_SYSCTL(t_rdv); OW_TIMING_SYSCTL(t_rstl); OW_TIMING_SYSCTL(t_rsth); OW_TIMING_SYSCTL(t_pdl); OW_TIMING_SYSCTL(t_pdh); OW_TIMING_SYSCTL(t_lowr); #undef _OW_TIMING_SYSCTL #undef OW_TIMING_SYSCTL static void ow_send_byte(device_t lldev, struct ow_timing *t, uint8_t byte) { int i; for (i = 0; i < 8; i++) if (byte & (1 << i)) OWLL_WRITE_ONE(lldev, t); else OWLL_WRITE_ZERO(lldev, t); } static void ow_read_byte(device_t lldev, struct ow_timing *t, uint8_t *bytep) { int i; uint8_t byte = 0; int bit; for (i = 0; i < 8; i++) { OWLL_READ_DATA(lldev, t, &bit); byte |= bit << i; } *bytep = byte; } static int ow_send_command(device_t ndev, device_t pdev, struct ow_cmd *cmd) { int present, i, bit, tries; device_t lldev; struct ow_timing *t; lldev = device_get_parent(ndev); /* * Retry the reset a couple of times before giving up. */ tries = 4; do { OWLL_RESET_AND_PRESENCE(lldev, &timing_regular, &present); if (present == 1) device_printf(ndev, "Reset said no device on bus?.\n"); } while (present == 1 && tries-- > 0); if (present == 1) { device_printf(ndev, "Reset said the device wasn't there.\n"); return ENOENT; /* No devices acked the RESET */ } if (present == -1) { device_printf(ndev, "Reset discovered bus wired wrong.\n"); return ENOENT; } for (i = 0; i < cmd->rom_len; i++) ow_send_byte(lldev, &timing_regular, cmd->rom_cmd[i]); for (i = 0; i < cmd->rom_read_len; i++) ow_read_byte(lldev, &timing_regular, cmd->rom_read + i); if (cmd->xpt_len) { /* * Per AN937, the reset pulse and ROM level are always * done with the regular timings. Certain ROM commands * put the device into overdrive mode for the remainder * of the data transfer, which is why we have to pass the * timings here. Commands that need to be handled like this * are expected to be flagged by the client. */ t = (cmd->flags & OW_FLAG_OVERDRIVE) ? &timing_overdrive : &timing_regular; for (i = 0; i < cmd->xpt_len; i++) ow_send_byte(lldev, t, cmd->xpt_cmd[i]); if (cmd->flags & OW_FLAG_READ_BIT) { memset(cmd->xpt_read, 0, (cmd->xpt_read_len + 7) / 8); for (i = 0; i < cmd->xpt_read_len; i++) { OWLL_READ_DATA(lldev, t, &bit); cmd->xpt_read[i / 8] |= bit << (i % 8); } } else { for (i = 0; i < cmd->xpt_read_len; i++) ow_read_byte(lldev, t, cmd->xpt_read + i); } } return 0; } static int ow_search_rom(device_t lldev, device_t dev) { struct ow_cmd cmd; memset(&cmd, 0, sizeof(cmd)); cmd.rom_cmd[0] = SEARCH_ROM; cmd.rom_len = 1; return ow_send_command(lldev, dev, &cmd); } #if 0 static int ow_alarm_search(device_t lldev, device_t dev) { struct ow_cmd cmd; memset(&cmd, 0, sizeof(cmd)); cmd.rom_cmd[0] = ALARM_SEARCH; cmd.rom_len = 1; return ow_send_command(lldev, dev, &cmd); } #endif static int ow_add_child(device_t dev, romid_t romid) { struct ow_devinfo *di; device_t child; di = malloc(sizeof(*di), M_OW, M_WAITOK); di->romid = romid; child = device_add_child(dev, NULL, -1); if (child == NULL) { free(di, M_OW); return ENOMEM; } device_set_ivars(child, di); return (0); } static device_t ow_child_by_romid(device_t dev, romid_t romid) { device_t *children, retval, child; int nkid, i; struct ow_devinfo *di; if (device_get_children(dev, &children, &nkid) != 0) return (NULL); retval = NULL; for (i = 0; i < nkid; i++) { child = children[i]; di = device_get_ivars(child); if (di->romid == romid) { retval = child; break; } } free(children, M_TEMP); return (retval); } /* * CRC generator table -- taken from AN937 DOW CRC LOOKUP FUNCTION Table 2 */ const uint8_t ow_crc_table[] = { 0, 94, 188, 226, 97, 63, 221, 131, 194, 156, 126, 32, 163, 253, 31, 65, 157, 195, 33, 127, 252, 162, 64, 30, 95, 1, 227, 189, 62, 96, 130, 220, 35, 125, 159, 193, 66, 28, 254, 160, 225, 191, 93, 3, 128, 222, 60, 98, 190, 224, 2, 92, 223, 129, 99, 61, 124, 34, 192, 158, 29, 67, 161, 255, 70, 24, 250, 164, 39, 121, 155, 197, 132, 218, 56, 102, 229, 187, 89, 7, 219, 133,103, 57, 186, 228, 6, 88, 25, 71, 165, 251, 120, 38, 196, 154, 101, 59, 217, 135, 4, 90, 184, 230, 167, 249, 27, 69, 198, 152, 122, 36, 248, 166, 68, 26, 153, 199, 37, 123, 58, 100, 134, 216, 91, 5, 231, 185, 140,210, 48, 110, 237, 179, 81, 15, 78, 16, 242, 172, 47, 113,147, 205, 17, 79, 173, 243, 112, 46, 204, 146, 211,141, 111, 49, 178, 236, 14, 80, 175, 241, 19, 77, 206, 144, 114, 44, 109, 51, 209, 143, 12, 82,176, 238, 50, 108, 142, 208, 83, 13, 239, 177, 240, 174, 76, 18, 145, 207, 45, 115, 202, 148, 118, 40, 171, 245, 23, 73, 8, 86, 180, 234, 105, 55, 213, 139, 87, 9, 235, 181, 54, 104, 138, 212, 149, 203, 41, 119, 244, 170, 72, 22, 233, 183, 85, 11, 136, 214, 52, 106, 43, 117, 151, 201, 74, 20, 246, 168, 116, 42, 200, 150, 21, 75, 169, 247, 182, 232, 10, 84, 215, 137, 107, 53 }; /* * Converted from DO_CRC page 131 ANN937 */ static uint8_t ow_crc(device_t ndev, device_t pdev, uint8_t *buffer, size_t len) { uint8_t crc = 0; int i; for (i = 0; i < len; i++) crc = ow_crc_table[crc ^ buffer[i]]; return crc; } static int ow_check_crc(romid_t romid) { return ow_crc(NULL, NULL, (uint8_t *)&romid, sizeof(romid)) == 0; } static int ow_device_found(device_t dev, romid_t romid) { /* XXX Move this up into enumerate? */ /* * All valid ROM IDs have a valid CRC. Check that first. */ if (!ow_check_crc(romid)) { device_printf(dev, "Device romid %8D failed CRC.\n", &romid, ":"); return EINVAL; } /* * If we've seen this child before, don't add a new one for it. */ if (ow_child_by_romid(dev, romid) != NULL) return 0; return ow_add_child(dev, romid); } static int ow_enumerate(device_t dev, ow_enum_fn *enumfp, ow_found_fn *foundfp) { device_t lldev = device_get_parent(dev); int first, second, i, dir, prior, last, err, retries; uint64_t probed, last_mask; int sanity = 10; prior = -1; last_mask = 0; retries = 0; last = -2; err = ow_acquire_bus(dev, dev, OWN_DONTWAIT); if (err != 0) return err; while (last != -1) { if (sanity-- < 0) { printf("Reached the sanity limit\n"); return EIO; } again: probed = 0; last = -1; /* * See AN397 section 5.II.C.3 for the algorithm (though a bit * poorly stated). The search command forces each device to * send ROM ID bits one at a time (first the bit, then the * complement) the master (us) sends back a bit. If the * device's bit doesn't match what we send back, that device * stops sending bits back. So each time through we remember * where we made the last decision (always 0). If there's a * conflict there this time (and there will be in the absence * of a hardware failure) we go with 1. This way, we prune the * devices on the bus and wind up with a unique ROM. We know * we're done when we detect no new conflicts. The same * algorithm is used for devices in alarm state as well. * * In addition, experience has shown that sometimes devices * stop responding in the middle of enumeration, so try this * step again a few times when that happens. It is unclear if * this is due to a nosiy electrical environment or some odd * timing issue. */ /* * The enumeration command should be successfully sent, if not, * we have big issues on the bus so punt. Lower layers report * any unusual errors, so we don't need to here. */ err = enumfp(dev, dev); if (err != 0) return (err); for (i = 0; i < 64; i++) { OWLL_READ_DATA(lldev, &timing_regular, &first); OWLL_READ_DATA(lldev, &timing_regular, &second); switch (first | second << 1) { case 0: /* Conflict */ if (i < prior) dir = (last_mask >> i) & 1; else dir = i == prior; if (dir == 0) last = i; break; case 1: /* 1 then 0 -> 1 for all */ dir = 1; break; case 2: /* 0 then 1 -> 0 for all */ dir = 0; break; case 3: /* * No device responded. This is unexpected, but * experience has shown that on some platforms * we miss a timing window, or otherwise have * an issue. Start this step over. Since we've * not updated prior yet, we can just jump to * the top of the loop for a re-do of this step. */ printf("oops, starting over\n"); if (++retries > 5) return (EIO); goto again; default: /* NOTREACHED */ __unreachable(); } if (dir) { OWLL_WRITE_ONE(lldev, &timing_regular); probed |= 1ull << i; } else { OWLL_WRITE_ZERO(lldev, &timing_regular); } } retries = 0; foundfp(dev, probed); last_mask = probed; prior = last; } ow_release_bus(dev, dev); return (0); } static int ow_probe(device_t dev) { device_set_desc(dev, "1 Wire Bus"); return (BUS_PROBE_GENERIC); } static int ow_attach(device_t ndev) { struct ow_softc *sc; /* * Find all the devices on the bus. We don't probe / attach them in the * enumeration phase. We do this because we want to allow the probe / * attach routines of the child drivers to have as full an access to the * bus as possible. While we reset things before the next step of the * search (so it would likely be OK to allow access by the clients to * the bus), it is more conservative to find them all, then to do the * attach of the devices. This also allows the child devices to have * more knowledge of the bus. We also ignore errors from the enumeration * because they might happen after we've found a few devices. */ sc = device_get_softc(ndev); sc->dev = ndev; mtx_init(&sc->mtx, device_get_nameunit(sc->dev), "ow", MTX_DEF); ow_enumerate(ndev, ow_search_rom, ow_device_found); return bus_generic_attach(ndev); } static int ow_detach(device_t ndev) { device_t *children, child; int nkid, i; struct ow_devinfo *di; struct ow_softc *sc; sc = device_get_softc(ndev); /* * detach all the children first. This is blocking until any threads * have stopped, etc. */ bus_generic_detach(ndev); /* * We delete all the children, and free up the ivars */ if (device_get_children(ndev, &children, &nkid) != 0) return ENOMEM; for (i = 0; i < nkid; i++) { child = children[i]; di = device_get_ivars(child); free(di, M_OW); device_delete_child(ndev, child); } free(children, M_TEMP); OW_LOCK_DESTROY(sc); return 0; } /* * Not sure this is really needed. I'm having trouble figuring out what * location means in the context of the one wire bus. */ static int ow_child_location_str(device_t dev, device_t child, char *buf, size_t buflen) { *buf = '\0'; return (0); } static int ow_child_pnpinfo_str(device_t dev, device_t child, char *buf, size_t buflen) { struct ow_devinfo *di; di = device_get_ivars(child); snprintf(buf, buflen, "romid=%8D", &di->romid, ":"); return (0); } static int ow_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) { struct ow_devinfo *di; romid_t **ptr; di = device_get_ivars(child); switch (which) { case OW_IVAR_FAMILY: *result = di->romid & 0xff; break; case OW_IVAR_ROMID: ptr = (romid_t **)result; *ptr = &di->romid; break; default: return EINVAL; } return 0; } static int ow_write_ivar(device_t dev, device_t child, int which, uintptr_t value) { return EINVAL; } static int ow_print_child(device_t ndev, device_t pdev) { int retval = 0; struct ow_devinfo *di; di = device_get_ivars(pdev); retval += bus_print_child_header(ndev, pdev); retval += printf(" romid %8D", &di->romid, ":"); retval += bus_print_child_footer(ndev, pdev); return retval; } static void ow_probe_nomatch(device_t ndev, device_t pdev) { struct ow_devinfo *di; di = device_get_ivars(pdev); device_printf(ndev, "romid %8D: no driver\n", &di->romid, ":"); } static int ow_acquire_bus(device_t ndev, device_t pdev, int how) { struct ow_softc *sc; sc = device_get_softc(ndev); OW_ASSERT_UNLOCKED(sc); OW_LOCK(sc); if (sc->owner != NULL) { if (sc->owner == pdev) panic("%s: %s recursively acquiring the bus.\n", device_get_nameunit(ndev), device_get_nameunit(pdev)); if (how == OWN_DONTWAIT) { OW_UNLOCK(sc); return EWOULDBLOCK; } while (sc->owner != NULL) mtx_sleep(sc, &sc->mtx, 0, "owbuswait", 0); } sc->owner = pdev; OW_UNLOCK(sc); return 0; } static void ow_release_bus(device_t ndev, device_t pdev) { struct ow_softc *sc; sc = device_get_softc(ndev); OW_ASSERT_UNLOCKED(sc); OW_LOCK(sc); if (sc->owner == NULL) panic("%s: %s releasing unowned bus.", device_get_nameunit(ndev), device_get_nameunit(pdev)); if (sc->owner != pdev) panic("%s: %s don't own the bus. %s does. game over.", device_get_nameunit(ndev), device_get_nameunit(pdev), device_get_nameunit(sc->owner)); sc->owner = NULL; wakeup(sc); OW_UNLOCK(sc); } devclass_t ow_devclass; static device_method_t ow_methods[] = { /* Device interface */ DEVMETHOD(device_probe, ow_probe), DEVMETHOD(device_attach, ow_attach), DEVMETHOD(device_detach, ow_detach), /* Bus interface */ DEVMETHOD(bus_child_pnpinfo_str, ow_child_pnpinfo_str), DEVMETHOD(bus_child_location_str, ow_child_location_str), DEVMETHOD(bus_read_ivar, ow_read_ivar), DEVMETHOD(bus_write_ivar, ow_write_ivar), DEVMETHOD(bus_print_child, ow_print_child), DEVMETHOD(bus_probe_nomatch, ow_probe_nomatch), /* One Wire Network/Transport layer interface */ DEVMETHOD(own_send_command, ow_send_command), DEVMETHOD(own_acquire_bus, ow_acquire_bus), DEVMETHOD(own_release_bus, ow_release_bus), DEVMETHOD(own_crc, ow_crc), { 0, 0 } }; static driver_t ow_driver = { "ow", ow_methods, sizeof(struct ow_softc), }; DRIVER_MODULE(ow, owc, ow_driver, ow_devclass, 0, 0); MODULE_VERSION(ow, 1); Index: head/sys/dev/ow/ow.h =================================================================== --- head/sys/dev/ow/ow.h (revision 355393) +++ head/sys/dev/ow/ow.h (revision 355394) @@ -1,77 +1,76 @@ /*- - * Copyright (c) 2015 M. Warner Losh - * All rights reserved. + * Copyright (c) 2015 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice unmodified, this list of conditions, and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ #ifndef DEV_OW_OW_H #define DEV_OW_OW_H 1 enum ow_device_ivars { OW_IVAR_FAMILY, OW_IVAR_ROMID }; #define OW_ACCESSOR(var, ivar, type) \ __BUS_ACCESSOR(ow, var, OW, ivar, type); OW_ACCESSOR(family, FAMILY, uint8_t) OW_ACCESSOR(romid, ROMID, uint8_t *) #undef OW_ACCSSOR /* * The following likely should be in the own.h file, but needs to be here to * avoid recursive issues when defining the own_if.m interface. */ /* * Generalized command structure for a 1wire bus transaction. Not all possible * transactions on the 1wire bus can be represented here (a notable exception * being both the search ROM commands), but most of them can be, allowing for * general transactions from userland. A lower-level interface to the link * layer is also provided. */ #define MAX_ROM 10 #define MAX_XPT 32 #define MAX_READ 32 struct ow_cmd { uint32_t flags; /* Various flags */ #define OW_FLAG_OVERDRIVE 1 /* Send xpt stuff overdrive speed */ #define OW_FLAG_READ_BIT 2 /* Read a single bit after xpt_cmd */ uint8_t rom_len; /* Number of ROM bytes to send */ uint8_t rom_cmd[MAX_ROM]; /* Rom command to send */ uint8_t rom_read_len; /* Number of bytes to read */ uint8_t rom_read[MAX_ROM]; /* Extra bytes read */ uint8_t xpt_len; /* Total transport bytes to send */ uint8_t xpt_cmd[MAX_XPT]; /* Device specific command to send, if flagged */ uint8_t xpt_read_len; /* Number of bytes to read after */ uint8_t xpt_read[MAX_READ]; /* Buffer for read bytes */ }; typedef uint64_t romid_t; #endif /* DEV_OW_OW_H */ Index: head/sys/dev/ow/ow_temp.c =================================================================== --- head/sys/dev/ow/ow_temp.c (revision 355393) +++ head/sys/dev/ow/ow_temp.c (revision 355394) @@ -1,287 +1,286 @@ /*- - * Copyright (c) 2015 M. Warner Losh - * All rights reserved. + * Copyright (c) 2015 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice unmodified, this list of conditions, and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define OWT_DS1820 0x10 /* Also 18S20 */ #define OWT_DS1822 0x22 /* Very close to 18B20 */ #define OWT_DS18B20 0x28 /* Also MAX31820 */ #define OWT_DS1825 0x3B /* Just like 18B20 with address bits */ #define CONVERT_T 0x44 #define COPY_SCRATCHPAD 0x48 #define WRITE_SCRATCHPAD 0x4e #define READ_POWER_SUPPLY 0xb4 #define RECALL_EE 0xb8 #define READ_SCRATCHPAD 0xbe #define OW_TEMP_DONE 0x01 #define OW_TEMP_RUNNING 0x02 struct ow_temp_softc { device_t dev; int type; int temp; int flags; int bad_crc; int bad_reads; int reading_interval; int parasite; struct mtx temp_lock; struct proc *event_thread; }; static int ow_temp_probe(device_t dev) { switch (ow_get_family(dev)) { case OWT_DS1820: device_set_desc(dev, "One Wire Temperature"); return BUS_PROBE_DEFAULT; case OWT_DS1822: case OWT_DS1825: case OWT_DS18B20: device_set_desc(dev, "Advanced One Wire Temperature"); return BUS_PROBE_DEFAULT; default: return ENXIO; } } static int ow_temp_read_scratchpad(device_t dev, uint8_t *scratch, int len) { struct ow_cmd cmd; own_self_command(dev, &cmd, READ_SCRATCHPAD); cmd.xpt_read_len = len; own_command_wait(dev, &cmd); memcpy(scratch, cmd.xpt_read, len); return 0; } static int ow_temp_convert_t(device_t dev) { struct ow_cmd cmd; own_self_command(dev, &cmd, CONVERT_T); own_command_wait(dev, &cmd); return 0; } static int ow_temp_read_power_supply(device_t dev, int *parasite) { struct ow_cmd cmd; own_self_command(dev, &cmd, READ_POWER_SUPPLY); cmd.flags |= OW_FLAG_READ_BIT; cmd.xpt_read_len = 1; own_command_wait(dev, &cmd); *parasite = !cmd.xpt_read[0]; /* parasites pull bus low */ return 0; } static void ow_temp_event_thread(void *arg) { struct ow_temp_softc *sc; uint8_t scratch[8 + 1]; uint8_t crc; int retries, rv, tmp; sc = arg; pause("owtstart", device_get_unit(sc->dev) * hz / 100); // 10ms stagger mtx_lock(&sc->temp_lock); sc->flags |= OW_TEMP_RUNNING; mtx_unlock(&sc->temp_lock); ow_temp_read_power_supply(sc->dev, &sc->parasite); if (sc->parasite) device_printf(sc->dev, "Running in parasitic mode unsupported\n"); mtx_lock(&sc->temp_lock); while ((sc->flags & OW_TEMP_DONE) == 0) { mtx_unlock(&sc->temp_lock); ow_temp_convert_t(sc->dev); mtx_lock(&sc->temp_lock); msleep(sc, &sc->temp_lock, 0, "owtcvt", hz); if (sc->flags & OW_TEMP_DONE) break; mtx_unlock(&sc->temp_lock); for (retries = 5; retries > 0; retries--) { rv = ow_temp_read_scratchpad(sc->dev, scratch, sizeof(scratch)); if (rv == 0) { crc = own_crc(sc->dev, scratch, sizeof(scratch) - 1); if (crc == scratch[8]) { if (sc->type == OWT_DS1820) { if (scratch[7]) { /* * Formula from DS18S20 datasheet, page 6 * DS18S20 datasheet says count_per_c is 16, DS1820 does not */ tmp = (int16_t)((scratch[0] & 0xfe) | (scratch[1] << 8)) << 3; tmp += 16 - scratch[6] - 4; /* count_per_c == 16 */ } else tmp = (int16_t)(scratch[0] | (scratch[1] << 8)) << 3; } else tmp = (int16_t)(scratch[0] | (scratch[1] << 8)); sc->temp = tmp * 1000 / 16 + 273150; break; } sc->bad_crc++; } else sc->bad_reads++; } mtx_lock(&sc->temp_lock); msleep(sc, &sc->temp_lock, 0, "owtcvt", sc->reading_interval); } sc->flags &= ~OW_TEMP_RUNNING; mtx_unlock(&sc->temp_lock); kproc_exit(0); } static int ow_temp_attach(device_t dev) { struct ow_temp_softc *sc; sc = device_get_softc(dev); sc->dev = dev; sc->type = ow_get_family(dev); SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "temperature", CTLFLAG_RD | CTLTYPE_INT, &sc->temp, 0, sysctl_handle_int, "IK3", "Current Temperature"); SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "badcrc", CTLFLAG_RD, &sc->bad_crc, 0, "Number of Bad CRC on reading scratchpad"); SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "badread", CTLFLAG_RD, &sc->bad_reads, 0, "Number of errors on reading scratchpad"); SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "reading_interval", CTLFLAG_RW, &sc->reading_interval, 0, "ticks between reads"); SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "parasite", CTLFLAG_RW, &sc->parasite, 0, "In Parasite mode"); /* * Just do this for unit 0 to avoid locking * the ow bus until that code can be put * into place. */ sc->temp = -1; sc->reading_interval = 10 * hz; mtx_init(&sc->temp_lock, "lock for doing temperature", NULL, MTX_DEF); /* Start the thread */ if (kproc_create(ow_temp_event_thread, sc, &sc->event_thread, 0, 0, "%s event thread", device_get_nameunit(dev))) { device_printf(dev, "unable to create event thread.\n"); panic("ow_temp_attach, can't create thread"); } return 0; } static int ow_temp_detach(device_t dev) { struct ow_temp_softc *sc; sc = device_get_softc(dev); /* * Wait for the thread to die. kproc_exit will do a wakeup * on the event thread's struct thread * so that we know it is * safe to proceed. IF the thread is running, set the please * die flag and wait for it to comply. Since the wakeup on * the event thread happens only in kproc_exit, we don't * need to loop here. */ mtx_lock(&sc->temp_lock); sc->flags |= OW_TEMP_DONE; while (sc->flags & OW_TEMP_RUNNING) { wakeup(sc); msleep(sc->event_thread, &sc->temp_lock, PWAIT, "owtun", 0); } mtx_destroy(&sc->temp_lock); return 0; } devclass_t ow_temp_devclass; static device_method_t ow_temp_methods[] = { /* Device interface */ DEVMETHOD(device_probe, ow_temp_probe), DEVMETHOD(device_attach, ow_temp_attach), DEVMETHOD(device_detach, ow_temp_detach), { 0, 0 } }; static driver_t ow_temp_driver = { "ow_temp", ow_temp_methods, sizeof(struct ow_temp_softc), }; DRIVER_MODULE(ow_temp, ow, ow_temp_driver, ow_temp_devclass, 0, 0); MODULE_DEPEND(ow_temp, ow, 1, 1, 1); Index: head/sys/dev/ow/owc_gpiobus.c =================================================================== --- head/sys/dev/ow/owc_gpiobus.c (revision 355393) +++ head/sys/dev/ow/owc_gpiobus.c (revision 355394) @@ -1,422 +1,421 @@ /*- - * Copyright (c) 2015 M. Warner Losh - * All rights reserved. + * Copyright (c) 2015 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include "opt_platform.h" #include #include #include #include #include #include #include #include #include #ifdef FDT #include #include #include #endif #include #include "gpiobus_if.h" #include #define OW_PIN 0 #define OWC_GPIOBUS_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) #define OWC_GPIOBUS_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) #define OWC_GPIOBUS_LOCK_INIT(_sc) \ mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->sc_dev), \ "owc_gpiobus", MTX_DEF) #define OWC_GPIOBUS_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx); struct owc_gpiobus_softc { device_t sc_dev; device_t sc_busdev; struct mtx sc_mtx; }; static int owc_gpiobus_probe(device_t); static int owc_gpiobus_attach(device_t); static int owc_gpiobus_detach(device_t); #ifdef FDT static void owc_gpiobus_identify(driver_t *driver, device_t bus) { phandle_t w1, root; /* * Find all the 1-wire bus pseudo-nodes that are * at the top level of the FDT. Would be nice to * somehow preserve the node name of these busses, * but there's no good place to put it. The driver's * name is used for the device name, and the 1-wire * bus overwrites the description. */ root = OF_finddevice("/"); if (root == -1) return; for (w1 = OF_child(root); w1 != 0; w1 = OF_peer(w1)) { if (!fdt_is_compatible_strict(w1, "w1-gpio")) continue; if (!OF_hasprop(w1, "gpios")) continue; ofw_gpiobus_add_fdt_child(bus, driver->name, w1); } } #endif static int owc_gpiobus_probe(device_t dev) { #ifdef FDT if (!ofw_bus_status_okay(dev)) return (ENXIO); if (ofw_bus_is_compatible(dev, "w1-gpio")) { device_set_desc(dev, "FDT GPIO attached one-wire bus"); return (BUS_PROBE_DEFAULT); } return (ENXIO); #else device_set_desc(dev, "GPIO attached one-wire bus"); return 0; #endif } static int owc_gpiobus_attach(device_t dev) { struct owc_gpiobus_softc *sc; device_t *kids; int nkid; sc = device_get_softc(dev); sc->sc_dev = dev; sc->sc_busdev = device_get_parent(dev); OWC_GPIOBUS_LOCK_INIT(sc); nkid = 0; if (device_get_children(dev, &kids, &nkid) == 0) free(kids, M_TEMP); if (nkid == 0) device_add_child(dev, "ow", -1); bus_generic_attach(dev); return (0); } static int owc_gpiobus_detach(device_t dev) { struct owc_gpiobus_softc *sc; sc = device_get_softc(dev); OWC_GPIOBUS_LOCK_DESTROY(sc); bus_generic_detach(dev); return (0); } /* * In the diagrams below, R is driven by the resistor pullup, M is driven by the * master, and S is driven by the slave / target. */ /* * These macros let what why we're doing stuff shine in the code * below, and let the how be confined to here. */ #define GETBUS(sc) GPIOBUS_ACQUIRE_BUS((sc)->sc_busdev, \ (sc)->sc_dev, GPIOBUS_WAIT) #define RELBUS(sc) GPIOBUS_RELEASE_BUS((sc)->sc_busdev, \ (sc)->sc_dev) #define OUTPIN(sc) GPIOBUS_PIN_SETFLAGS((sc)->sc_busdev, \ (sc)->sc_dev, OW_PIN, GPIO_PIN_OUTPUT) #define INPIN(sc) GPIOBUS_PIN_SETFLAGS((sc)->sc_busdev, \ (sc)->sc_dev, OW_PIN, GPIO_PIN_INPUT) #define GETPIN(sc, bit) GPIOBUS_PIN_GET((sc)->sc_busdev, \ (sc)->sc_dev, OW_PIN, bit) #define LOW(sc) GPIOBUS_PIN_SET((sc)->sc_busdev, \ (sc)->sc_dev, OW_PIN, GPIO_PIN_LOW) /* * WRITE-ONE (see owll_if.m for timings) From Figure 4-1 AN-937 * * |<---------tSLOT---->|<-tREC->| * High RRRRM | RRRRRRRRRRRR|RRRRRRRRM * M | R | | | M * M| R | | | M * Low MMMMMMM | | | MMMMMM... * |<-tLOW1->| | | * |<------15us--->| | * |<--------60us---->| */ static int owc_gpiobus_write_one(device_t dev, struct ow_timing *t) { struct owc_gpiobus_softc *sc; int error; sc = device_get_softc(dev); error = GETBUS(sc); if (error != 0) return (error); critical_enter(); /* Force low */ OUTPIN(sc); LOW(sc); DELAY(t->t_low1); /* Allow resistor to float line high */ INPIN(sc); DELAY(t->t_slot - t->t_low1 + t->t_rec); critical_exit(); RELBUS(sc); return (0); } /* * WRITE-ZERO (see owll_if.m for timings) From Figure 4-2 AN-937 * * |<---------tSLOT------>|<-tREC->| * High RRRRM | | |RRRRRRRM * M | | R M * M| | | |R M * Low MMMMMMMMMMMMMMMMMMMMMR MMMMMM... * |<--15us->| | | * |<------60us--->| | * |<-------tLOW0------>| */ static int owc_gpiobus_write_zero(device_t dev, struct ow_timing *t) { struct owc_gpiobus_softc *sc; int error; sc = device_get_softc(dev); error = GETBUS(sc); if (error != 0) return (error); critical_enter(); /* Force low */ OUTPIN(sc); LOW(sc); DELAY(t->t_low0); /* Allow resistor to float line high */ INPIN(sc); DELAY(t->t_slot - t->t_low0 + t->t_rec); critical_exit(); RELBUS(sc); return (0); } /* * READ-DATA (see owll_if.m for timings) From Figure 4-3 AN-937 * * |<---------tSLOT------>|<-tREC->| * High RRRRM | rrrrrrrrrrrrrrrRRRRRRRM * M | r | R M * M| r | |R M * Low MMMMMMMSSSSSSSSSSSSSSR MMMMMM... * |< sample > | * |<------tRDV---->| | * ->| |<-tRELEASE * * r -- allowed to pull high via the resitor when slave writes a 1-bit * */ static int owc_gpiobus_read_data(device_t dev, struct ow_timing *t, int *bit) { struct owc_gpiobus_softc *sc; int error, sample; sbintime_t then, now; sc = device_get_softc(dev); error = GETBUS(sc); if (error != 0) return (error); critical_enter(); /* Force low for t_lowr microseconds */ then = sbinuptime(); OUTPIN(sc); LOW(sc); DELAY(t->t_lowr); /* * Slave is supposed to hold the line low for t_rdv microseconds for 0 * and immediately float it high for a 1. This is measured from the * master's pushing the line low. */ INPIN(sc); do { now = sbinuptime(); GETPIN(sc, &sample); } while (now - then < (t->t_rdv + 2) * SBT_1US && sample == 0); critical_exit(); if (now - then < t->t_rdv * SBT_1US) *bit = 1; else *bit = 0; /* Wait out the rest of t_slot */ do { now = sbinuptime(); } while (now - then < (t->t_slot + t->t_rec) * SBT_1US); RELBUS(sc); return (error); } /* * RESET AND PRESENCE PULSE (see owll_if.m for timings) From Figure 4-4 AN-937 * * |<---------tRSTH------------>| * High RRRM | | RRRRRRRS | RRRR RRM * M | |R| |S | R M * M| R | | S |R M * Low MMMMMMMM MMMMMM| | | SSSSSSSSSS MMMMMM * |<----tRSTL--->| | |<-tPDL---->| * | ->| |<-tR | | * || * * Note: for Regular Speed operations, tRSTL + tR should be less than 960us to * avoid interferring with other devices on the bus */ static int owc_gpiobus_reset_and_presence(device_t dev, struct ow_timing *t, int *bit) { struct owc_gpiobus_softc *sc; int error; int buf = -1; sc = device_get_softc(dev); error = GETBUS(sc); if (error != 0) return (error); /* * Read the current state of the bus. The steady state of an idle bus is * high. Badly wired buses that are missing the required pull up, or * that have a short circuit to ground cause all kinds of mischief when * we try to read them later. Return EIO and release the bus if the bus * is currently low. */ INPIN(sc); GETPIN(sc, &buf); if (buf == 0) { *bit = -1; RELBUS(sc); return (EIO); } critical_enter(); /* Force low */ OUTPIN(sc); LOW(sc); DELAY(t->t_rstl); /* Allow resistor to float line high and then wait for reset pulse */ INPIN(sc); DELAY(t->t_pdh + t->t_pdl / 2); /* Read presence pulse */ GETPIN(sc, &buf); *bit = !!buf; critical_exit(); DELAY(t->t_rsth - (t->t_pdh + t->t_pdl / 2)); /* Timing not critical for this one */ /* * Read the state of the bus after we've waited past the end of the rest * window. It should return to high. If it is low, then we have some * problem and should abort the reset. */ GETPIN(sc, &buf); if (buf == 0) { *bit = -1; RELBUS(sc); return (EIO); } RELBUS(sc); return (0); } static devclass_t owc_gpiobus_devclass; static device_method_t owc_gpiobus_methods[] = { /* Device interface */ #ifdef FDT DEVMETHOD(device_identify, owc_gpiobus_identify), #endif DEVMETHOD(device_probe, owc_gpiobus_probe), DEVMETHOD(device_attach, owc_gpiobus_attach), DEVMETHOD(device_detach, owc_gpiobus_detach), DEVMETHOD(owll_write_one, owc_gpiobus_write_one), DEVMETHOD(owll_write_zero, owc_gpiobus_write_zero), DEVMETHOD(owll_read_data, owc_gpiobus_read_data), DEVMETHOD(owll_reset_and_presence, owc_gpiobus_reset_and_presence), { 0, 0 } }; static driver_t owc_gpiobus_driver = { "owc", owc_gpiobus_methods, sizeof(struct owc_gpiobus_softc), }; DRIVER_MODULE(owc_gpiobus, gpiobus, owc_gpiobus_driver, owc_gpiobus_devclass, 0, 0); MODULE_DEPEND(owc_gpiobus, ow, 1, 1, 1); MODULE_DEPEND(owc_gpiobus, gpiobus, 1, 1, 1); MODULE_VERSION(owc_gpiobus, 1); Index: head/sys/dev/ow/owll.h =================================================================== --- head/sys/dev/ow/owll.h (revision 355393) +++ head/sys/dev/ow/owll.h (revision 355394) @@ -1,54 +1,53 @@ /*- - * Copyright (c) 2015 M. Warner Losh - * All rights reserved. + * Copyright (c) 2015 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice unmodified, this list of conditions, and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ #ifndef DEV_OW_OWLL_H #define DEV_OW_OWLL_H 1 /* * Generalized parameters for the mode of operation in the bus. All units * are in nanoseconds, and assume that all timings are < 4s. * See owll_if.m for timings, and refer to AN937 for details. */ struct ow_timing { uint32_t t_slot; /* Slot time */ uint32_t t_low0; /* Time low for a 0 bit. */ uint32_t t_low1; /* Time low for a 1 bit. */ uint32_t t_lowr; /* Time slave holds line down per bit */ uint32_t t_release; /* Time after t_rdv to float high */ uint32_t t_rec; /* After sample before M low */ uint32_t t_rdv; /* Time to poll the bit after M low */ uint32_t t_rstl; /* Time M low on reset */ uint32_t t_rsth; /* Time M high on reset */ uint32_t t_pdl; /* Time S low on reset */ uint32_t t_pdh; /* Time R high after M low on reset */ }; #include "owll_if.h" #endif /* DEV_OW_OWLL_H */ Index: head/sys/dev/ow/owll_if.m =================================================================== --- head/sys/dev/ow/owll_if.m (revision 355393) +++ head/sys/dev/ow/owll_if.m (revision 355394) @@ -1,158 +1,157 @@ #- -# Copyright (c) 2015 M. Warner Losh -# All rights reserved. +# Copyright (c) 2015 M. Warner Losh # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # $FreeBSD$ # #include #include INTERFACE owll; # # Dallas Semiconductor 1-Wire bus Link Layer (owll) # # See Maxim Application Note AN937: Book of iButton Standards for the # 1-Wire protocol specification. # http://pdfserv.maximintegrated.com/en/an/AN937.pdf # # Note: 1-Wire is a registered trademark of Maxim Integrated Products, Inc. # # This file provides an interface to the logical layer of the protocol. # Although the first implementation is done with GPIO bit banging, some # SoCs have a 1-Wire controller with more smarts or hardware offload. # Maxim datasheets also describe how to use UARTs to generate timing, # as well as both usb and i2c 1-Wire controllers. # # Chapter 4 has all the electrical timing diagrams that make up the link # layer of this protocol. # # Two speed classes are defined: Regular speed and Overdrive speed. # It is the responsibility of a device implementing the owll(9) interface # to ensure that the timings are met: # # Regular Overdrive # # 60us <= tSLOT < 120us 6us <= tSLOT <= 16us # 60us <= tLOW0 < tSLOT < 120us 6us <= tLOW0 < tSLOT < 16us # 1us <= tLOW1 < 15us 1us <= tLOW < 2us # 1us < tLOWR < 15us 1us <= tLOWR < 2us # 0 <= tRELEASE < 45us 0 <= tRELEASE < 4us # 1us <= tREC < inf 1us <= tREC < inf # tRDV = 15us tRDV = 2us # 480us <= tRSTL < inf 48us <= tRSTL < 80us # 480us <= tRSTH < inf 48us <= tRSTH < inf # 15us < tPDH < 60us 2us <= tPDH < 6us # 60us < tPDL < 240us 8us <= tPDL < 24us # # In the diagrams below, R is driven by the resistor pullup, M is driven by # the master, and S is driven by the slave / target. # # All of these methods are expected to be called from the "network"/bus layer # for doing its operations. See 1wn_if.m for those. # # Note: This is the polling / busy-wait interface. An interrupt-based interface # may be different. But an interrupt-based, non-blocking interface can be tricky. # # Only the owbus should talk to this interface. # # WRITE-ONE (see above for timings) From Figure 4-1 AN-937 # # |<---------tSLOT---->|<-tREC->| # High RRRRM | RRRRRRRRRRRR|RRRRRRRRM # M | R | | | M # M| R | | | M # Low MMMMMMM | | | MMMMMM... # |<-tLOW1->| | | # |<------15us--->| | # |<--------60us---->| # # METHOD int write_one { device_t lldev; /* Link Level device (eg bridge) */ struct ow_timing *timing; /* timing values */ }; # WRITE-ZERO (see above for timings) From Figure 4-2 AN-937 # # |<---------tSLOT------>|<-tREC->| # High RRRRM | | |RRRRRRRM # M | | R M # M| | | |R M # Low MMMMMMMMMMMMMMMMMMMMMR MMMMMM... # |<--15us->| | | # |<------60us--->| | # |<-------tLOW0------>| # # METHOD int write_zero { device_t lldev; /* Link Level device (eg bridge) */ struct ow_timing *timing; /* timing values */ }; # READ-DATA (see above for timings) From Figure 4-3 AN-937 # # |<---------tSLOT------>|<-tREC->| # High RRRRM | rrrrrrrrrrrrrrrRRRRRRRM # M | r | R M # M| r | |R M # Low MMMMMMMSSSSSSSSSSSSSSR MMMMMM... # |< sample > | # |<------tRDV---->| | # ->| |<-tRELEASE # # r -- allowed to pull high via the resistor when slave writes a 1-bit # METHOD int read_data { device_t lldev; /* Link Level device (eg bridge) */ struct ow_timing *timing; /* timing values */ int *bit; /* Bit we sampled */ }; # RESET AND PRESENCE PULSE (see above for timings) From Figure 4-4 AN-937 # # |<---------tRSTH------------>| # High RRRM | | RRRRRRRS | RRRR RRM # M | |R| |S | R M # M| R | | S |R M # Low MMMMMMMM MMMMMM| | | SSSSSSSSSS MMMMMM # |<----tRSTL--->| | |<-tPDL---->| # | ->| |<-tR | | # || # # Note: for Regular Speed operations, tRSTL + tR should be less than 960us to # avoid interfering with other devives on the bus. # # Returns errors associating with acquiring the bus, or EIO to indicate # that the bus was low during the RRRR time where it should have been # pulled high. The present field is always updated, even on error. # METHOD int reset_and_presence { device_t lldev; /* Link level device (eg bridge) */ struct ow_timing *timing; /* timing values */ int *present; /* 0 = slave 1 = no slave -1 = bus error */ }; Index: head/sys/dev/ow/own.h =================================================================== --- head/sys/dev/ow/own.h (revision 355393) +++ head/sys/dev/ow/own.h (revision 355394) @@ -1,106 +1,105 @@ /*- - * Copyright (c) 2015 M. Warner Losh - * All rights reserved. + * Copyright (c) 2015 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice unmodified, this list of conditions, and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ #ifndef DEV_OW_OWN_H #define DEV_OW_OWN_H 1 #include "own_if.h" #define READ_ROM 0x33 #define MATCH_ROM 0x55 #define SKIP_ROM 0xcc #define ALARM_SEARCH 0xec #define SEARCH_ROM 0xf0 static inline int own_send_command(device_t pdev, struct ow_cmd *cmd) { device_t ndev = device_get_parent(pdev); return OWN_SEND_COMMAND(ndev, pdev, cmd); } /* * How args for own_acquire_bus */ #define OWN_WAIT 1 #define OWN_DONTWAIT 2 static inline int own_acquire_bus(device_t pdev, int how) { device_t ndev = device_get_parent(pdev); return OWN_ACQUIRE_BUS(ndev, pdev, how); } static inline void own_release_bus(device_t pdev) { device_t ndev = device_get_parent(pdev); OWN_RELEASE_BUS(ndev, pdev); } static inline uint8_t own_crc(device_t pdev, uint8_t *buffer, size_t len) { device_t ndev = device_get_parent(pdev); return OWN_CRC(ndev, pdev, buffer, len); } static inline void own_self_command(device_t pdev, struct ow_cmd *cmd, uint8_t xpt_cmd) { uint8_t *mep; memset(cmd, 0, sizeof(*cmd)); mep = ow_get_romid(pdev); cmd->rom_cmd[0] = MATCH_ROM; memcpy(&cmd->rom_cmd[1], mep, sizeof(romid_t)); cmd->rom_len = 1 + sizeof(romid_t); cmd->xpt_cmd[0] = xpt_cmd; cmd->xpt_len = 1; } static inline int own_command_wait(device_t pdev, struct ow_cmd *cmd) { int rv; rv = own_acquire_bus(pdev, OWN_WAIT); if (rv != 0) return rv; rv = own_send_command(pdev, cmd); own_release_bus(pdev); return rv; } #endif /* DEV_OW_OWLL_H */ Index: head/sys/dev/ow/own_if.m =================================================================== --- head/sys/dev/ow/own_if.m (revision 355393) +++ head/sys/dev/ow/own_if.m (revision 355394) @@ -1,78 +1,77 @@ #- -# Copyright (c) 2015 M. Warner Losh -# All rights reserved. +# Copyright (c) 2015 M. Warner Losh # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # $FreeBSD$ # #include #include INTERFACE own; # # Dallas Semiconductor 1-Wire bus network and transport layer (own) # # See Maxim Application Note AN937: Book of iButton Standards for the # 1-Wire protocol specification. # http://pdfserv.maximintegrated.com/en/an/AN937.pdf # # Note: 1-Wire is a registered trademark of Maxim Integrated Products, Inc. # # # Send a command up the stack. # METHOD int send_command { device_t ndev; /* Network (bus) level device */ device_t pdev; /* Device to send command for */ struct ow_cmd *cmd; /* Pointer to filled in command */ }; # # Grab exclusive use of the bus (advisory) # METHOD int acquire_bus { device_t ndev; device_t pdev; int how; }; # # Release exclusive use of the bus (advisory) # METHOD void release_bus { device_t ndev; device_t pdev; }; # # Compute a CRC for a given range of bytes # METHOD uint8_t crc { device_t ndev; device_t pdev; uint8_t *buffer; size_t len; }; Index: head/sys/dev/pccard/card_if.m =================================================================== --- head/sys/dev/pccard/card_if.m (revision 355393) +++ head/sys/dev/pccard/card_if.m (revision 355394) @@ -1,152 +1,151 @@ #- -# Copyright (c) 1999 M. Warner Losh. -# All rights reserved. +# Copyright (c) 1999 M. Warner Losh # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # $FreeBSD$ # #include #include #include INTERFACE card; # # Companion interface for pccard. We need to set attributes for memory # and i/o port mappings (as well as other types of attributes) that have # a well defined meaning inside the PC Card/CardBus system. The bus # methods are inadequate for this because this must be done at the time the # resources are set for the device, which predates their activation. Also, # the driver activating the resources doesn't necessarily know or need to know # these attributes. # METHOD int set_res_flags { device_t dev; device_t child; int restype; int rid; u_long value; }; METHOD int get_res_flags { device_t dev; device_t child; int restype; int rid; u_long *value; }; # # Sets the memory offset of the pccard bridge's window into attribute # or common memory space. # METHOD int set_memory_offset { device_t dev; device_t child; int rid; uint32_t cardaddr; uint32_t *deltap; } METHOD int get_memory_offset { device_t dev; device_t child; int rid; uint32_t *offset; } # # pccard bridges call this method to initate the attachment of a card # METHOD int attach_card { device_t dev; } # # pccard bridges call this to detach a card. # METHOD int detach_card { device_t dev; } # # Find "dev" in the passed table of devices. Return it or NULL. # METHOD const struct pccard_product * do_product_lookup { device_t bus; device_t dev; const struct pccard_product *tab; size_t ent_size; pccard_product_match_fn matchfn; } # # Scanning function for accessing the CIS of a card in its driver. # METHOD int cis_scan { device_t bus; device_t dev; pccard_scan_t fnp; void *argp; }; # # Convenience function to read attribute memory. # METHOD int attr_read { device_t bus; device_t dev; uint32_t offset; uint8_t *val; } # # Convenience function to write attribute memory. # METHOD int attr_write { device_t bus; device_t dev; uint32_t offset; uint8_t val; } # # Read the CCR register # METHOD int ccr_read { device_t bus; device_t dev; uint32_t offset; uint8_t *val; } # # Write the CCR register # METHOD int ccr_write { device_t bus; device_t dev; uint32_t offset; uint8_t val; } Index: head/sys/dev/pccard/pccard_device.c =================================================================== --- head/sys/dev/pccard/pccard_device.c (revision 355393) +++ head/sys/dev/pccard/pccard_device.c (revision 355394) @@ -1,175 +1,174 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2005, M. Warner Losh - * All rights reserved. + * Copyright (c) 2005 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice unmodified, this list of conditions, and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include static d_open_t pccard_open; static d_close_t pccard_close; static d_read_t pccard_read; static d_ioctl_t pccard_ioctl; static struct cdevsw pccard_cdevsw = { .d_version = D_VERSION, .d_open = pccard_open, .d_close = pccard_close, .d_read = pccard_read, .d_ioctl = pccard_ioctl, .d_name = "pccard" }; int pccard_device_create(struct pccard_softc *sc) { uint32_t minor; minor = device_get_unit(sc->dev) << 16; sc->cisdev = make_dev(&pccard_cdevsw, minor, 0, 0, 0666, "pccard%u.cis", device_get_unit(sc->dev)); sc->cisdev->si_drv1 = sc; return (0); } int pccard_device_destroy(struct pccard_softc *sc) { if (sc->cisdev) destroy_dev(sc->cisdev); return (0); } static int pccard_build_cis(const struct pccard_tuple *tuple, void *argp) { struct cis_buffer *cis; int i; uint8_t ch; cis = (struct cis_buffer *)argp; /* * CISTPL_END is a special case, it has no length field. */ if (tuple->code == CISTPL_END) { if (cis->len + 1 > sizeof(cis->buffer)) return (ENOSPC); cis->buffer[cis->len++] = tuple->code; return (0); } if (cis->len + 2 + tuple->length > sizeof(cis->buffer)) return (ENOSPC); cis->buffer[cis->len++] = tuple->code; cis->buffer[cis->len++] = tuple->length; for (i = 0; i < tuple->length; i++) { ch = pccard_tuple_read_1(tuple, i); cis->buffer[cis->len++] = ch; } return (0); } static int pccard_open(struct cdev *dev, int oflags, int devtype, struct thread *td) { device_t parent, child; device_t *kids; int cnt, err; struct pccard_softc *sc; sc = dev->si_drv1; if (sc->cis_open) return (EBUSY); parent = sc->dev; err = device_get_children(parent, &kids, &cnt); if (err) return err; if (cnt == 0) { free(kids, M_TEMP); sc->cis_open++; sc->cis = NULL; return (0); } child = kids[0]; free(kids, M_TEMP); sc->cis = malloc(sizeof(*sc->cis), M_TEMP, M_ZERO | M_WAITOK); err = pccard_scan_cis(parent, child, pccard_build_cis, sc->cis); if (err) { free(sc->cis, M_TEMP); sc->cis = NULL; return (err); } sc->cis_open++; return (0); } static int pccard_close(struct cdev *dev, int fflags, int devtype, struct thread *td) { struct pccard_softc *sc; sc = dev->si_drv1; free(sc->cis, M_TEMP); sc->cis = NULL; sc->cis_open = 0; return (0); } static int pccard_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread *td) { return (ENOTTY); } static int pccard_read(struct cdev *dev, struct uio *uio, int ioflag) { struct pccard_softc *sc; sc = dev->si_drv1; /* EOF */ if (sc->cis == NULL || uio->uio_offset > sc->cis->len) return (0); return (uiomove(sc->cis->buffer + uio->uio_offset, MIN(uio->uio_resid, sc->cis->len - uio->uio_offset), uio)); } Index: head/sys/dev/pccard/pccardvarp.h =================================================================== --- head/sys/dev/pccard/pccardvarp.h (revision 355393) +++ head/sys/dev/pccard/pccardvarp.h (revision 355394) @@ -1,200 +1,199 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2005, M. Warner Losh - * All rights reserved. + * Copyright (c) 2005 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice unmodified, this list of conditions, and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _PCCARD_PCCARDVARP_H #define _PCCARD_PCCARDVARP_H /* pccard itself */ #define PCCARD_MEM_PAGE_SIZE 1024 #define PCCARD_CFE_MWAIT_REQUIRED 0x0001 #define PCCARD_CFE_RDYBSY_ACTIVE 0x0002 #define PCCARD_CFE_WP_ACTIVE 0x0004 #define PCCARD_CFE_BVD_ACTIVE 0x0008 #define PCCARD_CFE_IO8 0x0010 #define PCCARD_CFE_IO16 0x0020 #define PCCARD_CFE_IRQSHARE 0x0040 #define PCCARD_CFE_IRQPULSE 0x0080 #define PCCARD_CFE_IRQLEVEL 0x0100 #define PCCARD_CFE_POWERDOWN 0x0200 #define PCCARD_CFE_READONLY 0x0400 #define PCCARD_CFE_AUDIO 0x0800 struct pccard_ce_iospace { rman_res_t length; rman_res_t start; }; struct pccard_ce_memspace { rman_res_t length; rman_res_t cardaddr; rman_res_t hostaddr; }; struct pccard_config_entry { int number; uint32_t flags; int iftype; int num_iospace; /* * The card will only decode this mask in any case, so we can * do dynamic allocation with this in mind, in case the suggestions * below are no good. */ u_long iomask; struct pccard_ce_iospace iospace[4]; /* XXX up to 16 */ uint16_t irqmask; int num_memspace; struct pccard_ce_memspace memspace[2]; /* XXX up to 8 */ int maxtwins; STAILQ_ENTRY(pccard_config_entry) cfe_list; }; struct pccard_funce_disk { uint8_t pfd_interface; uint8_t pfd_power; }; struct pccard_funce_lan { int pfl_nidlen; uint8_t pfl_nid[8]; }; union pccard_funce { struct pccard_funce_disk pfv_disk; struct pccard_funce_lan pfv_lan; }; struct pccard_function { /* read off the card */ int number; int function; int last_config_index; uint32_t ccr_base; /* Offset with card's memory */ uint32_t ccr_mask; struct resource *ccr_res; int ccr_rid; STAILQ_HEAD(, pccard_config_entry) cfe_head; STAILQ_ENTRY(pccard_function) pf_list; /* run-time state */ struct pccard_softc *sc; struct pccard_config_entry *cfe; struct pccard_mem_handle pf_pcmh; device_t dev; #define pf_ccrt pf_pcmh.memt #define pf_ccrh pf_pcmh.memh #define pf_ccr_realsize pf_pcmh.realsize uint32_t pf_ccr_offset; /* Offset from ccr_base of CIS */ int pf_ccr_window; bus_addr_t pf_mfc_iobase; bus_addr_t pf_mfc_iomax; int pf_flags; driver_filter_t *intr_filter; driver_intr_t *intr_handler; void *intr_handler_arg; void *intr_handler_cookie; union pccard_funce pf_funce; /* CISTPL_FUNCE */ #define pf_funce_disk_interface pf_funce.pfv_disk.pfd_interface #define pf_funce_disk_power pf_funce.pfv_disk.pfd_power #define pf_funce_lan_nid pf_funce.pfv_lan.pfl_nid #define pf_funce_lan_nidlen pf_funce.pfv_lan.pfl_nidlen }; /* pf_flags */ #define PFF_ENABLED 0x0001 /* function is enabled */ struct pccard_card { int cis1_major; int cis1_minor; /* XXX waste of space? */ char cis1_info_buf[256]; char *cis1_info[4]; /* * Use int32_t for manufacturer and product so that they can * hold the id value found in card CIS and special value that * indicates no id was found. */ int32_t manufacturer; #define PCMCIA_VENDOR_INVALID -1 int32_t product; #define PCMCIA_PRODUCT_INVALID -1 int16_t prodext; uint16_t error; #define PCMCIA_CIS_INVALID { NULL, NULL, NULL, NULL } STAILQ_HEAD(, pccard_function) pf_head; }; /* More later? */ struct pccard_ivar { struct resource_list resources; struct pccard_function *pf; }; struct cis_buffer { size_t len; /* Actual length of the CIS */ uint8_t buffer[2040]; /* small enough to be 2k */ }; struct pccard_softc { device_t dev; /* this stuff is for the socket */ /* this stuff is for the card */ struct pccard_card card; int sc_enabled_count; /* num functions enabled */ struct cdev *cisdev; int cis_open; struct cis_buffer *cis; }; struct pccard_cis_quirk { int32_t manufacturer; int32_t product; char *cis1_info[4]; struct pccard_function *pf; struct pccard_config_entry *cfe; }; void pccard_read_cis(struct pccard_softc *); void pccard_check_cis_quirks(device_t); void pccard_print_cis(device_t); int pccard_scan_cis(device_t, device_t, pccard_scan_t, void *); int pccard_device_create(struct pccard_softc *); int pccard_device_destroy(struct pccard_softc *); #define PCCARD_SOFTC(d) (struct pccard_softc *) device_get_softc(d) #define PCCARD_IVAR(d) (struct pccard_ivar *) device_get_ivars(d) #endif /* _PCCARD_PCCARDVARP_H */ Index: head/sys/dev/pccard/power_if.m =================================================================== --- head/sys/dev/pccard/power_if.m (revision 355393) +++ head/sys/dev/pccard/power_if.m (revision 355394) @@ -1,46 +1,45 @@ #- -# Copyright (c) 1999 M. Warner Losh. -# All rights reserved. +# Copyright (c) 1999 M. Warner Losh # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # $FreeBSD$ # #include INTERFACE power; # # Interface for powering cards on/off. It is hoped that this will be # generic enough to be used for other systems in addition to the pccard # <-> pcic interface that it was originally written for. # METHOD int enable_socket { device_t dev; device_t child; }; METHOD int disable_socket { device_t dev; device_t child; }; Index: head/sys/dev/pccbb/pccbb.c =================================================================== --- head/sys/dev/pccbb/pccbb.c (revision 355393) +++ head/sys/dev/pccbb/pccbb.c (revision 355394) @@ -1,1596 +1,1595 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2002-2004 M. Warner Losh. - * Copyright (c) 2000-2001 Jonathan Chen. - * All rights reserved. + * Copyright (c) 2000-2001 Jonathan Chen All rights reserved. + * Copyright (c) 2002-2004 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ /*- * Copyright (c) 1998, 1999 and 2000 * HAYAKAWA Koichi. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by HAYAKAWA Koichi. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Driver for PCI to CardBus Bridge chips * and PCI to PCMCIA Bridge chips * and ISA to PCMCIA host adapters * and C Bus to PCMCIA host adapters * * References: * TI Datasheets: * http://www-s.ti.com/cgi-bin/sc/generic2.cgi?family=PCI+CARDBUS+CONTROLLERS * * Written by Jonathan Chen * The author would like to acknowledge: * * HAYAKAWA Koichi: Author of the NetBSD code for the same thing * * Warner Losh: Newbus/newcard guru and author of the pccard side of things * * YAMAMOTO Shigeru: Author of another FreeBSD cardbus driver * * David Cross: Author of the initial ugly hack for a specific cardbus card */ #include __FBSDID("$FreeBSD$"); #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 "power_if.h" #include "card_if.h" #include "pcib_if.h" #define DPRINTF(x) do { if (cbb_debug) printf x; } while (0) #define DEVPRINTF(x) do { if (cbb_debug) device_printf x; } while (0) #define PCI_MASK_CONFIG(DEV,REG,MASK,SIZE) \ pci_write_config(DEV, REG, pci_read_config(DEV, REG, SIZE) MASK, SIZE) #define PCI_MASK2_CONFIG(DEV,REG,MASK1,MASK2,SIZE) \ pci_write_config(DEV, REG, ( \ pci_read_config(DEV, REG, SIZE) MASK1) MASK2, SIZE) #define CBB_CARD_PRESENT(s) ((s & CBB_STATE_CD) == 0) #define CBB_START_MEM 0x88000000 #define CBB_START_32_IO 0x1000 #define CBB_START_16_IO 0x100 devclass_t cbb_devclass; /* sysctl vars */ static SYSCTL_NODE(_hw, OID_AUTO, cbb, CTLFLAG_RD, 0, "CBB parameters"); /* There's no way to say TUNEABLE_LONG to get the right types */ u_long cbb_start_mem = CBB_START_MEM; SYSCTL_ULONG(_hw_cbb, OID_AUTO, start_memory, CTLFLAG_RWTUN, &cbb_start_mem, CBB_START_MEM, "Starting address for memory allocations"); u_long cbb_start_16_io = CBB_START_16_IO; SYSCTL_ULONG(_hw_cbb, OID_AUTO, start_16_io, CTLFLAG_RWTUN, &cbb_start_16_io, CBB_START_16_IO, "Starting ioport for 16-bit cards"); u_long cbb_start_32_io = CBB_START_32_IO; SYSCTL_ULONG(_hw_cbb, OID_AUTO, start_32_io, CTLFLAG_RWTUN, &cbb_start_32_io, CBB_START_32_IO, "Starting ioport for 32-bit cards"); int cbb_debug = 0; SYSCTL_INT(_hw_cbb, OID_AUTO, debug, CTLFLAG_RWTUN, &cbb_debug, 0, "Verbose cardbus bridge debugging"); static void cbb_insert(struct cbb_softc *sc); static void cbb_removal(struct cbb_softc *sc); static uint32_t cbb_detect_voltage(device_t brdev); static int cbb_cardbus_reset_power(device_t brdev, device_t child, int on); static int cbb_cardbus_io_open(device_t brdev, int win, uint32_t start, uint32_t end); static int cbb_cardbus_mem_open(device_t brdev, int win, uint32_t start, uint32_t end); static void cbb_cardbus_auto_open(struct cbb_softc *sc, int type); static int cbb_cardbus_activate_resource(device_t brdev, device_t child, int type, int rid, struct resource *res); static int cbb_cardbus_deactivate_resource(device_t brdev, device_t child, int type, int rid, struct resource *res); static struct resource *cbb_cardbus_alloc_resource(device_t brdev, device_t child, int type, int *rid, rman_res_t start, rman_res_t end, rman_res_t count, u_int flags); static int cbb_cardbus_release_resource(device_t brdev, device_t child, int type, int rid, struct resource *res); static int cbb_cardbus_power_enable_socket(device_t brdev, device_t child); static int cbb_cardbus_power_disable_socket(device_t brdev, device_t child); static int cbb_func_filt(void *arg); static void cbb_func_intr(void *arg); static void cbb_remove_res(struct cbb_softc *sc, struct resource *res) { struct cbb_reslist *rle; SLIST_FOREACH(rle, &sc->rl, link) { if (rle->res == res) { SLIST_REMOVE(&sc->rl, rle, cbb_reslist, link); free(rle, M_DEVBUF); return; } } } static struct resource * cbb_find_res(struct cbb_softc *sc, int type, int rid) { struct cbb_reslist *rle; SLIST_FOREACH(rle, &sc->rl, link) if (SYS_RES_MEMORY == rle->type && rid == rle->rid) return (rle->res); return (NULL); } static void cbb_insert_res(struct cbb_softc *sc, struct resource *res, int type, int rid) { struct cbb_reslist *rle; /* * Need to record allocated resource so we can iterate through * it later. */ rle = malloc(sizeof(struct cbb_reslist), M_DEVBUF, M_NOWAIT); if (rle == NULL) panic("cbb_cardbus_alloc_resource: can't record entry!"); rle->res = res; rle->type = type; rle->rid = rid; SLIST_INSERT_HEAD(&sc->rl, rle, link); } static void cbb_destroy_res(struct cbb_softc *sc) { struct cbb_reslist *rle; while ((rle = SLIST_FIRST(&sc->rl)) != NULL) { device_printf(sc->dev, "Danger Will Robinson: Resource " "left allocated! This is a bug... " "(rid=%x, type=%d, addr=%jx)\n", rle->rid, rle->type, rman_get_start(rle->res)); SLIST_REMOVE_HEAD(&sc->rl, link); free(rle, M_DEVBUF); } } /* * Disable function interrupts by telling the bridge to generate IRQ1 * interrupts. These interrupts aren't really generated by the chip, since * IRQ1 is reserved. Some chipsets assert INTA# inappropriately during * initialization, so this helps to work around the problem. * * XXX We can't do this workaround for all chipsets, because this * XXX causes interference with the keyboard because somechipsets will * XXX actually signal IRQ1 over their serial interrupt connections to * XXX the south bridge. Disable it it for now. */ void cbb_disable_func_intr(struct cbb_softc *sc) { #if 0 uint8_t reg; reg = (exca_getb(&sc->exca[0], EXCA_INTR) & ~EXCA_INTR_IRQ_MASK) | EXCA_INTR_IRQ_RESERVED1; exca_putb(&sc->exca[0], EXCA_INTR, reg); #endif } /* * Enable function interrupts. We turn on function interrupts when the card * requests an interrupt. The PCMCIA standard says that we should set * the lower 4 bits to 0 to route via PCI. Note: we call this for both * CardBus and R2 (PC Card) cases, but it should have no effect on CardBus * cards. */ static void cbb_enable_func_intr(struct cbb_softc *sc) { uint8_t reg; reg = (exca_getb(&sc->exca[0], EXCA_INTR) & ~EXCA_INTR_IRQ_MASK) | EXCA_INTR_IRQ_NONE; exca_putb(&sc->exca[0], EXCA_INTR, reg); PCI_MASK_CONFIG(sc->dev, CBBR_BRIDGECTRL, & ~CBBM_BRIDGECTRL_INTR_IREQ_ISA_EN, 2); } int cbb_detach(device_t brdev) { struct cbb_softc *sc = device_get_softc(brdev); device_t *devlist; int tmp, tries, error, numdevs; /* * Before we delete the children (which we have to do because * attach doesn't check for children busses correctly), we have * to detach the children. Even if we didn't need to delete the * children, we have to detach them. */ error = bus_generic_detach(brdev); if (error != 0) return (error); /* * Since the attach routine doesn't search for children before it * attaches them to this device, we must delete them here in order * for the kldload/unload case to work. If we failed to do that, then * we'd get duplicate devices when cbb.ko was reloaded. */ tries = 10; do { error = device_get_children(brdev, &devlist, &numdevs); if (error == 0) break; /* * Try hard to cope with low memory. */ if (error == ENOMEM) { pause("cbbnomem", 1); continue; } } while (tries-- > 0); for (tmp = 0; tmp < numdevs; tmp++) device_delete_child(brdev, devlist[tmp]); free(devlist, M_TEMP); /* Turn off the interrupts */ cbb_set(sc, CBB_SOCKET_MASK, 0); /* reset 16-bit pcmcia bus */ exca_clrb(&sc->exca[0], EXCA_INTR, EXCA_INTR_RESET); /* turn off power */ cbb_power(brdev, CARD_OFF); /* Ack the interrupt */ cbb_set(sc, CBB_SOCKET_EVENT, 0xffffffff); /* * Wait for the thread to die. kproc_exit will do a wakeup * on the event thread's struct proc * so that we know it is * safe to proceed. IF the thread is running, set the please * die flag and wait for it to comply. Since the wakeup on * the event thread happens only in kproc_exit, we don't * need to loop here. */ bus_teardown_intr(brdev, sc->irq_res, sc->intrhand); mtx_lock(&sc->mtx); sc->flags |= CBB_KTHREAD_DONE; while (sc->flags & CBB_KTHREAD_RUNNING) { DEVPRINTF((sc->dev, "Waiting for thread to die\n")); wakeup(&sc->intrhand); msleep(sc->event_thread, &sc->mtx, PWAIT, "cbbun", 0); } mtx_unlock(&sc->mtx); bus_release_resource(brdev, SYS_RES_IRQ, 0, sc->irq_res); bus_release_resource(brdev, SYS_RES_MEMORY, CBBR_SOCKBASE, sc->base_res); mtx_destroy(&sc->mtx); return (0); } int cbb_setup_intr(device_t dev, device_t child, struct resource *irq, int flags, driver_filter_t *filt, driver_intr_t *intr, void *arg, void **cookiep) { struct cbb_intrhand *ih; struct cbb_softc *sc = device_get_softc(dev); int err; if (filt == NULL && intr == NULL) return (EINVAL); ih = malloc(sizeof(struct cbb_intrhand), M_DEVBUF, M_NOWAIT); if (ih == NULL) return (ENOMEM); *cookiep = ih; ih->filt = filt; ih->intr = intr; ih->arg = arg; ih->sc = sc; /* * XXX need to turn on ISA interrupts, if we ever support them, but * XXX for now that's all we need to do. */ err = BUS_SETUP_INTR(device_get_parent(dev), child, irq, flags, filt ? cbb_func_filt : NULL, intr ? cbb_func_intr : NULL, ih, &ih->cookie); if (err != 0) { free(ih, M_DEVBUF); return (err); } cbb_enable_func_intr(sc); sc->cardok = 1; return 0; } int cbb_teardown_intr(device_t dev, device_t child, struct resource *irq, void *cookie) { struct cbb_intrhand *ih; int err; /* XXX Need to do different things for ISA interrupts. */ ih = (struct cbb_intrhand *) cookie; err = BUS_TEARDOWN_INTR(device_get_parent(dev), child, irq, ih->cookie); if (err != 0) return (err); free(ih, M_DEVBUF); return (0); } void cbb_driver_added(device_t brdev, driver_t *driver) { struct cbb_softc *sc = device_get_softc(brdev); device_t *devlist; device_t dev; int tmp; int numdevs; int wake = 0; DEVICE_IDENTIFY(driver, brdev); tmp = device_get_children(brdev, &devlist, &numdevs); if (tmp != 0) { device_printf(brdev, "Cannot get children list, no reprobe\n"); return; } for (tmp = 0; tmp < numdevs; tmp++) { dev = devlist[tmp]; if (device_get_state(dev) == DS_NOTPRESENT && device_probe_and_attach(dev) == 0) wake++; } free(devlist, M_TEMP); if (wake > 0) wakeup(&sc->intrhand); } void cbb_child_detached(device_t brdev, device_t child) { struct cbb_softc *sc = device_get_softc(brdev); /* I'm not sure we even need this */ if (child != sc->cbdev && child != sc->exca[0].pccarddev) device_printf(brdev, "Unknown child detached: %s\n", device_get_nameunit(child)); } /************************************************************************/ /* Kthreads */ /************************************************************************/ void cbb_event_thread(void *arg) { struct cbb_softc *sc = arg; uint32_t status; int err; int not_a_card = 0; /* * We need to act as a power sequencer on startup. Delay 2s/channel * to ensure the other channels have had a chance to come up. We likely * should add a lock that's shared on a per-slot basis so that only * one power event can happen per slot at a time. */ pause("cbbstart", hz * device_get_unit(sc->dev) * 2); mtx_lock(&sc->mtx); sc->flags |= CBB_KTHREAD_RUNNING; while ((sc->flags & CBB_KTHREAD_DONE) == 0) { mtx_unlock(&sc->mtx); status = cbb_get(sc, CBB_SOCKET_STATE); DPRINTF(("Status is 0x%x\n", status)); if (!CBB_CARD_PRESENT(status)) { not_a_card = 0; /* We know card type */ cbb_removal(sc); } else if (status & CBB_STATE_NOT_A_CARD) { /* * Up to 10 times, try to rescan the card when we see * NOT_A_CARD. 10 is somehwat arbitrary. When this * pathology hits, there's a ~40% chance each try will * fail. 10 tries takes about 5s and results in a * 99.99% certainty of the results. */ if (not_a_card++ < 10) { DEVPRINTF((sc->dev, "Not a card bit set, rescanning\n")); cbb_setb(sc, CBB_SOCKET_FORCE, CBB_FORCE_CV_TEST); } else { device_printf(sc->dev, "Can't determine card type\n"); } } else { not_a_card = 0; /* We know card type */ cbb_insert(sc); } /* * First time through we need to tell mountroot that we're * done. */ if (sc->sc_root_token) { root_mount_rel(sc->sc_root_token); sc->sc_root_token = NULL; } /* * Wait until it has been 250ms since the last time we * get an interrupt. We handle the rest of the interrupt * at the top of the loop. Although we clear the bit in the * ISR, we signal sc->cv from the detach path after we've * set the CBB_KTHREAD_DONE bit, so we can't do a simple * 250ms sleep here. * * In our ISR, we turn off the card changed interrupt. Turn * them back on here before we wait for them to happen. We * turn them on/off so that we can tolerate a large latency * between the time we signal cbb_event_thread and it gets * a chance to run. */ mtx_lock(&sc->mtx); cbb_setb(sc, CBB_SOCKET_MASK, CBB_SOCKET_MASK_CD | CBB_SOCKET_MASK_CSTS); msleep(&sc->intrhand, &sc->mtx, 0, "-", 0); err = 0; while (err != EWOULDBLOCK && (sc->flags & CBB_KTHREAD_DONE) == 0) err = msleep(&sc->intrhand, &sc->mtx, 0, "-", hz / 5); } DEVPRINTF((sc->dev, "Thread terminating\n")); sc->flags &= ~CBB_KTHREAD_RUNNING; mtx_unlock(&sc->mtx); kproc_exit(0); } /************************************************************************/ /* Insert/removal */ /************************************************************************/ static void cbb_insert(struct cbb_softc *sc) { uint32_t sockevent, sockstate; sockevent = cbb_get(sc, CBB_SOCKET_EVENT); sockstate = cbb_get(sc, CBB_SOCKET_STATE); DEVPRINTF((sc->dev, "card inserted: event=0x%08x, state=%08x\n", sockevent, sockstate)); if (sockstate & CBB_STATE_R2_CARD) { if (device_is_attached(sc->exca[0].pccarddev)) { sc->flags |= CBB_16BIT_CARD; exca_insert(&sc->exca[0]); } else { device_printf(sc->dev, "16-bit card inserted, but no pccard bus.\n"); } } else if (sockstate & CBB_STATE_CB_CARD) { if (device_is_attached(sc->cbdev)) { sc->flags &= ~CBB_16BIT_CARD; CARD_ATTACH_CARD(sc->cbdev); } else { device_printf(sc->dev, "CardBus card inserted, but no cardbus bus.\n"); } } else { /* * We should power the card down, and try again a couple of * times if this happens. XXX */ device_printf(sc->dev, "Unsupported card type detected\n"); } } static void cbb_removal(struct cbb_softc *sc) { sc->cardok = 0; if (sc->flags & CBB_16BIT_CARD) { exca_removal(&sc->exca[0]); } else { if (device_is_attached(sc->cbdev)) CARD_DETACH_CARD(sc->cbdev); } cbb_destroy_res(sc); } /************************************************************************/ /* Interrupt Handler */ /************************************************************************/ static int cbb_func_filt(void *arg) { struct cbb_intrhand *ih = (struct cbb_intrhand *)arg; struct cbb_softc *sc = ih->sc; /* * Make sure that the card is really there. */ if (!sc->cardok) return (FILTER_STRAY); if (!CBB_CARD_PRESENT(cbb_get(sc, CBB_SOCKET_STATE))) { sc->cardok = 0; return (FILTER_HANDLED); } /* * nb: don't have to check for giant or not, since that's done in the * ISR dispatch and one can't hold Giant in a filter anyway... */ return ((*ih->filt)(ih->arg)); } static void cbb_func_intr(void *arg) { struct cbb_intrhand *ih = (struct cbb_intrhand *)arg; struct cbb_softc *sc = ih->sc; /* * While this check may seem redundant, it helps close a race * condition. If the card is ejected after the filter runs, but * before this ISR can be scheduled, then we need to do the same * filtering to prevent the card's ISR from being called. One could * argue that the card's ISR should be able to cope, but experience * has shown they can't always. This mitigates the problem by making * the race quite a bit smaller. Properly written client ISRs should * cope with the card going away in the middle of the ISR. We assume * that drivers that are sophisticated enough to use filters don't * need our protection. This also allows us to ensure they *ARE* * called if their filter said they needed to be called. */ if (ih->filt == NULL) { if (!sc->cardok) return; if (!CBB_CARD_PRESENT(cbb_get(sc, CBB_SOCKET_STATE))) { sc->cardok = 0; return; } } /* * Call the registered ithread interrupt handler. This entire routine * will be called with Giant if this isn't an MP safe driver, or not * if it is. Either way, we don't have to worry. */ ih->intr(ih->arg); } /************************************************************************/ /* Generic Power functions */ /************************************************************************/ static uint32_t cbb_detect_voltage(device_t brdev) { struct cbb_softc *sc = device_get_softc(brdev); uint32_t psr; uint32_t vol = CARD_UKN_CARD; psr = cbb_get(sc, CBB_SOCKET_STATE); if (psr & CBB_STATE_5VCARD && psr & CBB_STATE_5VSOCK) vol |= CARD_5V_CARD; if (psr & CBB_STATE_3VCARD && psr & CBB_STATE_3VSOCK) vol |= CARD_3V_CARD; if (psr & CBB_STATE_XVCARD && psr & CBB_STATE_XVSOCK) vol |= CARD_XV_CARD; if (psr & CBB_STATE_YVCARD && psr & CBB_STATE_YVSOCK) vol |= CARD_YV_CARD; return (vol); } static uint8_t cbb_o2micro_power_hack(struct cbb_softc *sc) { uint8_t reg; /* * Issue #2: INT# not qualified with IRQ Routing Bit. An * unexpected PCI INT# may be generated during PC Card * initialization even with the IRQ Routing Bit Set with some * PC Cards. * * This is a two part issue. The first part is that some of * our older controllers have an issue in which the slot's PCI * INT# is NOT qualified by the IRQ routing bit (PCI reg. 3Eh * bit 7). Regardless of the IRQ routing bit, if NO ISA IRQ * is selected (ExCA register 03h bits 3:0, of the slot, are * cleared) we will generate INT# if IREQ# is asserted. The * second part is because some PC Cards prematurally assert * IREQ# before the ExCA registers are fully programmed. This * in turn asserts INT# because ExCA register 03h bits 3:0 * (ISA IRQ Select) are not yet programmed. * * The fix for this issue, which will work for any controller * (old or new), is to set ExCA register 03h bits 3:0 = 0001b * (select IRQ1), of the slot, before turning on slot power. * Selecting IRQ1 will result in INT# NOT being asserted * (because IRQ1 is selected), and IRQ1 won't be asserted * because our controllers don't generate IRQ1. * * Other, non O2Micro controllers will generate irq 1 in some * situations, so we can't do this hack for everybody. Reports of * keyboard controller's interrupts being suppressed occurred when * we did this. */ reg = exca_getb(&sc->exca[0], EXCA_INTR); exca_putb(&sc->exca[0], EXCA_INTR, (reg & 0xf0) | 1); return (reg); } /* * Restore the damage that cbb_o2micro_power_hack does to EXCA_INTR so * we don't have an interrupt storm on power on. This has the effect of * disabling card status change interrupts for the duration of poweron. */ static void cbb_o2micro_power_hack2(struct cbb_softc *sc, uint8_t reg) { exca_putb(&sc->exca[0], EXCA_INTR, reg); } int cbb_power(device_t brdev, int volts) { uint32_t status, sock_ctrl, reg_ctrl, mask; struct cbb_softc *sc = device_get_softc(brdev); int cnt, sane; int retval = 0; int on = 0; uint8_t reg = 0; sock_ctrl = cbb_get(sc, CBB_SOCKET_CONTROL); sock_ctrl &= ~CBB_SOCKET_CTRL_VCCMASK; switch (volts & CARD_VCCMASK) { case 5: sock_ctrl |= CBB_SOCKET_CTRL_VCC_5V; on++; break; case 3: sock_ctrl |= CBB_SOCKET_CTRL_VCC_3V; on++; break; case XV: sock_ctrl |= CBB_SOCKET_CTRL_VCC_XV; on++; break; case YV: sock_ctrl |= CBB_SOCKET_CTRL_VCC_YV; on++; break; case 0: break; default: return (0); /* power NEVER changed */ } /* VPP == VCC */ sock_ctrl &= ~CBB_SOCKET_CTRL_VPPMASK; sock_ctrl |= ((sock_ctrl >> 4) & 0x07); if (cbb_get(sc, CBB_SOCKET_CONTROL) == sock_ctrl) return (1); /* no change necessary */ DEVPRINTF((sc->dev, "cbb_power: %dV\n", volts)); if (volts != 0 && sc->chipset == CB_O2MICRO) reg = cbb_o2micro_power_hack(sc); /* * We have to mask the card change detect interrupt while we're * messing with the power. It is allowed to bounce while we're * messing with power as things settle down. In addition, we mask off * the card's function interrupt by routing it via the ISA bus. This * bit generally only affects 16-bit cards. Some bridges allow one to * set another bit to have it also affect 32-bit cards. Since 32-bit * cards are required to be better behaved, we don't bother to get * into those bridge specific features. * * XXX I wonder if we need to enable the READY bit interrupt in the * EXCA CSC register for 16-bit cards, and disable the CD bit? */ mask = cbb_get(sc, CBB_SOCKET_MASK); mask |= CBB_SOCKET_MASK_POWER; mask &= ~CBB_SOCKET_MASK_CD; cbb_set(sc, CBB_SOCKET_MASK, mask); PCI_MASK_CONFIG(brdev, CBBR_BRIDGECTRL, |CBBM_BRIDGECTRL_INTR_IREQ_ISA_EN, 2); cbb_set(sc, CBB_SOCKET_CONTROL, sock_ctrl); if (on) { mtx_lock(&sc->mtx); cnt = sc->powerintr; /* * We have a shortish timeout of 500ms here. Some bridges do * not generate a POWER_CYCLE event for 16-bit cards. In * those cases, we have to cope the best we can, and having * only a short delay is better than the alternatives. Others * raise the power cycle a smidge before it is really ready. * We deal with those below. */ sane = 10; while (!(cbb_get(sc, CBB_SOCKET_STATE) & CBB_STATE_POWER_CYCLE) && cnt == sc->powerintr && sane-- > 0) msleep(&sc->powerintr, &sc->mtx, 0, "-", hz / 20); mtx_unlock(&sc->mtx); /* * Relax for 100ms. Some bridges appear to assert this signal * right away, but before the card has stabilized. Other * cards need need more time to cope up reliabily. * Experiments with troublesome setups show this to be a * "cheap" way to enhance reliabilty. We need not do this for * "off" since we don't touch the card after we turn it off. */ pause("cbbPwr", min(hz / 10, 1)); /* * The TOPIC95B requires a little bit extra time to get its * act together, so delay for an additional 100ms. Also as * documented below, it doesn't seem to set the POWER_CYCLE * bit, so don't whine if it never came on. */ if (sc->chipset == CB_TOPIC95) pause("cbb95B", hz / 10); else if (sane <= 0) device_printf(sc->dev, "power timeout, doom?\n"); } /* * After the power is good, we can turn off the power interrupt. * However, the PC Card standard says that we must delay turning the * CD bit back on for a bit to allow for bouncyness on power down * (recall that we don't wait above for a power down, since we don't * get an interrupt for that). We're called either from the suspend * code in which case we don't want to turn card change on again, or * we're called from the card insertion code, in which case the cbb * thread will turn it on for us before it waits to be woken by a * change event. * * NB: Topic95B doesn't set the power cycle bit. we assume that * both it and the TOPIC95 behave the same. */ cbb_clrb(sc, CBB_SOCKET_MASK, CBB_SOCKET_MASK_POWER); status = cbb_get(sc, CBB_SOCKET_STATE); if (on && sc->chipset != CB_TOPIC95) { if ((status & CBB_STATE_POWER_CYCLE) == 0) device_printf(sc->dev, "Power not on?\n"); } if (status & CBB_STATE_BAD_VCC_REQ) { device_printf(sc->dev, "Bad Vcc requested\n"); /* * Turn off the power, and try again. Retrigger other * active interrupts via force register. From NetBSD * PR 36652, coded by me to description there. */ sock_ctrl &= ~CBB_SOCKET_CTRL_VCCMASK; sock_ctrl &= ~CBB_SOCKET_CTRL_VPPMASK; cbb_set(sc, CBB_SOCKET_CONTROL, sock_ctrl); status &= ~CBB_STATE_BAD_VCC_REQ; status &= ~CBB_STATE_DATA_LOST; status |= CBB_FORCE_CV_TEST; cbb_set(sc, CBB_SOCKET_FORCE, status); goto done; } if (sc->chipset == CB_TOPIC97) { reg_ctrl = pci_read_config(sc->dev, TOPIC_REG_CTRL, 4); reg_ctrl &= ~TOPIC97_REG_CTRL_TESTMODE; if (on) reg_ctrl |= TOPIC97_REG_CTRL_CLKRUN_ENA; else reg_ctrl &= ~TOPIC97_REG_CTRL_CLKRUN_ENA; pci_write_config(sc->dev, TOPIC_REG_CTRL, reg_ctrl, 4); } retval = 1; done:; if (volts != 0 && sc->chipset == CB_O2MICRO) cbb_o2micro_power_hack2(sc, reg); return (retval); } static int cbb_current_voltage(device_t brdev) { struct cbb_softc *sc = device_get_softc(brdev); uint32_t ctrl; ctrl = cbb_get(sc, CBB_SOCKET_CONTROL); switch (ctrl & CBB_SOCKET_CTRL_VCCMASK) { case CBB_SOCKET_CTRL_VCC_5V: return CARD_5V_CARD; case CBB_SOCKET_CTRL_VCC_3V: return CARD_3V_CARD; case CBB_SOCKET_CTRL_VCC_XV: return CARD_XV_CARD; case CBB_SOCKET_CTRL_VCC_YV: return CARD_YV_CARD; } return 0; } /* * detect the voltage for the card, and set it. Since the power * used is the square of the voltage, lower voltages is a big win * and what Windows does (and what Microsoft prefers). The MS paper * also talks about preferring the CIS entry as well, but that has * to be done elsewhere. We also optimize power sequencing here * and don't change things if we're already powered up at a supported * voltage. * * In addition, we power up with OE disabled. We'll set it later * in the power up sequence. */ static int cbb_do_power(device_t brdev) { struct cbb_softc *sc = device_get_softc(brdev); uint32_t voltage, curpwr; uint32_t status; /* Don't enable OE (output enable) until power stable */ exca_clrb(&sc->exca[0], EXCA_PWRCTL, EXCA_PWRCTL_OE); voltage = cbb_detect_voltage(brdev); curpwr = cbb_current_voltage(brdev); status = cbb_get(sc, CBB_SOCKET_STATE); if ((status & CBB_STATE_POWER_CYCLE) && (voltage & curpwr)) return 0; /* Prefer lowest voltage supported */ cbb_power(brdev, CARD_OFF); if (voltage & CARD_YV_CARD) cbb_power(brdev, CARD_VCC(YV)); else if (voltage & CARD_XV_CARD) cbb_power(brdev, CARD_VCC(XV)); else if (voltage & CARD_3V_CARD) cbb_power(brdev, CARD_VCC(3)); else if (voltage & CARD_5V_CARD) cbb_power(brdev, CARD_VCC(5)); else { device_printf(brdev, "Unknown card voltage\n"); return (ENXIO); } return (0); } /************************************************************************/ /* CardBus power functions */ /************************************************************************/ static int cbb_cardbus_reset_power(device_t brdev, device_t child, int on) { struct cbb_softc *sc = device_get_softc(brdev); uint32_t b, h; int delay, count, zero_seen, func; /* * Asserting reset for 20ms is necessary for most bridges. For some * reason, the Ricoh RF5C47x bridges need it asserted for 400ms. The * root cause of this is unknown, and NetBSD does the same thing. */ delay = sc->chipset == CB_RF5C47X ? 400 : 20; PCI_MASK_CONFIG(brdev, CBBR_BRIDGECTRL, |CBBM_BRIDGECTRL_RESET, 2); pause("cbbP3", hz * delay / 1000); /* * If a card exists and we're turning it on, take it out of reset. * After clearing reset, wait up to 1.1s for the first configuration * register (vendor/product) configuration register of device 0.0 to * become != 0xffffffff. The PCMCIA PC Card Host System Specification * says that when powering up the card, the PCI Spec v2.1 must be * followed. In PCI spec v2.2 Table 4-6, Trhfa (Reset High to first * Config Access) is at most 2^25 clocks, or just over 1s. Section * 2.2.1 states any card not ready to participate in bus transactions * must tristate its outputs. Therefore, any access to its * configuration registers must be ignored. In that state, the config * reg will read 0xffffffff. Section 6.2.1 states a vendor id of * 0xffff is invalid, so this can never match a real card. Print a * warning if it never returns a real id. The PCMCIA PC Card * Electrical Spec Section 5.2.7.1 implies only device 0 is present on * a cardbus bus, so that's the only register we check here. */ if (on && CBB_CARD_PRESENT(cbb_get(sc, CBB_SOCKET_STATE))) { PCI_MASK_CONFIG(brdev, CBBR_BRIDGECTRL, &~CBBM_BRIDGECTRL_RESET, 2); b = pcib_get_bus(child); count = 1100 / 20; do { pause("cbbP4", hz * 2 / 100); } while (PCIB_READ_CONFIG(brdev, b, 0, 0, PCIR_DEVVENDOR, 4) == 0xfffffffful && --count >= 0); if (count < 0) device_printf(brdev, "Warning: Bus reset timeout\n"); /* * Some cards (so far just an atheros card I have) seem to * come out of reset in a funky state. They report they are * multi-function cards, but have nonsense for some of the * higher functions. So if the card claims to be MFDEV, and * any of the higher functions' ID is 0, then we've hit the * bug and we'll try again. */ h = PCIB_READ_CONFIG(brdev, b, 0, 0, PCIR_HDRTYPE, 1); if ((h & PCIM_MFDEV) == 0) return 0; zero_seen = 0; for (func = 1; func < 8; func++) { h = PCIB_READ_CONFIG(brdev, b, 0, func, PCIR_DEVVENDOR, 4); if (h == 0) zero_seen++; } if (!zero_seen) return 0; return (EINVAL); } return 0; } static int cbb_cardbus_power_disable_socket(device_t brdev, device_t child) { cbb_power(brdev, CARD_OFF); cbb_cardbus_reset_power(brdev, child, 0); return (0); } static int cbb_cardbus_power_enable_socket(device_t brdev, device_t child) { struct cbb_softc *sc = device_get_softc(brdev); int err, count; if (!CBB_CARD_PRESENT(cbb_get(sc, CBB_SOCKET_STATE))) return (ENODEV); count = 10; do { err = cbb_do_power(brdev); if (err) return (err); err = cbb_cardbus_reset_power(brdev, child, 1); if (err) { device_printf(brdev, "Reset failed, trying again.\n"); cbb_cardbus_power_disable_socket(brdev, child); pause("cbbErr1", hz / 10); /* wait 100ms */ } } while (err != 0 && count-- > 0); return (0); } /************************************************************************/ /* CardBus Resource */ /************************************************************************/ static void cbb_activate_window(device_t brdev, int type) { PCI_ENABLE_IO(device_get_parent(brdev), brdev, type); } static int cbb_cardbus_io_open(device_t brdev, int win, uint32_t start, uint32_t end) { int basereg; int limitreg; if ((win < 0) || (win > 1)) { DEVPRINTF((brdev, "cbb_cardbus_io_open: window out of range %d\n", win)); return (EINVAL); } basereg = win * 8 + CBBR_IOBASE0; limitreg = win * 8 + CBBR_IOLIMIT0; pci_write_config(brdev, basereg, start, 4); pci_write_config(brdev, limitreg, end, 4); cbb_activate_window(brdev, SYS_RES_IOPORT); return (0); } static int cbb_cardbus_mem_open(device_t brdev, int win, uint32_t start, uint32_t end) { int basereg; int limitreg; if ((win < 0) || (win > 1)) { DEVPRINTF((brdev, "cbb_cardbus_mem_open: window out of range %d\n", win)); return (EINVAL); } basereg = win * 8 + CBBR_MEMBASE0; limitreg = win * 8 + CBBR_MEMLIMIT0; pci_write_config(brdev, basereg, start, 4); pci_write_config(brdev, limitreg, end, 4); cbb_activate_window(brdev, SYS_RES_MEMORY); return (0); } #define START_NONE 0xffffffff #define END_NONE 0 static void cbb_cardbus_auto_open(struct cbb_softc *sc, int type) { uint32_t starts[2]; uint32_t ends[2]; struct cbb_reslist *rle; int align, i; uint32_t reg; starts[0] = starts[1] = START_NONE; ends[0] = ends[1] = END_NONE; if (type == SYS_RES_MEMORY) align = CBB_MEMALIGN; else if (type == SYS_RES_IOPORT) align = CBB_IOALIGN; else align = 1; SLIST_FOREACH(rle, &sc->rl, link) { if (rle->type != type) continue; if (rle->res == NULL) continue; if (!(rman_get_flags(rle->res) & RF_ACTIVE)) continue; if (rman_get_flags(rle->res) & RF_PREFETCHABLE) i = 1; else i = 0; if (rman_get_start(rle->res) < starts[i]) starts[i] = rman_get_start(rle->res); if (rman_get_end(rle->res) > ends[i]) ends[i] = rman_get_end(rle->res); } for (i = 0; i < 2; i++) { if (starts[i] == START_NONE) continue; starts[i] &= ~(align - 1); ends[i] = roundup2(ends[i], align) - 1; } if (starts[0] != START_NONE && starts[1] != START_NONE) { if (starts[0] < starts[1]) { if (ends[0] > starts[1]) { device_printf(sc->dev, "Overlapping ranges" " for prefetch and non-prefetch memory\n"); return; } } else { if (ends[1] > starts[0]) { device_printf(sc->dev, "Overlapping ranges" " for prefetch and non-prefetch memory\n"); return; } } } if (type == SYS_RES_MEMORY) { cbb_cardbus_mem_open(sc->dev, 0, starts[0], ends[0]); cbb_cardbus_mem_open(sc->dev, 1, starts[1], ends[1]); reg = pci_read_config(sc->dev, CBBR_BRIDGECTRL, 2); reg &= ~(CBBM_BRIDGECTRL_PREFETCH_0 | CBBM_BRIDGECTRL_PREFETCH_1); if (starts[1] != START_NONE) reg |= CBBM_BRIDGECTRL_PREFETCH_1; pci_write_config(sc->dev, CBBR_BRIDGECTRL, reg, 2); if (bootverbose) { device_printf(sc->dev, "Opening memory:\n"); if (starts[0] != START_NONE) device_printf(sc->dev, "Normal: %#x-%#x\n", starts[0], ends[0]); if (starts[1] != START_NONE) device_printf(sc->dev, "Prefetch: %#x-%#x\n", starts[1], ends[1]); } } else if (type == SYS_RES_IOPORT) { cbb_cardbus_io_open(sc->dev, 0, starts[0], ends[0]); cbb_cardbus_io_open(sc->dev, 1, starts[1], ends[1]); if (bootverbose && starts[0] != START_NONE) device_printf(sc->dev, "Opening I/O: %#x-%#x\n", starts[0], ends[0]); } } static int cbb_cardbus_activate_resource(device_t brdev, device_t child, int type, int rid, struct resource *res) { int ret; ret = BUS_ACTIVATE_RESOURCE(device_get_parent(brdev), child, type, rid, res); if (ret != 0) return (ret); cbb_cardbus_auto_open(device_get_softc(brdev), type); return (0); } static int cbb_cardbus_deactivate_resource(device_t brdev, device_t child, int type, int rid, struct resource *res) { int ret; ret = BUS_DEACTIVATE_RESOURCE(device_get_parent(brdev), child, type, rid, res); if (ret != 0) return (ret); cbb_cardbus_auto_open(device_get_softc(brdev), type); return (0); } static struct resource * cbb_cardbus_alloc_resource(device_t brdev, device_t child, int type, int *rid, rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) { struct cbb_softc *sc = device_get_softc(brdev); int tmp; struct resource *res; rman_res_t align; switch (type) { case SYS_RES_IRQ: tmp = rman_get_start(sc->irq_res); if (start > tmp || end < tmp || count != 1) { device_printf(child, "requested interrupt %jd-%jd," "count = %jd not supported by cbb\n", start, end, count); return (NULL); } start = end = tmp; flags |= RF_SHAREABLE; break; case SYS_RES_IOPORT: if (start <= cbb_start_32_io) start = cbb_start_32_io; if (end < start) end = start; if (count > (1 << RF_ALIGNMENT(flags))) flags = (flags & ~RF_ALIGNMENT_MASK) | rman_make_alignment_flags(count); break; case SYS_RES_MEMORY: if (start <= cbb_start_mem) start = cbb_start_mem; if (end < start) end = start; if (count < CBB_MEMALIGN) align = CBB_MEMALIGN; else align = count; if (align > (1 << RF_ALIGNMENT(flags))) flags = (flags & ~RF_ALIGNMENT_MASK) | rman_make_alignment_flags(align); break; } res = BUS_ALLOC_RESOURCE(device_get_parent(brdev), child, type, rid, start, end, count, flags & ~RF_ACTIVE); if (res == NULL) { printf("cbb alloc res fail type %d rid %x\n", type, *rid); return (NULL); } cbb_insert_res(sc, res, type, *rid); if (flags & RF_ACTIVE) if (bus_activate_resource(child, type, *rid, res) != 0) { bus_release_resource(child, type, *rid, res); return (NULL); } return (res); } static int cbb_cardbus_release_resource(device_t brdev, device_t child, int type, int rid, struct resource *res) { struct cbb_softc *sc = device_get_softc(brdev); int error; if (rman_get_flags(res) & RF_ACTIVE) { error = bus_deactivate_resource(child, type, rid, res); if (error != 0) return (error); } cbb_remove_res(sc, res); return (BUS_RELEASE_RESOURCE(device_get_parent(brdev), child, type, rid, res)); } /************************************************************************/ /* PC Card Power Functions */ /************************************************************************/ static int cbb_pcic_power_enable_socket(device_t brdev, device_t child) { struct cbb_softc *sc = device_get_softc(brdev); int err; DPRINTF(("cbb_pcic_socket_enable:\n")); /* power down/up the socket to reset */ err = cbb_do_power(brdev); if (err) return (err); exca_reset(&sc->exca[0], child); return (0); } static int cbb_pcic_power_disable_socket(device_t brdev, device_t child) { struct cbb_softc *sc = device_get_softc(brdev); DPRINTF(("cbb_pcic_socket_disable\n")); /* Turn off the card's interrupt and leave it in reset, wait 10ms */ exca_putb(&sc->exca[0], EXCA_INTR, 0); pause("cbbP1", hz / 100); /* power down the socket */ cbb_power(brdev, CARD_OFF); exca_putb(&sc->exca[0], EXCA_PWRCTL, 0); /* wait 300ms until power fails (Tpf). */ pause("cbbP2", hz * 300 / 1000); /* enable CSC interrupts */ exca_putb(&sc->exca[0], EXCA_INTR, EXCA_INTR_ENABLE); return (0); } /************************************************************************/ /* POWER methods */ /************************************************************************/ int cbb_power_enable_socket(device_t brdev, device_t child) { struct cbb_softc *sc = device_get_softc(brdev); if (sc->flags & CBB_16BIT_CARD) return (cbb_pcic_power_enable_socket(brdev, child)); return (cbb_cardbus_power_enable_socket(brdev, child)); } int cbb_power_disable_socket(device_t brdev, device_t child) { struct cbb_softc *sc = device_get_softc(brdev); if (sc->flags & CBB_16BIT_CARD) return (cbb_pcic_power_disable_socket(brdev, child)); return (cbb_cardbus_power_disable_socket(brdev, child)); } static int cbb_pcic_activate_resource(device_t brdev, device_t child, int type, int rid, struct resource *res) { struct cbb_softc *sc = device_get_softc(brdev); int error; error = exca_activate_resource(&sc->exca[0], child, type, rid, res); if (error == 0) cbb_activate_window(brdev, type); return (error); } static int cbb_pcic_deactivate_resource(device_t brdev, device_t child, int type, int rid, struct resource *res) { struct cbb_softc *sc = device_get_softc(brdev); return (exca_deactivate_resource(&sc->exca[0], child, type, rid, res)); } static struct resource * cbb_pcic_alloc_resource(device_t brdev, device_t child, int type, int *rid, rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) { struct resource *res = NULL; struct cbb_softc *sc = device_get_softc(brdev); int align; int tmp; switch (type) { case SYS_RES_MEMORY: if (start < cbb_start_mem) start = cbb_start_mem; if (end < start) end = start; if (count < CBB_MEMALIGN) align = CBB_MEMALIGN; else align = count; if (align > (1 << RF_ALIGNMENT(flags))) flags = (flags & ~RF_ALIGNMENT_MASK) | rman_make_alignment_flags(align); break; case SYS_RES_IOPORT: if (start < cbb_start_16_io) start = cbb_start_16_io; if (end < start) end = start; break; case SYS_RES_IRQ: tmp = rman_get_start(sc->irq_res); if (start > tmp || end < tmp || count != 1) { device_printf(child, "requested interrupt %jd-%jd," "count = %jd not supported by cbb\n", start, end, count); return (NULL); } flags |= RF_SHAREABLE; start = end = rman_get_start(sc->irq_res); break; } res = BUS_ALLOC_RESOURCE(device_get_parent(brdev), child, type, rid, start, end, count, flags & ~RF_ACTIVE); if (res == NULL) return (NULL); cbb_insert_res(sc, res, type, *rid); if (flags & RF_ACTIVE) { if (bus_activate_resource(child, type, *rid, res) != 0) { bus_release_resource(child, type, *rid, res); return (NULL); } } return (res); } static int cbb_pcic_release_resource(device_t brdev, device_t child, int type, int rid, struct resource *res) { struct cbb_softc *sc = device_get_softc(brdev); int error; if (rman_get_flags(res) & RF_ACTIVE) { error = bus_deactivate_resource(child, type, rid, res); if (error != 0) return (error); } cbb_remove_res(sc, res); return (BUS_RELEASE_RESOURCE(device_get_parent(brdev), child, type, rid, res)); } /************************************************************************/ /* PC Card methods */ /************************************************************************/ int cbb_pcic_set_res_flags(device_t brdev, device_t child, int type, int rid, u_long flags) { struct cbb_softc *sc = device_get_softc(brdev); struct resource *res; if (type != SYS_RES_MEMORY) return (EINVAL); res = cbb_find_res(sc, type, rid); if (res == NULL) { device_printf(brdev, "set_res_flags: specified rid not found\n"); return (ENOENT); } return (exca_mem_set_flags(&sc->exca[0], res, flags)); } int cbb_pcic_set_memory_offset(device_t brdev, device_t child, int rid, uint32_t cardaddr, uint32_t *deltap) { struct cbb_softc *sc = device_get_softc(brdev); struct resource *res; res = cbb_find_res(sc, SYS_RES_MEMORY, rid); if (res == NULL) { device_printf(brdev, "set_memory_offset: specified rid not found\n"); return (ENOENT); } return (exca_mem_set_offset(&sc->exca[0], res, cardaddr, deltap)); } /************************************************************************/ /* BUS Methods */ /************************************************************************/ int cbb_activate_resource(device_t brdev, device_t child, int type, int rid, struct resource *r) { struct cbb_softc *sc = device_get_softc(brdev); if (sc->flags & CBB_16BIT_CARD) return (cbb_pcic_activate_resource(brdev, child, type, rid, r)); else return (cbb_cardbus_activate_resource(brdev, child, type, rid, r)); } int cbb_deactivate_resource(device_t brdev, device_t child, int type, int rid, struct resource *r) { struct cbb_softc *sc = device_get_softc(brdev); if (sc->flags & CBB_16BIT_CARD) return (cbb_pcic_deactivate_resource(brdev, child, type, rid, r)); else return (cbb_cardbus_deactivate_resource(brdev, child, type, rid, r)); } struct resource * cbb_alloc_resource(device_t brdev, device_t child, int type, int *rid, rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) { struct cbb_softc *sc = device_get_softc(brdev); if (sc->flags & CBB_16BIT_CARD) return (cbb_pcic_alloc_resource(brdev, child, type, rid, start, end, count, flags)); else return (cbb_cardbus_alloc_resource(brdev, child, type, rid, start, end, count, flags)); } int cbb_release_resource(device_t brdev, device_t child, int type, int rid, struct resource *r) { struct cbb_softc *sc = device_get_softc(brdev); if (sc->flags & CBB_16BIT_CARD) return (cbb_pcic_release_resource(brdev, child, type, rid, r)); else return (cbb_cardbus_release_resource(brdev, child, type, rid, r)); } int cbb_read_ivar(device_t brdev, device_t child, int which, uintptr_t *result) { struct cbb_softc *sc = device_get_softc(brdev); switch (which) { case PCIB_IVAR_DOMAIN: *result = sc->domain; return (0); case PCIB_IVAR_BUS: *result = sc->bus.sec; return (0); } return (ENOENT); } int cbb_write_ivar(device_t brdev, device_t child, int which, uintptr_t value) { switch (which) { case PCIB_IVAR_DOMAIN: return (EINVAL); case PCIB_IVAR_BUS: return (EINVAL); } return (ENOENT); } int cbb_child_present(device_t parent, device_t child) { struct cbb_softc *sc = (struct cbb_softc *)device_get_softc(parent); uint32_t sockstate; sockstate = cbb_get(sc, CBB_SOCKET_STATE); return (CBB_CARD_PRESENT(sockstate) && sc->cardok); } Index: head/sys/dev/pccbb/pccbb_isa.c =================================================================== --- head/sys/dev/pccbb/pccbb_isa.c (revision 355393) +++ head/sys/dev/pccbb/pccbb_isa.c (revision 355394) @@ -1,257 +1,256 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2002-2004 M. Warner Losh. - * All rights reserved. + * Copyright (c) 2002-2004 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Driver for ISA to PCMCIA bridges compliant with the Intel ExCA * specification. */ #include __FBSDID("$FreeBSD$"); #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 "power_if.h" #include "card_if.h" /***************************************************************************** * Configurable parameters. *****************************************************************************/ /* sysctl vars */ static SYSCTL_NODE(_hw, OID_AUTO, pcic, CTLFLAG_RD, 0, "PCIC parameters"); static int isa_intr_mask = EXCA_INT_MASK_ALLOWED; SYSCTL_INT(_hw_pcic, OID_AUTO, intr_mask, CTLFLAG_RDTUN, &isa_intr_mask, 0, "Mask of allowable interrupts for this laptop. The default is generally" " correct, but some laptops do not route all the IRQ pins to the bridge to" " save wires. Sometimes you need a more restrictive mask because some of" " the hardware in your laptop may not have a driver so its IRQ might not be" " allocated."); /* * CL-PD6722's VSENSE method * 0: NO VSENSE (assume a 5.0V card always) * 1: 6710's method (default) * 2: 6729's method */ int pcic_pd6722_vsense = 1; SYSCTL_INT(_hw_pcic, OID_AUTO, pd6722_vsense, CTLFLAG_RDTUN, &pcic_pd6722_vsense, 1, "Select CL-PD6722's VSENSE method. VSENSE is used to determine the" " voltage of inserted cards. The CL-PD6722 has two methods to determine" " the voltage of the card. 0 means assume a 5.0V card and do not check. 1" " means use the same method that the CL-PD6710 uses (default). 2 means use" " the same method as the CL-PD6729. 2 is documented in the datasheet as" " being the correct way, but 1 seems to give better results on more" " laptops."); /***************************************************************************** * End of configurable parameters. *****************************************************************************/ #define DPRINTF(x) do { if (cbb_debug) printf x; } while (0) #define DEVPRINTF(x) do { if (cbb_debug) device_printf x; } while (0) static struct isa_pnp_id pcic_ids[] = { {EXCA_PNP_ACTIONTEC, NULL}, /* AEI0218 */ {EXCA_PNP_IBM3765, NULL}, /* IBM3765 */ {EXCA_PNP_82365, NULL}, /* PNP0E00 */ {EXCA_PNP_CL_PD6720, NULL}, /* PNP0E01 */ {EXCA_PNP_VLSI_82C146, NULL}, /* PNP0E02 */ {EXCA_PNP_82365_CARDBUS, NULL}, /* PNP0E03 */ {EXCA_PNP_SCM_SWAPBOX, NULL}, /* SCM0469 */ {0} }; /************************************************************************/ /* Probe/Attach */ /************************************************************************/ static int cbb_isa_activate(device_t dev) { struct cbb_softc *sc = device_get_softc(dev); struct resource *res; int rid; int i; /* A little bogus, but go ahead and get the irq for CSC events */ rid = 0; res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE); if (res == NULL) { /* * No IRQ specified, find one. This can be due to the PnP * data not specifying any IRQ, or the default kernel not * assinging an IRQ. */ for (i = 0; i < 16 && res == NULL; i++) { if (((1 << i) & isa_intr_mask) == 0) continue; res = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, i, i, 1, RF_ACTIVE); } } if (res == NULL) return (ENXIO); sc->irq_res = res; rid = 0; res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, RF_ACTIVE); if (res == NULL) { bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res); sc->irq_res = NULL; device_printf(dev, "Cannot allocate I/O\n"); return (ENOMEM); } sc->bst = rman_get_bustag(res); sc->bsh = rman_get_bushandle(res); sc->base_res = res; return (0); } static void cbb_isa_deactivate(device_t dev) { struct cbb_softc *sc = device_get_softc(dev); if (sc->irq_res) bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res); sc->irq_res = NULL; if (sc->base_res) bus_release_resource(dev, SYS_RES_IOPORT, 0, sc->base_res); sc->base_res = NULL; } static int cbb_isa_probe(device_t dev) { int error; struct cbb_softc *sc = device_get_softc(dev); /* Check isapnp ids */ error = ISA_PNP_PROBE(device_get_parent(dev), dev, pcic_ids); if (error != 0 && error != ENOENT) return (error); error = cbb_isa_activate(dev); if (error != 0) return (error); /* Check to make sure that we have actual hardware */ error = exca_probe_slots(dev, &sc->exca[0], sc->bst, sc->bsh); cbb_isa_deactivate(dev); return (error); } static int cbb_isa_attach(device_t dev) { return (ENOMEM); } static int cbb_isa_suspend(device_t dev) { return (0); } static int cbb_isa_resume(device_t dev) { return (0); } static device_method_t cbb_methods[] = { /* Device interface */ DEVMETHOD(device_probe, cbb_isa_probe), DEVMETHOD(device_attach, cbb_isa_attach), DEVMETHOD(device_detach, cbb_detach), DEVMETHOD(device_suspend, cbb_isa_suspend), DEVMETHOD(device_resume, cbb_isa_resume), /* bus methods */ DEVMETHOD(bus_read_ivar, cbb_read_ivar), DEVMETHOD(bus_write_ivar, cbb_write_ivar), DEVMETHOD(bus_alloc_resource, cbb_alloc_resource), DEVMETHOD(bus_release_resource, cbb_release_resource), DEVMETHOD(bus_activate_resource, cbb_activate_resource), DEVMETHOD(bus_deactivate_resource, cbb_deactivate_resource), DEVMETHOD(bus_driver_added, cbb_driver_added), DEVMETHOD(bus_child_detached, cbb_child_detached), DEVMETHOD(bus_setup_intr, cbb_setup_intr), DEVMETHOD(bus_teardown_intr, cbb_teardown_intr), DEVMETHOD(bus_child_present, cbb_child_present), /* 16-bit card interface */ DEVMETHOD(card_set_res_flags, cbb_pcic_set_res_flags), DEVMETHOD(card_set_memory_offset, cbb_pcic_set_memory_offset), /* power interface */ DEVMETHOD(power_enable_socket, cbb_power_enable_socket), DEVMETHOD(power_disable_socket, cbb_power_disable_socket), DEVMETHOD_END }; static driver_t cbb_isa_driver = { "cbb", cbb_methods, sizeof(struct cbb_softc) }; DRIVER_MODULE(cbb, isa, cbb_isa_driver, cbb_devclass, 0, 0); MODULE_DEPEND(cbb, exca, 1, 1, 1); ISA_PNP_INFO(pcic_ids); Index: head/sys/dev/pccbb/pccbb_pci.c =================================================================== --- head/sys/dev/pccbb/pccbb_pci.c (revision 355393) +++ head/sys/dev/pccbb/pccbb_pci.c (revision 355394) @@ -1,988 +1,987 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2002-2004 M. Warner Losh. - * Copyright (c) 2000-2001 Jonathan Chen. - * All rights reserved. + * Copyright (c) 2000-2001 Jonathan Chen All rights reserved. + * Copyright (c) 2002-2004 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ /*- * Copyright (c) 1998, 1999 and 2000 * HAYAKAWA Koichi. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by HAYAKAWA Koichi. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Driver for PCI to CardBus Bridge chips * * References: * TI Datasheets: * http://www-s.ti.com/cgi-bin/sc/generic2.cgi?family=PCI+CARDBUS+CONTROLLERS * * Written by Jonathan Chen * The author would like to acknowledge: * * HAYAKAWA Koichi: Author of the NetBSD code for the same thing * * Warner Losh: Newbus/newcard guru and author of the pccard side of things * * YAMAMOTO Shigeru: Author of another FreeBSD cardbus driver * * David Cross: Author of the initial ugly hack for a specific cardbus card */ #include __FBSDID("$FreeBSD$"); #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 "power_if.h" #include "card_if.h" #include "pcib_if.h" #define DPRINTF(x) do { if (cbb_debug) printf x; } while (0) #define DEVPRINTF(x) do { if (cbb_debug) device_printf x; } while (0) #define PCI_MASK_CONFIG(DEV,REG,MASK,SIZE) \ pci_write_config(DEV, REG, pci_read_config(DEV, REG, SIZE) MASK, SIZE) #define PCI_MASK2_CONFIG(DEV,REG,MASK1,MASK2,SIZE) \ pci_write_config(DEV, REG, ( \ pci_read_config(DEV, REG, SIZE) MASK1) MASK2, SIZE) static void cbb_chipinit(struct cbb_softc *sc); static int cbb_pci_filt(void *arg); static struct yenta_chipinfo { uint32_t yc_id; const char *yc_name; int yc_chiptype; } yc_chipsets[] = { /* Texas Instruments chips */ {PCIC_ID_TI1031, "TI1031 PCI-PC Card Bridge", CB_TI113X}, {PCIC_ID_TI1130, "TI1130 PCI-CardBus Bridge", CB_TI113X}, {PCIC_ID_TI1131, "TI1131 PCI-CardBus Bridge", CB_TI113X}, {PCIC_ID_TI1210, "TI1210 PCI-CardBus Bridge", CB_TI12XX}, {PCIC_ID_TI1211, "TI1211 PCI-CardBus Bridge", CB_TI12XX}, {PCIC_ID_TI1220, "TI1220 PCI-CardBus Bridge", CB_TI12XX}, {PCIC_ID_TI1221, "TI1221 PCI-CardBus Bridge", CB_TI12XX}, {PCIC_ID_TI1225, "TI1225 PCI-CardBus Bridge", CB_TI12XX}, {PCIC_ID_TI1250, "TI1250 PCI-CardBus Bridge", CB_TI125X}, {PCIC_ID_TI1251, "TI1251 PCI-CardBus Bridge", CB_TI125X}, {PCIC_ID_TI1251B,"TI1251B PCI-CardBus Bridge",CB_TI125X}, {PCIC_ID_TI1260, "TI1260 PCI-CardBus Bridge", CB_TI12XX}, {PCIC_ID_TI1260B,"TI1260B PCI-CardBus Bridge",CB_TI12XX}, {PCIC_ID_TI1410, "TI1410 PCI-CardBus Bridge", CB_TI12XX}, {PCIC_ID_TI1420, "TI1420 PCI-CardBus Bridge", CB_TI12XX}, {PCIC_ID_TI1421, "TI1421 PCI-CardBus Bridge", CB_TI12XX}, {PCIC_ID_TI1450, "TI1450 PCI-CardBus Bridge", CB_TI125X}, /*SIC!*/ {PCIC_ID_TI1451, "TI1451 PCI-CardBus Bridge", CB_TI12XX}, {PCIC_ID_TI1510, "TI1510 PCI-CardBus Bridge", CB_TI12XX}, {PCIC_ID_TI1520, "TI1520 PCI-CardBus Bridge", CB_TI12XX}, {PCIC_ID_TI4410, "TI4410 PCI-CardBus Bridge", CB_TI12XX}, {PCIC_ID_TI4450, "TI4450 PCI-CardBus Bridge", CB_TI12XX}, {PCIC_ID_TI4451, "TI4451 PCI-CardBus Bridge", CB_TI12XX}, {PCIC_ID_TI4510, "TI4510 PCI-CardBus Bridge", CB_TI12XX}, {PCIC_ID_TI6411, "TI6411 PCI-CardBus Bridge", CB_TI12XX}, {PCIC_ID_TI6420, "TI6420 PCI-CardBus Bridge", CB_TI12XX}, {PCIC_ID_TI6420SC, "TI6420 PCI-CardBus Bridge", CB_TI12XX}, {PCIC_ID_TI7410, "TI7410 PCI-CardBus Bridge", CB_TI12XX}, {PCIC_ID_TI7510, "TI7510 PCI-CardBus Bridge", CB_TI12XX}, {PCIC_ID_TI7610, "TI7610 PCI-CardBus Bridge", CB_TI12XX}, {PCIC_ID_TI7610M, "TI7610 PCI-CardBus Bridge", CB_TI12XX}, {PCIC_ID_TI7610SD, "TI7610 PCI-CardBus Bridge", CB_TI12XX}, {PCIC_ID_TI7610MS, "TI7610 PCI-CardBus Bridge", CB_TI12XX}, /* ENE */ {PCIC_ID_ENE_CB710, "ENE CB710 PCI-CardBus Bridge", CB_TI12XX}, {PCIC_ID_ENE_CB720, "ENE CB720 PCI-CardBus Bridge", CB_TI12XX}, {PCIC_ID_ENE_CB1211, "ENE CB1211 PCI-CardBus Bridge", CB_TI12XX}, {PCIC_ID_ENE_CB1225, "ENE CB1225 PCI-CardBus Bridge", CB_TI12XX}, {PCIC_ID_ENE_CB1410, "ENE CB1410 PCI-CardBus Bridge", CB_TI12XX}, {PCIC_ID_ENE_CB1420, "ENE CB1420 PCI-CardBus Bridge", CB_TI12XX}, /* Ricoh chips */ {PCIC_ID_RICOH_RL5C465, "RF5C465 PCI-CardBus Bridge", CB_RF5C46X}, {PCIC_ID_RICOH_RL5C466, "RF5C466 PCI-CardBus Bridge", CB_RF5C46X}, {PCIC_ID_RICOH_RL5C475, "RF5C475 PCI-CardBus Bridge", CB_RF5C47X}, {PCIC_ID_RICOH_RL5C476, "RF5C476 PCI-CardBus Bridge", CB_RF5C47X}, {PCIC_ID_RICOH_RL5C477, "RF5C477 PCI-CardBus Bridge", CB_RF5C47X}, {PCIC_ID_RICOH_RL5C478, "RF5C478 PCI-CardBus Bridge", CB_RF5C47X}, /* Toshiba products */ {PCIC_ID_TOPIC95, "ToPIC95 PCI-CardBus Bridge", CB_TOPIC95}, {PCIC_ID_TOPIC95B, "ToPIC95B PCI-CardBus Bridge", CB_TOPIC95}, {PCIC_ID_TOPIC97, "ToPIC97 PCI-CardBus Bridge", CB_TOPIC97}, {PCIC_ID_TOPIC100, "ToPIC100 PCI-CardBus Bridge", CB_TOPIC97}, /* Cirrus Logic */ {PCIC_ID_CLPD6832, "CLPD6832 PCI-CardBus Bridge", CB_CIRRUS}, {PCIC_ID_CLPD6833, "CLPD6833 PCI-CardBus Bridge", CB_CIRRUS}, {PCIC_ID_CLPD6834, "CLPD6834 PCI-CardBus Bridge", CB_CIRRUS}, /* 02Micro */ {PCIC_ID_OZ6832, "O2Micro OZ6832/6833 PCI-CardBus Bridge", CB_O2MICRO}, {PCIC_ID_OZ6860, "O2Micro OZ6836/6860 PCI-CardBus Bridge", CB_O2MICRO}, {PCIC_ID_OZ6872, "O2Micro OZ6812/6872 PCI-CardBus Bridge", CB_O2MICRO}, {PCIC_ID_OZ6912, "O2Micro OZ6912/6972 PCI-CardBus Bridge", CB_O2MICRO}, {PCIC_ID_OZ6922, "O2Micro OZ6922 PCI-CardBus Bridge", CB_O2MICRO}, {PCIC_ID_OZ6933, "O2Micro OZ6933 PCI-CardBus Bridge", CB_O2MICRO}, {PCIC_ID_OZ711E1, "O2Micro OZ711E1 PCI-CardBus Bridge", CB_O2MICRO}, {PCIC_ID_OZ711EC1, "O2Micro OZ711EC1/M1 PCI-CardBus Bridge", CB_O2MICRO}, {PCIC_ID_OZ711E2, "O2Micro OZ711E2 PCI-CardBus Bridge", CB_O2MICRO}, {PCIC_ID_OZ711M1, "O2Micro OZ711M1 PCI-CardBus Bridge", CB_O2MICRO}, {PCIC_ID_OZ711M2, "O2Micro OZ711M2 PCI-CardBus Bridge", CB_O2MICRO}, {PCIC_ID_OZ711M3, "O2Micro OZ711M3 PCI-CardBus Bridge", CB_O2MICRO}, /* SMC */ {PCIC_ID_SMC_34C90, "SMC 34C90 PCI-CardBus Bridge", CB_CIRRUS}, /* sentinel */ {0 /* null id */, "unknown", CB_UNKNOWN}, }; /************************************************************************/ /* Probe/Attach */ /************************************************************************/ static int cbb_chipset(uint32_t pci_id, const char **namep) { struct yenta_chipinfo *ycp; for (ycp = yc_chipsets; ycp->yc_id != 0 && pci_id != ycp->yc_id; ++ycp) continue; if (namep != NULL) *namep = ycp->yc_name; return (ycp->yc_chiptype); } static int cbb_pci_probe(device_t brdev) { const char *name; uint32_t progif; uint32_t baseclass; uint32_t subclass; /* * Do we know that we support the chipset? If so, then we * accept the device. */ if (cbb_chipset(pci_get_devid(brdev), &name) != CB_UNKNOWN) { device_set_desc(brdev, name); return (BUS_PROBE_DEFAULT); } /* * We do support generic CardBus bridges. All that we've seen * to date have progif 0 (the Yenta spec, and successors mandate * this). */ baseclass = pci_get_class(brdev); subclass = pci_get_subclass(brdev); progif = pci_get_progif(brdev); if (baseclass == PCIC_BRIDGE && subclass == PCIS_BRIDGE_CARDBUS && progif == 0) { device_set_desc(brdev, "PCI-CardBus Bridge"); return (BUS_PROBE_GENERIC); } return (ENXIO); } /* * Print out the config space */ static void cbb_print_config(device_t dev) { int i; device_printf(dev, "PCI Configuration space:"); for (i = 0; i < 256; i += 4) { if (i % 16 == 0) printf("\n 0x%02x: ", i); printf("0x%08x ", pci_read_config(dev, i, 4)); } printf("\n"); } static int cbb_pci_attach(device_t brdev) { #if !(defined(NEW_PCIB) && defined(PCI_RES_BUS)) static int curr_bus_number = 2; /* XXX EVILE BAD (see below) */ uint32_t pribus; #endif struct cbb_softc *sc = (struct cbb_softc *)device_get_softc(brdev); struct sysctl_ctx_list *sctx; struct sysctl_oid *soid; int rid; device_t parent; parent = device_get_parent(brdev); mtx_init(&sc->mtx, device_get_nameunit(brdev), "cbb", MTX_DEF); sc->chipset = cbb_chipset(pci_get_devid(brdev), NULL); sc->dev = brdev; sc->cbdev = NULL; sc->exca[0].pccarddev = NULL; sc->domain = pci_get_domain(brdev); sc->pribus = pcib_get_bus(parent); #if defined(NEW_PCIB) && defined(PCI_RES_BUS) pci_write_config(brdev, PCIR_PRIBUS_2, sc->pribus, 1); pcib_setup_secbus(brdev, &sc->bus, 1); #else sc->bus.sec = pci_read_config(brdev, PCIR_SECBUS_2, 1); sc->bus.sub = pci_read_config(brdev, PCIR_SUBBUS_2, 1); #endif SLIST_INIT(&sc->rl); rid = CBBR_SOCKBASE; sc->base_res = bus_alloc_resource_any(brdev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (!sc->base_res) { device_printf(brdev, "Could not map register memory\n"); mtx_destroy(&sc->mtx); return (ENOMEM); } else { DEVPRINTF((brdev, "Found memory at %jx\n", rman_get_start(sc->base_res))); } sc->bst = rman_get_bustag(sc->base_res); sc->bsh = rman_get_bushandle(sc->base_res); exca_init(&sc->exca[0], brdev, sc->bst, sc->bsh, CBB_EXCA_OFFSET); sc->exca[0].flags |= EXCA_HAS_MEMREG_WIN; sc->exca[0].chipset = EXCA_CARDBUS; sc->chipinit = cbb_chipinit; sc->chipinit(sc); /*Sysctls*/ sctx = device_get_sysctl_ctx(brdev); soid = device_get_sysctl_tree(brdev); SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "domain", CTLFLAG_RD, &sc->domain, 0, "Domain number"); SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "pribus", CTLFLAG_RD, &sc->pribus, 0, "Primary bus number"); SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "secbus", CTLFLAG_RD, &sc->bus.sec, 0, "Secondary bus number"); SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "subbus", CTLFLAG_RD, &sc->bus.sub, 0, "Subordinate bus number"); #if 0 SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "memory", CTLFLAG_RD, &sc->subbus, 0, "Memory window open"); SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "premem", CTLFLAG_RD, &sc->subbus, 0, "Prefetch memory window open"); SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "io1", CTLFLAG_RD, &sc->subbus, 0, "io range 1 open"); SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "io2", CTLFLAG_RD, &sc->subbus, 0, "io range 2 open"); #endif #if !(defined(NEW_PCIB) && defined(PCI_RES_BUS)) /* * This is a gross hack. We should be scanning the entire pci * tree, assigning bus numbers in a way such that we (1) can * reserve 1 extra bus just in case and (2) all sub buses * are in an appropriate range. */ DEVPRINTF((brdev, "Secondary bus is %d\n", sc->bus.sec)); pribus = pci_read_config(brdev, PCIR_PRIBUS_2, 1); if (sc->bus.sec == 0 || sc->pribus != pribus) { if (curr_bus_number <= sc->pribus) curr_bus_number = sc->pribus + 1; if (pribus != sc->pribus) { DEVPRINTF((brdev, "Setting primary bus to %d\n", sc->pribus)); pci_write_config(brdev, PCIR_PRIBUS_2, sc->pribus, 1); } sc->bus.sec = curr_bus_number++; sc->bus.sub = curr_bus_number++; DEVPRINTF((brdev, "Secondary bus set to %d subbus %d\n", sc->bus.sec, sc->bus.sub)); pci_write_config(brdev, PCIR_SECBUS_2, sc->bus.sec, 1); pci_write_config(brdev, PCIR_SUBBUS_2, sc->bus.sub, 1); } #endif /* attach children */ sc->cbdev = device_add_child(brdev, "cardbus", -1); if (sc->cbdev == NULL) DEVPRINTF((brdev, "WARNING: cannot add cardbus bus.\n")); else if (device_probe_and_attach(sc->cbdev) != 0) DEVPRINTF((brdev, "WARNING: cannot attach cardbus bus!\n")); sc->exca[0].pccarddev = device_add_child(brdev, "pccard", -1); if (sc->exca[0].pccarddev == NULL) DEVPRINTF((brdev, "WARNING: cannot add pccard bus.\n")); else if (device_probe_and_attach(sc->exca[0].pccarddev) != 0) DEVPRINTF((brdev, "WARNING: cannot attach pccard bus.\n")); /* Map and establish the interrupt. */ rid = 0; sc->irq_res = bus_alloc_resource_any(brdev, SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE); if (sc->irq_res == NULL) { device_printf(brdev, "Unable to map IRQ...\n"); goto err; } if (bus_setup_intr(brdev, sc->irq_res, INTR_TYPE_AV | INTR_MPSAFE, cbb_pci_filt, NULL, sc, &sc->intrhand)) { device_printf(brdev, "couldn't establish interrupt\n"); goto err; } /* reset 16-bit pcmcia bus */ exca_clrb(&sc->exca[0], EXCA_INTR, EXCA_INTR_RESET); /* turn off power */ cbb_power(brdev, CARD_OFF); /* CSC Interrupt: Card detect interrupt on */ cbb_setb(sc, CBB_SOCKET_MASK, CBB_SOCKET_MASK_CD); /* reset interrupt */ cbb_set(sc, CBB_SOCKET_EVENT, cbb_get(sc, CBB_SOCKET_EVENT)); if (bootverbose) cbb_print_config(brdev); /* Start the thread */ if (kproc_create(cbb_event_thread, sc, &sc->event_thread, 0, 0, "%s event thread", device_get_nameunit(brdev))) { device_printf(brdev, "unable to create event thread.\n"); panic("cbb_create_event_thread"); } sc->sc_root_token = root_mount_hold(device_get_nameunit(sc->dev)); return (0); err: if (sc->irq_res) bus_release_resource(brdev, SYS_RES_IRQ, 0, sc->irq_res); if (sc->base_res) { bus_release_resource(brdev, SYS_RES_MEMORY, CBBR_SOCKBASE, sc->base_res); } mtx_destroy(&sc->mtx); return (ENOMEM); } static int cbb_pci_detach(device_t brdev) { #if defined(NEW_PCIB) && defined(PCI_RES_BUS) struct cbb_softc *sc = device_get_softc(brdev); #endif int error; error = cbb_detach(brdev); #if defined(NEW_PCIB) && defined(PCI_RES_BUS) if (error == 0) pcib_free_secbus(brdev, &sc->bus); #endif return (error); } static void cbb_chipinit(struct cbb_softc *sc) { uint32_t mux, sysctrl, reg; /* Set CardBus latency timer */ if (pci_read_config(sc->dev, PCIR_SECLAT_2, 1) < 0x20) pci_write_config(sc->dev, PCIR_SECLAT_2, 0x20, 1); /* Set PCI latency timer */ if (pci_read_config(sc->dev, PCIR_LATTIMER, 1) < 0x20) pci_write_config(sc->dev, PCIR_LATTIMER, 0x20, 1); /* Enable DMA, memory access for this card and I/O access for children */ pci_enable_busmaster(sc->dev); pci_enable_io(sc->dev, SYS_RES_IOPORT); pci_enable_io(sc->dev, SYS_RES_MEMORY); /* disable Legacy IO */ switch (sc->chipset) { case CB_RF5C46X: PCI_MASK_CONFIG(sc->dev, CBBR_BRIDGECTRL, & ~(CBBM_BRIDGECTRL_RL_3E0_EN | CBBM_BRIDGECTRL_RL_3E2_EN), 2); break; default: pci_write_config(sc->dev, CBBR_LEGACY, 0x0, 4); break; } /* Use PCI interrupt for interrupt routing */ PCI_MASK2_CONFIG(sc->dev, CBBR_BRIDGECTRL, & ~(CBBM_BRIDGECTRL_MASTER_ABORT | CBBM_BRIDGECTRL_INTR_IREQ_ISA_EN), | CBBM_BRIDGECTRL_WRITE_POST_EN, 2); /* * XXX this should be a function table, ala OLDCARD. This means * that we could more easily support ISA interrupts for pccard * cards if we had to. */ switch (sc->chipset) { case CB_TI113X: /* * The TI 1031, TI 1130 and TI 1131 all require another bit * be set to enable PCI routing of interrupts, and then * a bit for each of the CSC and Function interrupts we * want routed. */ PCI_MASK_CONFIG(sc->dev, CBBR_CBCTRL, | CBBM_CBCTRL_113X_PCI_INTR | CBBM_CBCTRL_113X_PCI_CSC | CBBM_CBCTRL_113X_PCI_IRQ_EN, 1); PCI_MASK_CONFIG(sc->dev, CBBR_DEVCTRL, & ~(CBBM_DEVCTRL_INT_SERIAL | CBBM_DEVCTRL_INT_PCI), 1); break; case CB_TI12XX: /* * Some TI 12xx (and [14][45]xx) based pci cards * sometimes have issues with the MFUNC register not * being initialized due to a bad EEPROM on board. * Laptops that this matters on have this register * properly initialized. * * The TI125X parts have a different register. * * Note: Only the lower two nibbles matter. When set * to 0, the MFUNC{0,1} pins are GPIO, which isn't * going to work out too well because we specifically * program these parts to parallel interrupt signalling * elsewhere. We preserve the upper bits of this * register since changing them have subtle side effects * for different variants of the card and are * extremely difficult to exaustively test. * * Also, the TI 1510/1520 changed the default for the MFUNC * register from 0x0 to 0x1000 to enable IRQSER by default. * We want to be careful to avoid overriding that, and the * below test will do that. Should this check prove to be * too permissive, we should just check against 0 and 0x1000 * and not touch it otherwise. */ mux = pci_read_config(sc->dev, CBBR_MFUNC, 4); sysctrl = pci_read_config(sc->dev, CBBR_SYSCTRL, 4); if ((mux & (CBBM_MFUNC_PIN0 | CBBM_MFUNC_PIN1)) == 0) { mux = (mux & ~CBBM_MFUNC_PIN0) | CBBM_MFUNC_PIN0_INTA; if ((sysctrl & CBBM_SYSCTRL_INTRTIE) == 0) mux = (mux & ~CBBM_MFUNC_PIN1) | CBBM_MFUNC_PIN1_INTB; pci_write_config(sc->dev, CBBR_MFUNC, mux, 4); } /*FALLTHROUGH*/ case CB_TI125X: /* * Disable zoom video. Some machines initialize this * improperly and exerpience has shown that this helps * prevent strange behavior. We don't support zoom * video anyway, so no harm can come from this. */ pci_write_config(sc->dev, CBBR_MMCTRL, 0, 4); break; case CB_O2MICRO: /* * Issue #1: INT# generated at the same time as * selected ISA IRQ. When IREQ# or STSCHG# is active, * in addition to the ISA IRQ being generated, INT# * will also be generated at the same time. * * Some of the older controllers have an issue in * which the slot's PCI INT# will be asserted whenever * IREQ# or STSCGH# is asserted even if ExCA registers * 03h or 05h have an ISA IRQ selected. * * The fix for this issue, which will work for any * controller (old or new), is to set ExCA registers * 3Ah (slot 0) & 7Ah (slot 1) bits 7:4 = 1010b. * These bits are undocumented. By setting this * register (of each slot) to '1010xxxxb' a routing of * IREQ# to INTC# and STSCHG# to INTC# is selected. * Since INTC# isn't connected there will be no * unexpected PCI INT when IREQ# or STSCHG# is active. * However, INTA# (slot 0) or INTB# (slot 1) will * still be correctly generated if NO ISA IRQ is * selected (ExCA regs 03h or 05h are cleared). */ reg = exca_getb(&sc->exca[0], EXCA_O2MICRO_CTRL_C); reg = (reg & 0x0f) | EXCA_O2CC_IREQ_INTC | EXCA_O2CC_STSCHG_INTC; exca_putb(&sc->exca[0], EXCA_O2MICRO_CTRL_C, reg); break; case CB_TOPIC97: /* * Disable Zoom Video, ToPIC 97, 100. */ pci_write_config(sc->dev, TOPIC97_ZV_CONTROL, 0, 1); /* * ToPIC 97, 100 * At offset 0xa1: INTERRUPT CONTROL register * 0x1: Turn on INT interrupts. */ PCI_MASK_CONFIG(sc->dev, TOPIC_INTCTRL, | TOPIC97_INTCTRL_INTIRQSEL, 1); /* * ToPIC97, 100 * Need to assert support for low voltage cards */ exca_setb(&sc->exca[0], EXCA_TOPIC97_CTRL, EXCA_TOPIC97_CTRL_LV_MASK); goto topic_common; case CB_TOPIC95: /* * SOCKETCTRL appears to be TOPIC 95/B specific */ PCI_MASK_CONFIG(sc->dev, TOPIC95_SOCKETCTRL, | TOPIC95_SOCKETCTRL_SCR_IRQSEL, 4); topic_common:; /* * At offset 0xa0: SLOT CONTROL * 0x80 Enable CardBus Functionality * 0x40 Enable CardBus and PC Card registers * 0x20 Lock ID in exca regs * 0x10 Write protect ID in config regs * Clear the rest of the bits, which defaults the slot * in legacy mode to 0x3e0 and offset 0. (legacy * mode is determined elsewhere) */ pci_write_config(sc->dev, TOPIC_SLOTCTRL, TOPIC_SLOTCTRL_SLOTON | TOPIC_SLOTCTRL_SLOTEN | TOPIC_SLOTCTRL_ID_LOCK | TOPIC_SLOTCTRL_ID_WP, 1); /* * At offset 0xa3 Card Detect Control Register * 0x80 CARDBUS enbale * 0x01 Cleared for hardware change detect */ PCI_MASK2_CONFIG(sc->dev, TOPIC_CDC, | TOPIC_CDC_CARDBUS, & ~TOPIC_CDC_SWDETECT, 4); break; } /* * Need to tell ExCA registers to CSC interrupts route via PCI * interrupts. There are two ways to do this. One is to set * INTR_ENABLE and the other is to set CSC to 0. Since both * methods are mutually compatible, we do both. */ exca_putb(&sc->exca[0], EXCA_INTR, EXCA_INTR_ENABLE); exca_putb(&sc->exca[0], EXCA_CSC_INTR, 0); cbb_disable_func_intr(sc); /* close all memory and io windows */ pci_write_config(sc->dev, CBBR_MEMBASE0, 0xffffffff, 4); pci_write_config(sc->dev, CBBR_MEMLIMIT0, 0, 4); pci_write_config(sc->dev, CBBR_MEMBASE1, 0xffffffff, 4); pci_write_config(sc->dev, CBBR_MEMLIMIT1, 0, 4); pci_write_config(sc->dev, CBBR_IOBASE0, 0xffffffff, 4); pci_write_config(sc->dev, CBBR_IOLIMIT0, 0, 4); pci_write_config(sc->dev, CBBR_IOBASE1, 0xffffffff, 4); pci_write_config(sc->dev, CBBR_IOLIMIT1, 0, 4); } static int cbb_route_interrupt(device_t pcib, device_t dev, int pin) { struct cbb_softc *sc = (struct cbb_softc *)device_get_softc(pcib); return (rman_get_start(sc->irq_res)); } static int cbb_pci_shutdown(device_t brdev) { struct cbb_softc *sc = (struct cbb_softc *)device_get_softc(brdev); /* * We're about to pull the rug out from the card, so mark it as * gone to prevent harm. */ sc->cardok = 0; /* * Place the cards in reset, turn off the interrupts and power * down the socket. */ PCI_MASK_CONFIG(brdev, CBBR_BRIDGECTRL, |CBBM_BRIDGECTRL_RESET, 2); exca_clrb(&sc->exca[0], EXCA_INTR, EXCA_INTR_RESET); cbb_set(sc, CBB_SOCKET_MASK, 0); cbb_set(sc, CBB_SOCKET_EVENT, 0xffffffff); cbb_power(brdev, CARD_OFF); /* * For paranoia, turn off all address decoding. Really not needed, * it seems, but it can't hurt */ exca_putb(&sc->exca[0], EXCA_ADDRWIN_ENABLE, 0); pci_write_config(brdev, CBBR_MEMBASE0, 0, 4); pci_write_config(brdev, CBBR_MEMLIMIT0, 0, 4); pci_write_config(brdev, CBBR_MEMBASE1, 0, 4); pci_write_config(brdev, CBBR_MEMLIMIT1, 0, 4); pci_write_config(brdev, CBBR_IOBASE0, 0, 4); pci_write_config(brdev, CBBR_IOLIMIT0, 0, 4); pci_write_config(brdev, CBBR_IOBASE1, 0, 4); pci_write_config(brdev, CBBR_IOLIMIT1, 0, 4); return (0); } static int cbb_pci_filt(void *arg) { struct cbb_softc *sc = arg; uint32_t sockevent; uint8_t csc; int retval = FILTER_STRAY; /* * Some chips also require us to read the old ExCA registe for card * status change when we route CSC vis PCI. This isn't supposed to be * required, but it clears the interrupt state on some chipsets. * Maybe there's a setting that would obviate its need. Maybe we * should test the status bits and deal with them, but so far we've * not found any machines that don't also give us the socket status * indication above. * * This call used to be unconditional. However, further research * suggests that we hit this condition when the card READY interrupt * fired. So now we only read it for 16-bit cards, and we only claim * the interrupt if READY is set. If this still causes problems, then * the next step would be to read this if we have a 16-bit card *OR* * we have no card. We treat the READY signal as if it were the power * completion signal. Some bridges may double signal things here, bit * signalling twice should be OK since we only sleep on the powerintr * in one place and a double wakeup would be benign there. */ if (sc->flags & CBB_16BIT_CARD) { csc = exca_getb(&sc->exca[0], EXCA_CSC); if (csc & EXCA_CSC_READY) { atomic_add_int(&sc->powerintr, 1); wakeup((void *)&sc->powerintr); retval = FILTER_HANDLED; } } /* * Read the socket event. Sometimes, the theory goes, the PCI bus is * so loaded that it cannot satisfy the read request, so we get * garbage back from the following read. We have to filter out the * garbage so that we don't spontaneously reset the card under high * load. PCI isn't supposed to act like this. No doubt this is a bug * in the PCI bridge chipset (or cbb brige) that's being used in * certain amd64 laptops today. Work around the issue by assuming * that any bits we don't know about being set means that we got * garbage. */ sockevent = cbb_get(sc, CBB_SOCKET_EVENT); if (sockevent != 0 && (sockevent & ~CBB_SOCKET_EVENT_VALID_MASK) == 0) { /* * If anything has happened to the socket, we assume that the * card is no longer OK, and we shouldn't call its ISR. We * set cardok as soon as we've attached the card. This helps * in a noisy eject, which happens all too often when users * are ejecting their PC Cards. * * We use this method in preference to checking to see if the * card is still there because the check suffers from a race * condition in the bouncing case. */ #define DELTA (CBB_SOCKET_MASK_CD) if (sockevent & DELTA) { cbb_clrb(sc, CBB_SOCKET_MASK, DELTA); cbb_set(sc, CBB_SOCKET_EVENT, DELTA); sc->cardok = 0; cbb_disable_func_intr(sc); wakeup(&sc->intrhand); } #undef DELTA /* * Wakeup anybody waiting for a power interrupt. We have to * use atomic_add_int for wakups on other cores. */ if (sockevent & CBB_SOCKET_EVENT_POWER) { cbb_clrb(sc, CBB_SOCKET_MASK, CBB_SOCKET_EVENT_POWER); cbb_set(sc, CBB_SOCKET_EVENT, CBB_SOCKET_EVENT_POWER); atomic_add_int(&sc->powerintr, 1); wakeup((void *)&sc->powerintr); } /* * Status change interrupts aren't presently used in the * rest of the driver. For now, just ACK them. */ if (sockevent & CBB_SOCKET_EVENT_CSTS) cbb_set(sc, CBB_SOCKET_EVENT, CBB_SOCKET_EVENT_CSTS); retval = FILTER_HANDLED; } return retval; } #if defined(NEW_PCIB) && defined(PCI_RES_BUS) static struct resource * cbb_pci_alloc_resource(device_t bus, device_t child, int type, int *rid, rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) { struct cbb_softc *sc; sc = device_get_softc(bus); if (type == PCI_RES_BUS) return (pcib_alloc_subbus(&sc->bus, child, rid, start, end, count, flags)); return (cbb_alloc_resource(bus, child, type, rid, start, end, count, flags)); } static int cbb_pci_adjust_resource(device_t bus, device_t child, int type, struct resource *r, rman_res_t start, rman_res_t end) { struct cbb_softc *sc; sc = device_get_softc(bus); if (type == PCI_RES_BUS) { if (!rman_is_region_manager(r, &sc->bus.rman)) return (EINVAL); return (rman_adjust_resource(r, start, end)); } return (bus_generic_adjust_resource(bus, child, type, r, start, end)); } static int cbb_pci_release_resource(device_t bus, device_t child, int type, int rid, struct resource *r) { struct cbb_softc *sc; int error; sc = device_get_softc(bus); if (type == PCI_RES_BUS) { if (!rman_is_region_manager(r, &sc->bus.rman)) return (EINVAL); if (rman_get_flags(r) & RF_ACTIVE) { error = bus_deactivate_resource(child, type, rid, r); if (error) return (error); } return (rman_release_resource(r)); } return (cbb_release_resource(bus, child, type, rid, r)); } #endif /************************************************************************/ /* PCI compat methods */ /************************************************************************/ static int cbb_maxslots(device_t brdev) { return (0); } static uint32_t cbb_read_config(device_t brdev, u_int b, u_int s, u_int f, u_int reg, int width) { /* * Pass through to the next ppb up the chain (i.e. our grandparent). */ return (PCIB_READ_CONFIG(device_get_parent(device_get_parent(brdev)), b, s, f, reg, width)); } static void cbb_write_config(device_t brdev, u_int b, u_int s, u_int f, u_int reg, uint32_t val, int width) { /* * Pass through to the next ppb up the chain (i.e. our grandparent). */ PCIB_WRITE_CONFIG(device_get_parent(device_get_parent(brdev)), b, s, f, reg, val, width); } static int cbb_pci_suspend(device_t brdev) { int error = 0; struct cbb_softc *sc = device_get_softc(brdev); error = bus_generic_suspend(brdev); if (error != 0) return (error); cbb_set(sc, CBB_SOCKET_MASK, 0); /* Quiet hardware */ sc->cardok = 0; /* Card is bogus now */ return (0); } static int cbb_pci_resume(device_t brdev) { int error = 0; struct cbb_softc *sc = (struct cbb_softc *)device_get_softc(brdev); uint32_t tmp; /* * In the APM and early ACPI era, BIOSes saved the PCI config * registers. As chips became more complicated, that functionality moved * into the ACPI code / tables. We must therefore, restore the settings * we made here to make sure the device come back. Transitions to Dx * from D0 and back to D0 cause the bridge to lose its config space, so * all the bus mappings and such are preserved. * * The PCI layer handles standard PCI registers like the * command register and BARs, but cbb-specific registers are * handled here. */ sc->chipinit(sc); /* reset interrupt -- Do we really need to do this? */ tmp = cbb_get(sc, CBB_SOCKET_EVENT); cbb_set(sc, CBB_SOCKET_EVENT, tmp); /* CSC Interrupt: Card detect interrupt on */ cbb_setb(sc, CBB_SOCKET_MASK, CBB_SOCKET_MASK_CD); /* Signal the thread to wakeup. */ wakeup(&sc->intrhand); error = bus_generic_resume(brdev); return (error); } static device_method_t cbb_methods[] = { /* Device interface */ DEVMETHOD(device_probe, cbb_pci_probe), DEVMETHOD(device_attach, cbb_pci_attach), DEVMETHOD(device_detach, cbb_pci_detach), DEVMETHOD(device_shutdown, cbb_pci_shutdown), DEVMETHOD(device_suspend, cbb_pci_suspend), DEVMETHOD(device_resume, cbb_pci_resume), /* bus methods */ DEVMETHOD(bus_read_ivar, cbb_read_ivar), DEVMETHOD(bus_write_ivar, cbb_write_ivar), #if defined(NEW_PCIB) && defined(PCI_RES_BUS) DEVMETHOD(bus_alloc_resource, cbb_pci_alloc_resource), DEVMETHOD(bus_adjust_resource, cbb_pci_adjust_resource), DEVMETHOD(bus_release_resource, cbb_pci_release_resource), #else DEVMETHOD(bus_alloc_resource, cbb_alloc_resource), DEVMETHOD(bus_release_resource, cbb_release_resource), #endif DEVMETHOD(bus_activate_resource, cbb_activate_resource), DEVMETHOD(bus_deactivate_resource, cbb_deactivate_resource), DEVMETHOD(bus_driver_added, cbb_driver_added), DEVMETHOD(bus_child_detached, cbb_child_detached), DEVMETHOD(bus_setup_intr, cbb_setup_intr), DEVMETHOD(bus_teardown_intr, cbb_teardown_intr), DEVMETHOD(bus_child_present, cbb_child_present), /* 16-bit card interface */ DEVMETHOD(card_set_res_flags, cbb_pcic_set_res_flags), DEVMETHOD(card_set_memory_offset, cbb_pcic_set_memory_offset), /* power interface */ DEVMETHOD(power_enable_socket, cbb_power_enable_socket), DEVMETHOD(power_disable_socket, cbb_power_disable_socket), /* pcib compatibility interface */ DEVMETHOD(pcib_maxslots, cbb_maxslots), DEVMETHOD(pcib_read_config, cbb_read_config), DEVMETHOD(pcib_write_config, cbb_write_config), DEVMETHOD(pcib_route_interrupt, cbb_route_interrupt), DEVMETHOD_END }; static driver_t cbb_driver = { "cbb", cbb_methods, sizeof(struct cbb_softc) }; DRIVER_MODULE(cbb, pci, cbb_driver, cbb_devclass, 0, 0); MODULE_PNP_INFO("W32:vendor/device;D:#", pci, cbb, yc_chipsets, nitems(yc_chipsets) - 1); MODULE_DEPEND(cbb, exca, 1, 1, 1); Index: head/sys/dev/pccbb/pccbbdevid.h =================================================================== --- head/sys/dev/pccbb/pccbbdevid.h (revision 355393) +++ head/sys/dev/pccbb/pccbbdevid.h (revision 355394) @@ -1,116 +1,116 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2001-2004 M. Warner Losh. + * Copyright (c) 2001-2004 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ /* Vendor/Device IDs */ #define PCIC_ID_CLPD6729 0x11001013ul /* 16bit I/O */ #define PCIC_ID_CLPD6832 0x11101013ul #define PCIC_ID_CLPD6833 0x11131013ul #define PCIC_ID_CLPD6834 0x11121013ul #define PCIC_ID_ENE_CB710 0x14111524ul #define PCIC_ID_ENE_CB720 0x14211524ul /* ??? */ #define PCIC_ID_ENE_CB1211 0x12111524ul /* ??? */ #define PCIC_ID_ENE_CB1225 0x12251524ul /* ??? */ #define PCIC_ID_ENE_CB1410 0x14101524ul #define PCIC_ID_ENE_CB1420 0x14201524ul #define PCIC_ID_INTEL_82092AA_0 0x12218086ul /* 16bit I/O */ #define PCIC_ID_INTEL_82092AA_1 0x12228086ul /* 16bit I/O */ #define PCIC_ID_OMEGA_82C094 0x1221119bul /* 16bit I/O */ #define PCIC_ID_OZ6729 0x67291217ul /* 16bit I/O */ #define PCIC_ID_OZ6730 0x673a1217ul /* 16bit I/O */ #define PCIC_ID_OZ6832 0x68321217ul /* Also 6833 */ #define PCIC_ID_OZ6860 0x68361217ul /* Also 6836 */ #define PCIC_ID_OZ6872 0x68721217ul /* Also 6812 */ #define PCIC_ID_OZ6912 0x69721217ul /* Also 6972 */ #define PCIC_ID_OZ6922 0x69251217ul #define PCIC_ID_OZ6933 0x69331217ul #define PCIC_ID_OZ711EC1 0x71121217ul /* O2Micro 711EC1/M1 */ #define PCIC_ID_OZ711E1 0x71131217ul /* O2Micro 711E1 */ #define PCIC_ID_OZ711M1 0x71141217ul /* O2Micro 711M1 */ #define PCIC_ID_OZ711E2 0x71e21217ul #define PCIC_ID_OZ711M2 0x72121217ul #define PCIC_ID_OZ711M3 0x72231217ul #define PCIC_ID_RICOH_RL5C465 0x04651180ul #define PCIC_ID_RICOH_RL5C466 0x04661180ul #define PCIC_ID_RICOH_RL5C475 0x04751180ul #define PCIC_ID_RICOH_RL5C476 0x04761180ul #define PCIC_ID_RICOH_RL5C477 0x04771180ul #define PCIC_ID_RICOH_RL5C478 0x04781180ul #define PCIC_ID_SMC_34C90 0xb10610b3ul #define PCIC_ID_TI1031 0xac13104cul #define PCIC_ID_TI1130 0xac12104cul #define PCIC_ID_TI1131 0xac15104cul #define PCIC_ID_TI1210 0xac1a104cul #define PCIC_ID_TI1211 0xac1e104cul #define PCIC_ID_TI1220 0xac17104cul #define PCIC_ID_TI1221 0xac19104cul /* never sold */ #define PCIC_ID_TI1225 0xac1c104cul #define PCIC_ID_TI1250 0xac16104cul /* Rare */ #define PCIC_ID_TI1251 0xac1d104cul #define PCIC_ID_TI1251B 0xac1f104cul #define PCIC_ID_TI1260 0xac18104cul /* never sold */ #define PCIC_ID_TI1260B 0xac30104cul /* never sold */ #define PCIC_ID_TI1410 0xac50104cul #define PCIC_ID_TI1420 0xac51104cul #define PCIC_ID_TI1421 0xac53104cul /* never sold */ #define PCIC_ID_TI1450 0xac1b104cul #define PCIC_ID_TI1451 0xac52104cul #define PCIC_ID_TI1510 0xac56104cul #define PCIC_ID_TI1515 0xac58104cul #define PCIC_ID_TI1520 0xac55104cul #define PCIC_ID_TI1530 0xac57104cul #define PCIC_ID_TI1620 0xac54104cul #define PCIC_ID_TI4410 0xac41104cul #define PCIC_ID_TI4450 0xac40104cul #define PCIC_ID_TI4451 0xac42104cul #define PCIC_ID_TI4510 0xac44104cul #define PCIC_ID_TI4520 0xac46104cul #define PCIC_ID_TI6411 0x8031104cul /* PCI[67]x[12]1 */ #define PCIC_ID_TI6420 0xac8d104cul /* PCI[67]x20 Smartcard dis */ #define PCIC_ID_TI6420SC 0xac8e104cul /* PCI[67]x20 Smartcard en */ #define PCIC_ID_TI7410 0xac49104cul #define PCIC_ID_TI7510 0xac47104cul #define PCIC_ID_TI7610 0xac48104cul #define PCIC_ID_TI7610M 0xac4a104cul #define PCIC_ID_TI7610SD 0xac4b104cul #define PCIC_ID_TI7610MS 0xac4c104cul #define PCIC_ID_TOPIC95 0x06031179ul #define PCIC_ID_TOPIC95B 0x060a1179ul #define PCIC_ID_TOPIC97 0x060f1179ul #define PCIC_ID_TOPIC100 0x06171179ul /* * Other ID, from sources too vague to be reliable * Mfg model PCI ID * smc/Databook DB87144 0x310610b3 * Omega/Trident 82c194 0x01941023 * Omega/Trident 82c722 0x07221023? * Opti 82c814 0xc8141045 * Opti 82c824 0xc8241045 * NEC uPD66369 0x003e1033 */ Index: head/sys/dev/pccbb/pccbbvar.h =================================================================== --- head/sys/dev/pccbb/pccbbvar.h (revision 355393) +++ head/sys/dev/pccbb/pccbbvar.h (revision 355394) @@ -1,171 +1,170 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2003-2004 M. Warner Losh. - * Copyright (c) 2000,2001 Jonathan Chen. - * All rights reserved. + * Copyright (c) 2000,2001 Jonathan Chen All rights reserved. + * Copyright (c) 2003-2004 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ /* * Structure definitions for the Cardbus Bridge driver */ struct cbb_intrhand { driver_filter_t *filt; driver_intr_t *intr; void *arg; struct cbb_softc *sc; void *cookie; }; struct cbb_reslist { SLIST_ENTRY(cbb_reslist) link; struct resource *res; int type; int rid; /* note: unlike the regular resource list, there can be * duplicate rid's in the same list. However, the * combination of rid and res->r_dev should be unique. */ bus_addr_t cardaddr; /* for 16-bit pccard memory */ }; #define CBB_AUTO_OPEN_SMALLHOLE 0x100 #define CBB_NSLOTS 4 struct cbb_softc { device_t dev; struct exca_softc exca[CBB_NSLOTS]; struct resource *base_res; struct resource *irq_res; void *intrhand; bus_space_tag_t bst; bus_space_handle_t bsh; uint32_t domain; unsigned int pribus; struct pcib_secbus bus; struct mtx mtx; int cardok; u_int32_t flags; #define CBB_16BIT_CARD 0x20000000 #define CBB_KTHREAD_RUNNING 0x40000000 #define CBB_KTHREAD_DONE 0x80000000 int chipset; /* chipset id */ #define CB_UNKNOWN 0 /* NOT Cardbus-PCI bridge */ #define CB_TI113X 1 /* TI PCI1130/1131 */ #define CB_TI12XX 2 /* TI PCI12xx/14xx/44xx/15xx/45xx */ #define CB_TI125X 3 /* TI PCI1250/1251(B)/1450 */ #define CB_RF5C47X 4 /* RICOH RF5C475/476/477 */ #define CB_RF5C46X 5 /* RICOH RF5C465/466/467 */ #define CB_CIRRUS 6 /* Cirrus Logic CLPD683x */ #define CB_TOPIC95 7 /* Toshiba ToPIC95 */ #define CB_TOPIC97 8 /* Toshiba ToPIC97/100 */ #define CB_O2MICRO 9 /* O2Micro chips */ SLIST_HEAD(, cbb_reslist) rl; device_t cbdev; struct proc *event_thread; void (*chipinit)(struct cbb_softc *); int powerintr; struct root_hold_token *sc_root_token; }; /* result of detect_card */ #define CARD_UKN_CARD 0x00 #define CARD_5V_CARD 0x01 #define CARD_3V_CARD 0x02 #define CARD_XV_CARD 0x04 #define CARD_YV_CARD 0x08 /* for power_socket */ #define CARD_VCC(X) (X) #define CARD_VPP_VCC 0xf0 #define CARD_VCCMASK 0xf #define CARD_VCCSHIFT 0 #define XV 2 #define YV 1 #define CARD_OFF (CARD_VCC(0)) extern int cbb_debug; extern devclass_t cbb_devclass; int cbb_activate_resource(device_t brdev, device_t child, int type, int rid, struct resource *r); struct resource *cbb_alloc_resource(device_t brdev, device_t child, int type, int *rid, rman_res_t start, rman_res_t end, rman_res_t count, u_int flags); void cbb_child_detached(device_t brdev, device_t child); int cbb_child_present(device_t parent, device_t child); int cbb_deactivate_resource(device_t brdev, device_t child, int type, int rid, struct resource *r); int cbb_detach(device_t brdev); void cbb_disable_func_intr(struct cbb_softc *sc); void cbb_driver_added(device_t brdev, driver_t *driver); void cbb_event_thread(void *arg); int cbb_pcic_set_memory_offset(device_t brdev, device_t child, int rid, uint32_t cardaddr, uint32_t *deltap); int cbb_pcic_set_res_flags(device_t brdev, device_t child, int type, int rid, u_long flags); int cbb_power(device_t brdev, int volts); int cbb_power_enable_socket(device_t brdev, device_t child); int cbb_power_disable_socket(device_t brdev, device_t child); int cbb_read_ivar(device_t brdev, device_t child, int which, uintptr_t *result); int cbb_release_resource(device_t brdev, device_t child, int type, int rid, struct resource *r); int cbb_setup_intr(device_t dev, device_t child, struct resource *irq, int flags, driver_filter_t *filt, driver_intr_t *intr, void *arg, void **cookiep); int cbb_teardown_intr(device_t dev, device_t child, struct resource *irq, void *cookie); int cbb_write_ivar(device_t brdev, device_t child, int which, uintptr_t value); /* */ static __inline void cbb_set(struct cbb_softc *sc, uint32_t reg, uint32_t val) { bus_space_write_4(sc->bst, sc->bsh, reg, val); } static __inline uint32_t cbb_get(struct cbb_softc *sc, uint32_t reg) { return (bus_space_read_4(sc->bst, sc->bsh, reg)); } static __inline void cbb_setb(struct cbb_softc *sc, uint32_t reg, uint32_t bits) { cbb_set(sc, reg, cbb_get(sc, reg) | bits); } static __inline void cbb_clrb(struct cbb_softc *sc, uint32_t reg, uint32_t bits) { cbb_set(sc, reg, cbb_get(sc, reg) & ~bits); } Index: head/sys/dev/puc/puc_pci.c =================================================================== --- head/sys/dev/puc/puc_pci.c (revision 355393) +++ head/sys/dev/puc/puc_pci.c (revision 355394) @@ -1,203 +1,203 @@ /* $NetBSD: puc.c,v 1.7 2000/07/29 17:43:38 jlam Exp $ */ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD AND BSD-3-Clause * * Copyright (c) 2002 JF Hay. All rights reserved. - * Copyright (c) 2000 M. Warner Losh. + * Copyright (c) 2000 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /*- * Copyright (c) 1996, 1998, 1999 * Christopher G. Demetriou. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Christopher G. Demetriou * for the NetBSD Project. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static int puc_msi_disable; SYSCTL_INT(_hw_puc, OID_AUTO, msi_disable, CTLFLAG_RDTUN, &puc_msi_disable, 0, "Disable use of MSI interrupts by puc(9)"); static const struct puc_cfg * puc_pci_match(device_t dev, const struct puc_cfg *desc) { uint16_t vendor, device; uint16_t subvendor, subdevice; vendor = pci_get_vendor(dev); device = pci_get_device(dev); subvendor = pci_get_subvendor(dev); subdevice = pci_get_subdevice(dev); while (desc->vendor != 0xffff) { if (desc->vendor == vendor && desc->device == device) { /* exact match */ if (desc->subvendor == subvendor && desc->subdevice == subdevice) return (desc); /* wildcard match */ if (desc->subvendor == 0xffff) return (desc); } desc++; } /* no match */ return (NULL); } static int puc_pci_probe(device_t dev) { const struct puc_cfg *desc; if ((pci_read_config(dev, PCIR_HDRTYPE, 1) & PCIM_HDRTYPE) != 0) return (ENXIO); desc = puc_pci_match(dev, puc_pci_devices); if (desc == NULL) return (ENXIO); return (puc_bfe_probe(dev, desc)); } static int puc_pci_attach(device_t dev) { struct puc_softc *sc; int error, count; sc = device_get_softc(dev); if (!puc_msi_disable) { count = 1; if (pci_alloc_msi(dev, &count) == 0) { sc->sc_msi = 1; sc->sc_irid = 1; } } error = puc_bfe_attach(dev); if (error != 0 && sc->sc_msi) pci_release_msi(dev); return (error); } static int puc_pci_detach(device_t dev) { struct puc_softc *sc; int error; sc = device_get_softc(dev); error = puc_bfe_detach(dev); if (error != 0) return (error); if (sc->sc_msi) error = pci_release_msi(dev); return (error); } static device_method_t puc_pci_methods[] = { /* Device interface */ DEVMETHOD(device_probe, puc_pci_probe), DEVMETHOD(device_attach, puc_pci_attach), DEVMETHOD(device_detach, puc_pci_detach), DEVMETHOD(bus_alloc_resource, puc_bus_alloc_resource), DEVMETHOD(bus_release_resource, puc_bus_release_resource), DEVMETHOD(bus_get_resource, puc_bus_get_resource), DEVMETHOD(bus_read_ivar, puc_bus_read_ivar), DEVMETHOD(bus_setup_intr, puc_bus_setup_intr), DEVMETHOD(bus_teardown_intr, puc_bus_teardown_intr), DEVMETHOD(bus_print_child, puc_bus_print_child), DEVMETHOD(bus_child_pnpinfo_str, puc_bus_child_pnpinfo_str), DEVMETHOD(bus_child_location_str, puc_bus_child_location_str), DEVMETHOD_END }; static driver_t puc_pci_driver = { puc_driver_name, puc_pci_methods, sizeof(struct puc_softc), }; DRIVER_MODULE(puc, pci, puc_pci_driver, puc_devclass, 0, 0); MODULE_PNP_INFO("U16:vendor;U16:device;U16:#;U16:#;D:#", pci, puc, puc_pci_devices, nitems(puc_pci_devices) - 1); Index: head/sys/dev/sdhci/sdhci_if.m =================================================================== --- head/sys/dev/sdhci/sdhci_if.m (revision 355393) +++ head/sys/dev/sdhci/sdhci_if.m (revision 355394) @@ -1,167 +1,166 @@ #- -# Copyright (c) 2006 M. Warner Losh -# All rights reserved. +# Copyright (c) 2006 M. Warner Losh # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # Portions of this software may have been developed with reference to # the SD Simplified Specification. The following disclaimer may apply: # # The following conditions apply to the release of the simplified # specification ("Simplified Specification") by the SD Card Association and # the SD Group. The Simplified Specification is a subset of the complete SD # Specification which is owned by the SD Card Association and the SD # Group. This Simplified Specification is provided on a non-confidential # basis subject to the disclaimers below. Any implementation of the # Simplified Specification may require a license from the SD Card # Association, SD Group, SD-3C LLC or other third parties. # # Disclaimers: # # The information contained in the Simplified Specification is presented only # as a standard specification for SD Cards and SD Host/Ancillary products and # is provided "AS-IS" without any representations or warranties of any # kind. No responsibility is assumed by the SD Group, SD-3C LLC or the SD # Card Association for any damages, any infringements of patents or other # right of the SD Group, SD-3C LLC, the SD Card Association or any third # parties, which may result from its use. No license is granted by # implication, estoppel or otherwise under any patent or other rights of the # SD Group, SD-3C LLC, the SD Card Association or any third party. Nothing # herein shall be construed as an obligation by the SD Group, the SD-3C LLC # or the SD Card Association to disclose or distribute any technical # information, know-how or other confidential information to any third party. # # $FreeBSD$ # # # This is the set of callbacks that mmc bridges call into the bus, or # that mmc/sd card drivers call to make requests. # #include #include #include #include #include #include #include #include CODE { static void null_set_uhs_timing(device_t brdev __unused, struct sdhci_slot *slot __unused) { } } INTERFACE sdhci; METHOD uint8_t read_1 { device_t brdev; struct sdhci_slot *slot; bus_size_t off; } METHOD uint16_t read_2 { device_t brdev; struct sdhci_slot *slot; bus_size_t off; } METHOD uint32_t read_4 { device_t brdev; struct sdhci_slot *slot; bus_size_t off; } METHOD void read_multi_4 { device_t brdev; struct sdhci_slot *slot; bus_size_t off; uint32_t *data; bus_size_t count; } METHOD void write_1 { device_t brdev; struct sdhci_slot *slot; bus_size_t off; uint8_t val; } METHOD void write_2 { device_t brdev; struct sdhci_slot *slot; bus_size_t off; uint16_t val; } METHOD void write_4 { device_t brdev; struct sdhci_slot *slot; bus_size_t off; uint32_t val; } METHOD void write_multi_4 { device_t brdev; struct sdhci_slot *slot; bus_size_t off; uint32_t *data; bus_size_t count; } METHOD int platform_will_handle { device_t brdev; struct sdhci_slot *slot; } METHOD void platform_start_transfer { device_t brdev; struct sdhci_slot *slot; uint32_t *intmask; } METHOD void platform_finish_transfer { device_t brdev; struct sdhci_slot *slot; } METHOD uint32_t min_freq { device_t brdev; struct sdhci_slot *slot; } DEFAULT sdhci_generic_min_freq; METHOD bool get_card_present { device_t brdev; struct sdhci_slot *slot; } DEFAULT sdhci_generic_get_card_present; METHOD void set_uhs_timing { device_t brdev; struct sdhci_slot *slot; } DEFAULT null_set_uhs_timing; Index: head/sys/dev/spibus/spi.h =================================================================== --- head/sys/dev/spibus/spi.h (revision 355393) +++ head/sys/dev/spibus/spi.h (revision 355394) @@ -1,48 +1,47 @@ /*- - * Copyright (c) 2006 M. Warner Losh - * All rights reserved. + * Copyright (c) 2006 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ struct spi_command { void *tx_cmd; uint32_t tx_cmd_sz; void *rx_cmd; uint32_t rx_cmd_sz; void *tx_data; uint32_t tx_data_sz; void *rx_data; uint32_t rx_data_sz; }; #define SPI_COMMAND_INITIALIZER { 0 } #define SPI_CHIP_SELECT_HIGH 0x1 /* Chip select high (else low) */ #ifdef FDT #define SPIBUS_FDT_PNP_INFO(t) FDTCOMPAT_PNP_INFO(t, spibus) #else #define SPIBUS_FDT_PNP_INFO(t) #endif Index: head/sys/dev/spibus/spibus.c =================================================================== --- head/sys/dev/spibus/spibus.c (revision 355393) +++ head/sys/dev/spibus/spibus.c (revision 355394) @@ -1,264 +1,263 @@ /*- - * Copyright (c) 2006 M. Warner Losh - * All rights reserved. + * Copyright (c) 2006 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "spibus_if.h" static int spibus_probe(device_t dev) { device_set_desc(dev, "SPI bus"); return (BUS_PROBE_DEFAULT); } static int spibus_attach(device_t dev) { struct spibus_softc *sc = SPIBUS_SOFTC(dev); sc->dev = dev; bus_enumerate_hinted_children(dev); return (bus_generic_attach(dev)); } /* * Since this is not a self-enumerating bus, and since we always add * children in attach, we have to always delete children here. */ static int spibus_detach(device_t dev) { int err; if ((err = bus_generic_detach(dev)) != 0) return (err); device_delete_children(dev); return (0); } static int spibus_suspend(device_t dev) { return (bus_generic_suspend(dev)); } static int spibus_resume(device_t dev) { return (bus_generic_resume(dev)); } static int spibus_print_child(device_t dev, device_t child) { struct spibus_ivar *devi = SPIBUS_IVAR(child); int retval = 0; retval += bus_print_child_header(dev, child); retval += printf(" at cs %d", devi->cs); retval += printf(" mode %d", devi->mode); retval += bus_print_child_footer(dev, child); return (retval); } static void spibus_probe_nomatch(device_t bus, device_t child) { struct spibus_ivar *devi = SPIBUS_IVAR(child); device_printf(bus, " at cs %d mode %d\n", devi->cs, devi->mode); return; } static int spibus_child_location_str(device_t bus, device_t child, char *buf, size_t buflen) { struct spibus_ivar *devi = SPIBUS_IVAR(child); int cs; cs = devi->cs & ~SPIBUS_CS_HIGH; /* trim 'cs high' bit */ snprintf(buf, buflen, "bus=%d cs=%d", device_get_unit(bus), cs); return (0); } static int spibus_child_pnpinfo_str(device_t bus, device_t child, char *buf, size_t buflen) { *buf = '\0'; return (0); } static int spibus_read_ivar(device_t bus, device_t child, int which, uintptr_t *result) { struct spibus_ivar *devi = SPIBUS_IVAR(child); switch (which) { default: return (EINVAL); case SPIBUS_IVAR_CS: *(uint32_t *)result = devi->cs; break; case SPIBUS_IVAR_MODE: *(uint32_t *)result = devi->mode; break; case SPIBUS_IVAR_CLOCK: *(uint32_t *)result = devi->clock; break; } return (0); } static int spibus_write_ivar(device_t bus, device_t child, int which, uintptr_t value) { struct spibus_ivar *devi = SPIBUS_IVAR(child); if (devi == NULL || device_get_parent(child) != bus) return (EDOOFUS); switch (which) { case SPIBUS_IVAR_CLOCK: /* Any non-zero value is allowed for max clock frequency. */ if (value == 0) return (EINVAL); devi->clock = (uint32_t)value; break; case SPIBUS_IVAR_CS: /* Chip select cannot be changed. */ return (EINVAL); case SPIBUS_IVAR_MODE: /* Valid SPI modes are 0-3. */ if (value > 3) return (EINVAL); devi->mode = (uint32_t)value; break; default: return (EINVAL); } return (0); } static device_t spibus_add_child(device_t dev, u_int order, const char *name, int unit) { device_t child; struct spibus_ivar *devi; child = device_add_child_ordered(dev, order, name, unit); if (child == NULL) return (child); devi = malloc(sizeof(struct spibus_ivar), M_DEVBUF, M_NOWAIT | M_ZERO); if (devi == NULL) { device_delete_child(dev, child); return (0); } device_set_ivars(child, devi); return (child); } static void spibus_hinted_child(device_t bus, const char *dname, int dunit) { device_t child; struct spibus_ivar *devi; child = BUS_ADD_CHILD(bus, 0, dname, dunit); devi = SPIBUS_IVAR(child); devi->mode = SPIBUS_MODE_NONE; resource_int_value(dname, dunit, "clock", &devi->clock); resource_int_value(dname, dunit, "cs", &devi->cs); resource_int_value(dname, dunit, "mode", &devi->mode); } static int spibus_transfer_impl(device_t dev, device_t child, struct spi_command *cmd) { return (SPIBUS_TRANSFER(device_get_parent(dev), child, cmd)); } static device_method_t spibus_methods[] = { /* Device interface */ DEVMETHOD(device_probe, spibus_probe), DEVMETHOD(device_attach, spibus_attach), DEVMETHOD(device_detach, spibus_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD(device_suspend, spibus_suspend), DEVMETHOD(device_resume, spibus_resume), /* Bus interface */ DEVMETHOD(bus_add_child, spibus_add_child), DEVMETHOD(bus_print_child, spibus_print_child), DEVMETHOD(bus_probe_nomatch, spibus_probe_nomatch), DEVMETHOD(bus_read_ivar, spibus_read_ivar), DEVMETHOD(bus_write_ivar, spibus_write_ivar), DEVMETHOD(bus_child_pnpinfo_str, spibus_child_pnpinfo_str), DEVMETHOD(bus_child_location_str, spibus_child_location_str), DEVMETHOD(bus_hinted_child, spibus_hinted_child), /* spibus interface */ DEVMETHOD(spibus_transfer, spibus_transfer_impl), DEVMETHOD_END }; driver_t spibus_driver = { "spibus", spibus_methods, sizeof(struct spibus_softc) }; devclass_t spibus_devclass; DRIVER_MODULE(spibus, spi, spibus_driver, spibus_devclass, 0, 0); MODULE_VERSION(spibus, 1); Index: head/sys/dev/spibus/spibus_if.m =================================================================== --- head/sys/dev/spibus/spibus_if.m (revision 355393) +++ head/sys/dev/spibus/spibus_if.m (revision 355394) @@ -1,41 +1,40 @@ #- -# Copyright (c) 2006 M. Warner Losh -# All rights reserved. +# Copyright (c) 2006 M. Warner Losh # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # $FreeBSD$ # #include #include INTERFACE spibus; # # Do a spi command # METHOD int transfer { device_t dev; device_t child; struct spi_command *cmd; }; Index: head/sys/dev/spibus/spibusvar.h =================================================================== --- head/sys/dev/spibus/spibusvar.h (revision 355393) +++ head/sys/dev/spibus/spibusvar.h (revision 355394) @@ -1,78 +1,77 @@ /*- - * Copyright (c) 2006 M. Warner Losh - * All rights reserved. + * Copyright (c) 2006 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #define SPIBUS_IVAR(d) (struct spibus_ivar *) device_get_ivars(d) #define SPIBUS_SOFTC(d) (struct spibus_softc *) device_get_softc(d) struct spibus_softc { device_t dev; }; #define SPIBUS_MODE_NONE 0 #define SPIBUS_MODE_CPHA 1 #define SPIBUS_MODE_CPOL 2 #define SPIBUS_MODE_CPOL_CPHA 3 struct spibus_ivar { uint32_t cs; uint32_t mode; uint32_t clock; }; #define SPIBUS_CS_HIGH (1U << 31) enum { SPIBUS_IVAR_CS, /* chip select that we're on */ SPIBUS_IVAR_MODE, /* SPI mode (0-3) */ SPIBUS_IVAR_CLOCK, /* maximum clock freq for device */ }; #define SPIBUS_ACCESSOR(A, B, T) \ static inline int \ spibus_get_ ## A(device_t dev, T *t) \ { \ return BUS_READ_IVAR(device_get_parent(dev), dev, \ SPIBUS_IVAR_ ## B, (uintptr_t *) t); \ } \ static inline int \ spibus_set_ ## A(device_t dev, T t) \ { \ return BUS_WRITE_IVAR(device_get_parent(dev), dev, \ SPIBUS_IVAR_ ## B, (uintptr_t) t); \ } SPIBUS_ACCESSOR(cs, CS, uint32_t) SPIBUS_ACCESSOR(mode, MODE, uint32_t) SPIBUS_ACCESSOR(clock, CLOCK, uint32_t) extern driver_t spibus_driver; extern devclass_t spibus_devclass; extern driver_t ofw_spibus_driver; extern devclass_t ofw_spibus_devclass; Index: head/sys/dev/uart/uart_bus_acpi.c =================================================================== --- head/sys/dev/uart/uart_bus_acpi.c (revision 355393) +++ head/sys/dev/uart/uart_bus_acpi.c (revision 355394) @@ -1,102 +1,102 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2001 M. Warner Losh. + * Copyright (c) 2001 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static int uart_acpi_probe(device_t dev); static device_method_t uart_acpi_methods[] = { /* Device interface */ DEVMETHOD(device_probe, uart_acpi_probe), DEVMETHOD(device_attach, uart_bus_attach), DEVMETHOD(device_detach, uart_bus_detach), DEVMETHOD(device_resume, uart_bus_resume), { 0, 0 } }; static driver_t uart_acpi_driver = { uart_driver_name, uart_acpi_methods, sizeof(struct uart_softc), }; static struct acpi_uart_compat_data * uart_acpi_find_device(device_t dev) { struct acpi_uart_compat_data **cd, *cd_it; ACPI_HANDLE h; if ((h = acpi_get_handle(dev)) == NULL) return (NULL); SET_FOREACH(cd, uart_acpi_class_and_device_set) { for (cd_it = *cd; cd_it->cd_hid != NULL; cd_it++) { if (acpi_MatchHid(h, cd_it->cd_hid)) return (cd_it); } } return (NULL); } static int uart_acpi_probe(device_t dev) { struct uart_softc *sc; struct acpi_uart_compat_data *cd; sc = device_get_softc(dev); if ((cd = uart_acpi_find_device(dev)) != NULL) { sc->sc_class = cd->cd_class; if (cd->cd_desc != NULL) device_set_desc(dev, cd->cd_desc); return (uart_bus_probe(dev, cd->cd_regshft, cd->cd_regiowidth, cd->cd_rclk, 0, 0, cd->cd_quirks)); } return (ENXIO); } DRIVER_MODULE(uart, acpi, uart_acpi_driver, uart_devclass, 0, 0); Index: head/sys/dev/uart/uart_bus_isa.c =================================================================== --- head/sys/dev/uart/uart_bus_isa.c (revision 355393) +++ head/sys/dev/uart/uart_bus_isa.c (revision 355394) @@ -1,175 +1,174 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2008 TAKAHASHI Yoshihiro - * Copyright (c) 2008 Marcel Moolenaar - * Copyright (c) 2001 M. Warner Losh - * All rights reserved. + * Copyright (c) 2008 TAKAHASHI Yoshihiro All rights reserved. + * Copyright (c) 2008 Marcel Moolenaar All rights reserved. + * Copyright (c) 2001 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include static int uart_isa_probe(device_t dev); static device_method_t uart_isa_methods[] = { /* Device interface */ DEVMETHOD(device_probe, uart_isa_probe), DEVMETHOD(device_attach, uart_bus_attach), DEVMETHOD(device_detach, uart_bus_detach), DEVMETHOD(device_resume, uart_bus_resume), { 0, 0 } }; static driver_t uart_isa_driver = { uart_driver_name, uart_isa_methods, sizeof(struct uart_softc), }; static struct isa_pnp_id isa_ns8250_ids[] = { {0x0005d041, "Standard PC COM port"}, /* PNP0500 */ {0x0105d041, "16550A-compatible COM port"}, /* PNP0501 */ {0x0205d041, "Multiport serial device (non-intelligent 16550)"}, /* PNP0502 */ {0x1005d041, "Generic IRDA-compatible device"}, /* PNP0510 */ {0x1105d041, "Generic IRDA-compatible device"}, /* PNP0511 */ /* Devices that do not have a compatid */ {0x12206804, NULL}, /* ACH2012 - 5634BTS 56K Video Ready Modem */ {0x7602a904, NULL}, /* AEI0276 - 56K v.90 Fax Modem (LKT) */ {0x00007905, NULL}, /* AKY0000 - 56K Plug&Play Modem */ {0x21107905, NULL}, /* AKY1021 - 56K Plug&Play Modem */ {0x01405407, NULL}, /* AZT4001 - AZT3000 PnP SOUND DEVICE, MODEM */ {0x56039008, NULL}, /* BDP0356 - Best Data 56x2 */ {0x56159008, NULL}, /* BDP1556 - B.D. Smart One 56SPS,Voice Modem*/ {0x36339008, NULL}, /* BDP3336 - Best Data Prods. 336F */ {0x0014490a, NULL}, /* BRI1400 - Boca 33.6 PnP */ {0x0015490a, NULL}, /* BRI1500 - Internal Fax Data */ {0x0034490a, NULL}, /* BRI3400 - Internal ACF Modem */ {0x0094490a, NULL}, /* BRI9400 - Boca K56Flex PnP */ {0x00b4490a, NULL}, /* BRIB400 - Boca 56k PnP */ {0x0010320d, NULL}, /* CIR1000 - Cirrus Logic V34 */ {0x0030320d, NULL}, /* CIR3000 - Cirrus Logic V43 */ {0x0100440e, NULL}, /* CRD0001 - Cardinal MVP288IV ? */ {0x01308c0e, NULL}, /* CTL3001 - Creative Labs Phoneblaster */ {0x36033610, NULL}, /* DAV0336 - DAVICOM 336PNP MODEM */ {0x01009416, NULL}, /* ETT0001 - E-Tech Bullet 33k6 PnP */ {0x0000aa1a, NULL}, /* FUJ0000 - FUJITSU Modem 33600 PNP/I2 */ {0x1200c31e, NULL}, /* GVC0012 - VF1128HV-R9 (win modem?) */ {0x0303c31e, NULL}, /* GVC0303 - MaxTech 33.6 PnP D/F/V */ {0x0505c31e, NULL}, /* GVC0505 - GVC 56k Faxmodem */ {0x0116c31e, NULL}, /* GVC1601 - Rockwell V.34 Plug & Play Modem */ {0x0050c31e, NULL}, /* GVC5000 - some GVC modem */ {0x3800f91e, NULL}, /* GWY0038 - Telepath with v.90 */ {0x9062f91e, NULL}, /* GWY6290 - Telepath with x2 Technology */ {0x8100e425, NULL}, /* IOD0081 - I-O DATA DEVICE,INC. IFML-560 */ {0x71004d24, NULL}, /* IBM0071 - IBM ThinkPad 240 IrDA controller*/ {0x21002534, NULL}, /* MAE0021 - Jetstream Int V.90 56k Voice Series 2*/ {0x0000f435, NULL}, /* MOT0000 - Motorola ModemSURFR 33.6 Intern */ {0x5015f435, NULL}, /* MOT1550 - Motorola ModemSURFR 56K Modem */ {0xf015f435, NULL}, /* MOT15F0 - Motorola VoiceSURFR 56K Modem */ {0x6045f435, NULL}, /* MOT4560 - Motorola ? */ {0x61e7a338, NULL}, /* NECE761 - 33.6Modem */ {0x0160633a, NULL}, /* NSC6001 - National Semi's IrDA Controller*/ {0x08804f3f, NULL}, /* OZO8008 - Zoom (33.6k Modem) */ {0x0f804f3f, NULL}, /* OZO800f - Zoom 2812 (56k Modem) */ {0x39804f3f, NULL}, /* OZO8039 - Zoom 56k flex */ {0x00914f3f, NULL}, /* OZO9100 - Zoom 2919 (K56 Faxmodem) */ {0x3024a341, NULL}, /* PMC2430 - Pace 56 Voice Internal Modem */ {0x1000eb49, NULL}, /* ROK0010 - Rockwell ? */ {0x1200b23d, NULL}, /* RSS0012 - OMRON ME5614ISA */ {0x5002734a, NULL}, /* RSS0250 - 5614Jx3(G) Internal Modem */ {0x6202734a, NULL}, /* RSS0262 - 5614Jx3[G] V90+K56Flex Modem */ {0x1010104d, NULL}, /* SHP1010 - Rockwell 33600bps Modem */ {0x10f0a34d, NULL}, /* SMCF010 - SMC IrCC*/ {0xc100ad4d, NULL}, /* SMM00C1 - Leopard 56k PnP */ {0x9012b04e, NULL}, /* SUP1290 - Supra ? */ {0x1013b04e, NULL}, /* SUP1310 - SupraExpress 336i PnP */ {0x8013b04e, NULL}, /* SUP1380 - SupraExpress 288i PnP Voice */ {0x8113b04e, NULL}, /* SUP1381 - SupraExpress 336i PnP Voice */ {0x5016b04e, NULL}, /* SUP1650 - Supra 336i Sp Intl */ {0x7016b04e, NULL}, /* SUP1670 - Supra 336i V+ Intl */ {0x7420b04e, NULL}, /* SUP2070 - Supra ? */ {0x8020b04e, NULL}, /* SUP2080 - Supra ? */ {0x8420b04e, NULL}, /* SUP2084 - SupraExpress 56i PnP */ {0x7121b04e, NULL}, /* SUP2171 - SupraExpress 56i Sp? */ {0x8024b04e, NULL}, /* SUP2480 - Supra ? */ {0x01007256, NULL}, /* USR0001 - U.S. Robotics Inc., Sportster W */ {0x02007256, NULL}, /* USR0002 - U.S. Robotics Inc. Sportster 33. */ {0x04007256, NULL}, /* USR0004 - USR Sportster 14.4k */ {0x06007256, NULL}, /* USR0006 - USR Sportster 33.6k */ {0x11007256, NULL}, /* USR0011 - USR ? */ {0x01017256, NULL}, /* USR0101 - USR ? */ {0x30207256, NULL}, /* USR2030 - U.S.Robotics Inc. Sportster 560 */ {0x50207256, NULL}, /* USR2050 - U.S.Robotics Inc. Sportster 33. */ {0x70207256, NULL}, /* USR2070 - U.S.Robotics Inc. Sportster 560 */ {0x30307256, NULL}, /* USR3030 - U.S. Robotics 56K FAX INT */ {0x31307256, NULL}, /* USR3031 - U.S. Robotics 56K FAX INT */ {0x50307256, NULL}, /* USR3050 - U.S. Robotics 56K FAX INT */ {0x70307256, NULL}, /* USR3070 - U.S. Robotics 56K Voice INT */ {0x90307256, NULL}, /* USR3090 - USR ? */ {0x70917256, NULL}, /* USR9170 - U.S. Robotics 56K FAX INT */ {0x90917256, NULL}, /* USR9190 - USR 56k Voice INT */ {0x04f0235c, NULL}, /* WACF004 - Wacom Tablet PC Screen */ {0x0ef0235c, NULL}, /* WACF00e - Wacom Tablet PC Screen 00e */ {0x0300695c, NULL}, /* WCI0003 - Fax/Voice/Modem/Speakphone/Asvd */ {0x01a0896a, NULL}, /* ZTIA001 - Zoom Internal V90 Faxmodem */ {0x61f7896a, NULL}, /* ZTIF761 - Zoom ComStar 33.6 */ {0} }; static int uart_isa_probe(device_t dev) { struct uart_softc *sc; device_t parent; parent = device_get_parent(dev); sc = device_get_softc(dev); /* Check PnP IDs */ if (ISA_PNP_PROBE(parent, dev, isa_ns8250_ids) == ENXIO) return (ENXIO); /* Probe PnP _and_ non-PnP ns8250 here. */ sc->sc_class = &uart_ns8250_class; return (uart_bus_probe(dev, 0, 0, 0, 0, 0, 0)); } DRIVER_MODULE(uart, isa, uart_isa_driver, uart_devclass, 0, 0); ISA_PNP_INFO(isa_ns8250_ids); Index: head/sys/dev/uart/uart_bus_pccard.c =================================================================== --- head/sys/dev/uart/uart_bus_pccard.c (revision 355393) +++ head/sys/dev/uart/uart_bus_pccard.c (revision 355394) @@ -1,106 +1,106 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2001 M. Warner Losh. * Copyright (c) 2003 Norikatsu Shigemura, Takenori Watanabe All rights reserved. + * Copyright (c) 2001 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include "pccarddevs.h" static int uart_pccard_probe(device_t dev); static int uart_pccard_attach(device_t dev); static device_method_t uart_pccard_methods[] = { /* Device interface */ DEVMETHOD(device_probe, uart_pccard_probe), DEVMETHOD(device_attach, uart_pccard_attach), DEVMETHOD(device_detach, uart_bus_detach), { 0, 0 } }; static uint32_t uart_pccard_function = PCCARD_FUNCTION_SERIAL; static driver_t uart_pccard_driver = { uart_driver_name, uart_pccard_methods, sizeof(struct uart_softc), }; static int uart_pccard_probe(device_t dev) { int error; uint32_t fcn; fcn = PCCARD_FUNCTION_UNSPEC; error = pccard_get_function(dev, &fcn); if (error != 0) return (error); /* * If a serial card, we are likely the right driver. However, * some serial cards are better serviced by other drivers, so * allow other drivers to claim it, if they want. */ if (fcn == uart_pccard_function) return (BUS_PROBE_GENERIC); return (ENXIO); } static int uart_pccard_attach(device_t dev) { struct uart_softc *sc; int error; sc = device_get_softc(dev); sc->sc_class = &uart_ns8250_class; error = uart_bus_probe(dev, 0, 0, 0, 0, 0, 0); if (error > 0) return (error); return (uart_bus_attach(dev)); } DRIVER_MODULE(uart, pccard, uart_pccard_driver, uart_devclass, 0, 0); MODULE_PNP_INFO("U32:function_type;", pccard, uart, &uart_pccard_function, 1); Index: head/sys/dev/uart/uart_bus_pci.c =================================================================== --- head/sys/dev/uart/uart_bus_pci.c (revision 355393) +++ head/sys/dev/uart/uart_bus_pci.c (revision 355394) @@ -1,257 +1,256 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2006 Marcel Moolenaar - * Copyright (c) 2001 M. Warner Losh - * All rights reserved. + * Copyright (c) 2006 Marcel Moolenaar All rights reserved. + * Copyright (c) 2001 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #define DEFAULT_RCLK 1843200 static int uart_pci_probe(device_t dev); static int uart_pci_attach(device_t dev); static int uart_pci_detach(device_t dev); static device_method_t uart_pci_methods[] = { /* Device interface */ DEVMETHOD(device_probe, uart_pci_probe), DEVMETHOD(device_attach, uart_pci_attach), DEVMETHOD(device_detach, uart_pci_detach), DEVMETHOD(device_resume, uart_bus_resume), DEVMETHOD_END }; static driver_t uart_pci_driver = { uart_driver_name, uart_pci_methods, sizeof(struct uart_softc), }; struct pci_id { uint16_t vendor; uint16_t device; uint16_t subven; uint16_t subdev; const char *desc; int rid; int rclk; int regshft; }; static const struct pci_id pci_ns8250_ids[] = { { 0x1028, 0x0008, 0xffff, 0, "Dell Remote Access Card III", 0x14, 128 * DEFAULT_RCLK }, { 0x1028, 0x0012, 0xffff, 0, "Dell RAC 4 Daughter Card Virtual UART", 0x14, 128 * DEFAULT_RCLK }, { 0x1033, 0x0074, 0x1033, 0x8014, "NEC RCV56ACF 56k Voice Modem", 0x10 }, { 0x1033, 0x007d, 0x1033, 0x8012, "NEC RS232C", 0x10 }, { 0x103c, 0x1048, 0x103c, 0x1227, "HP Diva Serial [GSP] UART - Powerbar SP2", 0x10 }, { 0x103c, 0x1048, 0x103c, 0x1301, "HP Diva RMP3", 0x14 }, { 0x103c, 0x1290, 0xffff, 0, "HP Auxiliary Diva Serial Port", 0x18 }, { 0x103c, 0x3301, 0xffff, 0, "HP iLO serial port", 0x10 }, { 0x11c1, 0x0480, 0xffff, 0, "Agere Systems Venus Modem (V90, 56KFlex)", 0x14 }, { 0x115d, 0x0103, 0xffff, 0, "Xircom Cardbus Ethernet + 56k Modem", 0x10 }, { 0x125b, 0x9100, 0xa000, 0x1000, "ASIX AX99100 PCIe 1/2/3/4-port RS-232/422/485", 0x10 }, { 0x1282, 0x6585, 0xffff, 0, "Davicom 56PDV PCI Modem", 0x10 }, { 0x12b9, 0x1008, 0xffff, 0, "3Com 56K FaxModem Model 5610", 0x10 }, { 0x131f, 0x1000, 0xffff, 0, "Siig CyberSerial (1-port) 16550", 0x18 }, { 0x131f, 0x1001, 0xffff, 0, "Siig CyberSerial (1-port) 16650", 0x18 }, { 0x131f, 0x1002, 0xffff, 0, "Siig CyberSerial (1-port) 16850", 0x18 }, { 0x131f, 0x2000, 0xffff, 0, "Siig CyberSerial (1-port) 16550", 0x10 }, { 0x131f, 0x2001, 0xffff, 0, "Siig CyberSerial (1-port) 16650", 0x10 }, { 0x131f, 0x2002, 0xffff, 0, "Siig CyberSerial (1-port) 16850", 0x10 }, { 0x135c, 0x0190, 0xffff, 0, "Quatech SSCLP-100", 0x18 }, { 0x135c, 0x01c0, 0xffff, 0, "Quatech SSCLP-200/300", 0x18 }, { 0x135e, 0x7101, 0xffff, 0, "Sealevel Systems Single Port RS-232/422/485/530", 0x18 }, { 0x1407, 0x0110, 0xffff, 0, "Lava Computer mfg DSerial-PCI Port A", 0x10 }, { 0x1407, 0x0111, 0xffff, 0, "Lava Computer mfg DSerial-PCI Port B", 0x10 }, { 0x1407, 0x0510, 0xffff, 0, "Lava SP Serial 550 PCI", 0x10 }, { 0x1409, 0x7168, 0x1409, 0x4025, "Timedia Technology Serial Port", 0x10, 8 * DEFAULT_RCLK }, { 0x1409, 0x7168, 0x1409, 0x4027, "Timedia Technology Serial Port", 0x10, 8 * DEFAULT_RCLK }, { 0x1409, 0x7168, 0x1409, 0x4028, "Timedia Technology Serial Port", 0x10, 8 * DEFAULT_RCLK }, { 0x1409, 0x7168, 0x1409, 0x5025, "Timedia Technology Serial Port", 0x10, 8 * DEFAULT_RCLK }, { 0x1409, 0x7168, 0x1409, 0x5027, "Timedia Technology Serial Port", 0x10, 8 * DEFAULT_RCLK }, { 0x1415, 0x950b, 0xffff, 0, "Oxford Semiconductor OXCB950 Cardbus 16950 UART", 0x10, 16384000 }, { 0x1415, 0xc120, 0xffff, 0, "Oxford Semiconductor OXPCIe952 PCIe 16950 UART", 0x10 }, { 0x14e4, 0x160a, 0xffff, 0, "Broadcom TruManage UART", 0x10, 128 * DEFAULT_RCLK, 2}, { 0x14e4, 0x4344, 0xffff, 0, "Sony Ericsson GC89 PC Card", 0x10}, { 0x151f, 0x0000, 0xffff, 0, "TOPIC Semiconductor TP560 56k modem", 0x10 }, { 0x1d0f, 0x8250, 0x0000, 0, "Amazon PCI serial device", 0x10 }, { 0x1d0f, 0x8250, 0x1d0f, 0, "Amazon PCI serial device", 0x10 }, { 0x1fd4, 0x1999, 0x1fd4, 0x0001, "Sunix SER5xxxx Serial Port", 0x10, 8 * DEFAULT_RCLK }, { 0x8086, 0x0f0a, 0xffff, 0, "Intel ValleyView LPIO1 HSUART#1", 0x10, 24 * DEFAULT_RCLK, 2 }, { 0x8086, 0x0f0c, 0xffff, 0, "Intel ValleyView LPIO1 HSUART#2", 0x10, 24 * DEFAULT_RCLK, 2 }, { 0x8086, 0x108f, 0xffff, 0, "Intel AMT - SOL", 0x10 }, { 0x8086, 0x1c3d, 0xffff, 0, "Intel AMT - KT Controller", 0x10 }, { 0x8086, 0x1d3d, 0xffff, 0, "Intel C600/X79 Series Chipset KT Controller", 0x10 }, { 0x8086, 0x1e3d, 0xffff, 0, "Intel Panther Point KT Controller", 0x10 }, { 0x8086, 0x228a, 0xffff, 0, "Intel Cherryview SIO HSUART#1", 0x10, 24 * DEFAULT_RCLK, 2 }, { 0x8086, 0x228c, 0xffff, 0, "Intel Cherryview SIO HSUART#2", 0x10, 24 * DEFAULT_RCLK, 2 }, { 0x8086, 0x2a07, 0xffff, 0, "Intel AMT - PM965/GM965 KT Controller", 0x10 }, { 0x8086, 0x2a47, 0xffff, 0, "Mobile 4 Series Chipset KT Controller", 0x10 }, { 0x8086, 0x2e17, 0xffff, 0, "4 Series Chipset Serial KT Controller", 0x10 }, { 0x8086, 0x3b67, 0xffff, 0, "5 Series/3400 Series Chipset KT Controller", 0x10 }, { 0x8086, 0x8811, 0xffff, 0, "Intel EG20T Serial Port 0", 0x10 }, { 0x8086, 0x8812, 0xffff, 0, "Intel EG20T Serial Port 1", 0x10 }, { 0x8086, 0x8813, 0xffff, 0, "Intel EG20T Serial Port 2", 0x10 }, { 0x8086, 0x8814, 0xffff, 0, "Intel EG20T Serial Port 3", 0x10 }, { 0x8086, 0x8c3d, 0xffff, 0, "Intel Lynx Point KT Controller", 0x10 }, { 0x8086, 0x8cbd, 0xffff, 0, "Intel Wildcat Point KT Controller", 0x10 }, { 0x8086, 0x9c3d, 0xffff, 0, "Intel Lynx Point-LP HECI KT", 0x10 }, { 0x9710, 0x9820, 0x1000, 1, "NetMos NM9820 Serial Port", 0x10 }, { 0x9710, 0x9835, 0x1000, 1, "NetMos NM9835 Serial Port", 0x10 }, { 0x9710, 0x9865, 0xa000, 0x1000, "NetMos NM9865 Serial Port", 0x10 }, { 0x9710, 0x9900, 0xa000, 0x1000, "MosChip MCS9900 PCIe to Peripheral Controller", 0x10 }, { 0x9710, 0x9901, 0xa000, 0x1000, "MosChip MCS9901 PCIe to Peripheral Controller", 0x10 }, { 0x9710, 0x9904, 0xa000, 0x1000, "MosChip MCS9904 PCIe to Peripheral Controller", 0x10 }, { 0x9710, 0x9922, 0xa000, 0x1000, "MosChip MCS9922 PCIe to Peripheral Controller", 0x10 }, { 0xdeaf, 0x9051, 0xffff, 0, "Middle Digital PC Weasel Serial Port", 0x10 }, { 0xffff, 0, 0xffff, 0, NULL, 0, 0} }; const static struct pci_id * uart_pci_match(device_t dev, const struct pci_id *id) { uint16_t device, subdev, subven, vendor; vendor = pci_get_vendor(dev); device = pci_get_device(dev); while (id->vendor != 0xffff && (id->vendor != vendor || id->device != device)) id++; if (id->vendor == 0xffff) return (NULL); if (id->subven == 0xffff) return (id); subven = pci_get_subvendor(dev); subdev = pci_get_subdevice(dev); while (id->vendor == vendor && id->device == device && (id->subven != subven || id->subdev != subdev)) id++; return ((id->vendor == vendor && id->device == device) ? id : NULL); } static int uart_pci_probe(device_t dev) { struct uart_softc *sc; const struct pci_id *id; int result; sc = device_get_softc(dev); id = uart_pci_match(dev, pci_ns8250_ids); if (id != NULL) { sc->sc_class = &uart_ns8250_class; goto match; } /* Add checks for non-ns8250 IDs here. */ return (ENXIO); match: result = uart_bus_probe(dev, id->regshft, 0, id->rclk, id->rid, 0, 0); /* Bail out on error. */ if (result > 0) return (result); /* Set/override the device description. */ if (id->desc) device_set_desc(dev, id->desc); return (result); } static int uart_pci_attach(device_t dev) { struct uart_softc *sc; int count; sc = device_get_softc(dev); /* * Use MSI in preference to legacy IRQ if available. * Whilst some PCIe UARTs support >1 MSI vector, use only the first. */ if (pci_msi_count(dev) > 0) { count = 1; if (pci_alloc_msi(dev, &count) == 0) { sc->sc_irid = 1; device_printf(dev, "Using %d MSI message\n", count); } } return (uart_bus_attach(dev)); } static int uart_pci_detach(device_t dev) { struct uart_softc *sc; sc = device_get_softc(dev); if (sc->sc_irid != 0) pci_release_msi(dev); return (uart_bus_detach(dev)); } DRIVER_MODULE(uart, pci, uart_pci_driver, uart_devclass, NULL, NULL); Index: head/sys/dev/uart/uart_bus_puc.c =================================================================== --- head/sys/dev/uart/uart_bus_puc.c (revision 355393) +++ head/sys/dev/uart/uart_bus_puc.c (revision 355394) @@ -1,89 +1,89 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2006 Marcel Moolenaar. All rights reserved. * Copyright (c) 2002 JF Hay. All rights reserved. - * Copyright (c) 2001 M. Warner Losh. + * Copyright (c) 2001 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include static int uart_puc_probe(device_t dev); static device_method_t uart_puc_methods[] = { /* Device interface */ DEVMETHOD(device_probe, uart_puc_probe), DEVMETHOD(device_attach, uart_bus_attach), DEVMETHOD(device_detach, uart_bus_detach), /* Serdev interface */ DEVMETHOD(serdev_ihand, uart_bus_ihand), DEVMETHOD(serdev_ipend, uart_bus_ipend), { 0, 0 } }; static driver_t uart_puc_driver = { uart_driver_name, uart_puc_methods, sizeof(struct uart_softc), }; static int uart_puc_probe(device_t dev) { device_t parent; struct uart_softc *sc; uintptr_t rclk, type; parent = device_get_parent(dev); sc = device_get_softc(dev); if (BUS_READ_IVAR(parent, dev, PUC_IVAR_TYPE, &type)) return (ENXIO); if (type != PUC_TYPE_SERIAL) return (ENXIO); sc->sc_class = &uart_ns8250_class; if (BUS_READ_IVAR(parent, dev, PUC_IVAR_CLOCK, &rclk)) rclk = 0; return (uart_bus_probe(dev, 0, 0, rclk, 0, 0, 0)); } DRIVER_MODULE(uart, puc, uart_puc_driver, uart_devclass, 0, 0); Index: head/sys/dev/usb/controller/generic_ohci.c =================================================================== --- head/sys/dev/usb/controller/generic_ohci.c (revision 355393) +++ head/sys/dev/usb/controller/generic_ohci.c (revision 355394) @@ -1,348 +1,348 @@ /*- - * Copyright (c) 2006 M. Warner Losh. * Copyright (c) 2016 Emmanuel Vadot All rights reserved. + * Copyright (c) 2006 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Generic OHCI driver based on AT91 OHCI */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef EXT_RESOURCES #include #include #include #include #endif #include "generic_usb_if.h" #ifdef EXT_RESOURCES struct clk_list { TAILQ_ENTRY(clk_list) next; clk_t clk; }; struct phy_list { TAILQ_ENTRY(phy_list) next; phy_t phy; }; struct hwrst_list { TAILQ_ENTRY(hwrst_list) next; hwreset_t rst; }; #endif struct generic_ohci_softc { ohci_softc_t ohci_sc; #ifdef EXT_RESOURCES TAILQ_HEAD(, clk_list) clk_list; TAILQ_HEAD(, phy_list) phy_list; TAILQ_HEAD(, hwrst_list) rst_list; #endif }; static int generic_ohci_detach(device_t); static int generic_ohci_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (!ofw_bus_is_compatible(dev, "generic-ohci")) return (ENXIO); device_set_desc(dev, "Generic OHCI Controller"); return (BUS_PROBE_DEFAULT); } static int generic_ohci_attach(device_t dev) { struct generic_ohci_softc *sc = device_get_softc(dev); int err, rid; #ifdef EXT_RESOURCES int off; struct clk_list *clkp; struct phy_list *phyp; struct hwrst_list *rstp; clk_t clk; phy_t phy; hwreset_t rst; #endif sc->ohci_sc.sc_bus.parent = dev; sc->ohci_sc.sc_bus.devices = sc->ohci_sc.sc_devices; sc->ohci_sc.sc_bus.devices_max = OHCI_MAX_DEVICES; sc->ohci_sc.sc_bus.dma_bits = 32; /* get all DMA memory */ if (usb_bus_mem_alloc_all(&sc->ohci_sc.sc_bus, USB_GET_DMA_TAG(dev), &ohci_iterate_hw_softc)) { return (ENOMEM); } rid = 0; sc->ohci_sc.sc_io_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (sc->ohci_sc.sc_io_res == 0) { err = ENOMEM; goto error; } sc->ohci_sc.sc_io_tag = rman_get_bustag(sc->ohci_sc.sc_io_res); sc->ohci_sc.sc_io_hdl = rman_get_bushandle(sc->ohci_sc.sc_io_res); sc->ohci_sc.sc_io_size = rman_get_size(sc->ohci_sc.sc_io_res); rid = 0; sc->ohci_sc.sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE); if (sc->ohci_sc.sc_irq_res == 0) { err = ENXIO; goto error; } sc->ohci_sc.sc_bus.bdev = device_add_child(dev, "usbus", -1); if (sc->ohci_sc.sc_bus.bdev == 0) { err = ENXIO; goto error; } device_set_ivars(sc->ohci_sc.sc_bus.bdev, &sc->ohci_sc.sc_bus); strlcpy(sc->ohci_sc.sc_vendor, "Generic", sizeof(sc->ohci_sc.sc_vendor)); err = bus_setup_intr(dev, sc->ohci_sc.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, NULL, (driver_intr_t *)ohci_interrupt, sc, &sc->ohci_sc.sc_intr_hdl); if (err) { sc->ohci_sc.sc_intr_hdl = NULL; goto error; } #ifdef EXT_RESOURCES TAILQ_INIT(&sc->clk_list); /* Enable clock */ for (off = 0; clk_get_by_ofw_index(dev, 0, off, &clk) == 0; off++) { err = clk_enable(clk); if (err != 0) { device_printf(dev, "Could not enable clock %s\n", clk_get_name(clk)); goto error; } clkp = malloc(sizeof(*clkp), M_DEVBUF, M_WAITOK | M_ZERO); clkp->clk = clk; TAILQ_INSERT_TAIL(&sc->clk_list, clkp, next); } /* De-assert reset */ TAILQ_INIT(&sc->rst_list); for (off = 0; hwreset_get_by_ofw_idx(dev, 0, off, &rst) == 0; off++) { err = hwreset_deassert(rst); if (err != 0) { device_printf(dev, "Could not de-assert reset\n"); goto error; } rstp = malloc(sizeof(*rstp), M_DEVBUF, M_WAITOK | M_ZERO); rstp->rst = rst; TAILQ_INSERT_TAIL(&sc->rst_list, rstp, next); } /* Enable phy */ TAILQ_INIT(&sc->phy_list); for (off = 0; phy_get_by_ofw_idx(dev, 0, off, &phy) == 0; off++) { err = phy_usb_set_mode(phy, PHY_USB_MODE_HOST); if (err != 0) { device_printf(dev, "Could not set phy to host mode\n"); goto error; } err = phy_enable(phy); if (err != 0) { device_printf(dev, "Could not enable phy\n"); goto error; } phyp = malloc(sizeof(*phyp), M_DEVBUF, M_WAITOK | M_ZERO); phyp->phy = phy; TAILQ_INSERT_TAIL(&sc->phy_list, phyp, next); } #endif if (GENERIC_USB_INIT(dev) != 0) { err = ENXIO; goto error; } err = ohci_init(&sc->ohci_sc); if (err == 0) err = device_probe_and_attach(sc->ohci_sc.sc_bus.bdev); if (err) goto error; return (0); error: generic_ohci_detach(dev); return (err); } static int generic_ohci_detach(device_t dev) { struct generic_ohci_softc *sc = device_get_softc(dev); int err; #ifdef EXT_RESOURCES struct clk_list *clk, *clk_tmp; struct phy_list *phy, *phy_tmp; struct hwrst_list *rst, *rst_tmp; #endif /* during module unload there are lots of children leftover */ device_delete_children(dev); /* * Put the controller into reset, then disable clocks and do * the MI tear down. We have to disable the clocks/hardware * after we do the rest of the teardown. We also disable the * clocks in the opposite order we acquire them, but that * doesn't seem to be absolutely necessary. We free up the * clocks after we disable them, so the system could, in * theory, reuse them. */ bus_space_write_4(sc->ohci_sc.sc_io_tag, sc->ohci_sc.sc_io_hdl, OHCI_CONTROL, 0); if (sc->ohci_sc.sc_irq_res && sc->ohci_sc.sc_intr_hdl) { /* * only call ohci_detach() after ohci_init() */ ohci_detach(&sc->ohci_sc); err = bus_teardown_intr(dev, sc->ohci_sc.sc_irq_res, sc->ohci_sc.sc_intr_hdl); sc->ohci_sc.sc_intr_hdl = NULL; } if (sc->ohci_sc.sc_irq_res) { bus_release_resource(dev, SYS_RES_IRQ, 0, sc->ohci_sc.sc_irq_res); sc->ohci_sc.sc_irq_res = NULL; } if (sc->ohci_sc.sc_io_res) { bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->ohci_sc.sc_io_res); sc->ohci_sc.sc_io_res = NULL; } usb_bus_mem_free_all(&sc->ohci_sc.sc_bus, &ohci_iterate_hw_softc); #ifdef EXT_RESOURCES /* Disable phy */ TAILQ_FOREACH_SAFE(phy, &sc->phy_list, next, phy_tmp) { err = phy_disable(phy->phy); if (err != 0) device_printf(dev, "Could not disable phy\n"); phy_release(phy->phy); TAILQ_REMOVE(&sc->phy_list, phy, next); free(phy, M_DEVBUF); } /* Assert reset */ TAILQ_FOREACH_SAFE(rst, &sc->rst_list, next, rst_tmp) { hwreset_assert(rst->rst); hwreset_release(rst->rst); TAILQ_REMOVE(&sc->rst_list, rst, next); free(rst, M_DEVBUF); } /* Disable clock */ TAILQ_FOREACH_SAFE(clk, &sc->clk_list, next, clk_tmp) { err = clk_disable(clk->clk); if (err != 0) device_printf(dev, "Could not disable clock %s\n", clk_get_name(clk->clk)); err = clk_release(clk->clk); if (err != 0) device_printf(dev, "Could not release clock %s\n", clk_get_name(clk->clk)); TAILQ_REMOVE(&sc->clk_list, clk, next); free(clk, M_DEVBUF); } #endif if (GENERIC_USB_DEINIT(dev) != 0) return (ENXIO); return (0); } static device_method_t generic_ohci_methods[] = { /* Device interface */ DEVMETHOD(device_probe, generic_ohci_probe), DEVMETHOD(device_attach, generic_ohci_attach), DEVMETHOD(device_detach, generic_ohci_detach), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD_END }; driver_t generic_ohci_driver = { .name = "ohci", .methods = generic_ohci_methods, .size = sizeof(struct generic_ohci_softc), }; static devclass_t generic_ohci_devclass; DRIVER_MODULE(ohci, simplebus, generic_ohci_driver, generic_ohci_devclass, 0, 0); MODULE_DEPEND(ohci, usb, 1, 1, 1); Index: head/sys/dev/usb/misc/ufm.c =================================================================== --- head/sys/dev/usb/misc/ufm.c (revision 355393) +++ head/sys/dev/usb/misc/ufm.c (revision 355394) @@ -1,340 +1,339 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2001 M. Warner Losh - * All rights reserved. + * Copyright (c) 2001 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions, and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * This code is based on ugen.c and ulpt.c developed by Lennart Augustsson. * This code includes software developed by the NetBSD Foundation, Inc. and * its contributors. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "usbdevs.h" #define USB_DEBUG_VAR usb_debug #include #include #define UFM_CMD0 0x00 #define UFM_CMD_SET_FREQ 0x01 #define UFM_CMD2 0x02 struct ufm_softc { struct usb_fifo_sc sc_fifo; struct mtx sc_mtx; struct usb_device *sc_udev; uint32_t sc_unit; uint32_t sc_freq; uint8_t sc_name[16]; }; /* prototypes */ static device_probe_t ufm_probe; static device_attach_t ufm_attach; static device_detach_t ufm_detach; static usb_fifo_ioctl_t ufm_ioctl; static struct usb_fifo_methods ufm_fifo_methods = { .f_ioctl = &ufm_ioctl, .basename[0] = "ufm", }; static int ufm_do_req(struct ufm_softc *, uint8_t, uint16_t, uint16_t, uint8_t *); static int ufm_set_freq(struct ufm_softc *, void *); static int ufm_get_freq(struct ufm_softc *, void *); static int ufm_start(struct ufm_softc *, void *); static int ufm_stop(struct ufm_softc *, void *); static int ufm_get_stat(struct ufm_softc *, void *); static devclass_t ufm_devclass; static device_method_t ufm_methods[] = { DEVMETHOD(device_probe, ufm_probe), DEVMETHOD(device_attach, ufm_attach), DEVMETHOD(device_detach, ufm_detach), DEVMETHOD_END }; static driver_t ufm_driver = { .name = "ufm", .methods = ufm_methods, .size = sizeof(struct ufm_softc), }; static const STRUCT_USB_HOST_ID ufm_devs[] = { {USB_VPI(USB_VENDOR_CYPRESS, USB_PRODUCT_CYPRESS_FMRADIO, 0)}, }; DRIVER_MODULE(ufm, uhub, ufm_driver, ufm_devclass, NULL, 0); MODULE_DEPEND(ufm, usb, 1, 1, 1); MODULE_VERSION(ufm, 1); USB_PNP_HOST_INFO(ufm_devs); static int ufm_probe(device_t dev) { struct usb_attach_arg *uaa = device_get_ivars(dev); if (uaa->usb_mode != USB_MODE_HOST) return (ENXIO); if (uaa->info.bConfigIndex != 0) return (ENXIO); if (uaa->info.bIfaceIndex != 0) return (ENXIO); return (usbd_lookup_id_by_uaa(ufm_devs, sizeof(ufm_devs), uaa)); } static int ufm_attach(device_t dev) { struct usb_attach_arg *uaa = device_get_ivars(dev); struct ufm_softc *sc = device_get_softc(dev); int error; sc->sc_udev = uaa->device; sc->sc_unit = device_get_unit(dev); snprintf(sc->sc_name, sizeof(sc->sc_name), "%s", device_get_nameunit(dev)); mtx_init(&sc->sc_mtx, "ufm lock", NULL, MTX_DEF | MTX_RECURSE); device_set_usb_desc(dev); error = usb_fifo_attach(uaa->device, sc, &sc->sc_mtx, &ufm_fifo_methods, &sc->sc_fifo, device_get_unit(dev), -1, uaa->info.bIfaceIndex, UID_ROOT, GID_OPERATOR, 0644); if (error) { goto detach; } return (0); /* success */ detach: ufm_detach(dev); return (ENXIO); } static int ufm_detach(device_t dev) { struct ufm_softc *sc = device_get_softc(dev); usb_fifo_detach(&sc->sc_fifo); mtx_destroy(&sc->sc_mtx); return (0); } static int ufm_do_req(struct ufm_softc *sc, uint8_t request, uint16_t value, uint16_t index, uint8_t *retbuf) { int error; struct usb_device_request req; uint8_t buf[1]; req.bmRequestType = UT_READ_VENDOR_DEVICE; req.bRequest = request; USETW(req.wValue, value); USETW(req.wIndex, index); USETW(req.wLength, 1); error = usbd_do_request(sc->sc_udev, NULL, &req, buf); if (retbuf) { *retbuf = buf[0]; } if (error) { return (ENXIO); } return (0); } static int ufm_set_freq(struct ufm_softc *sc, void *addr) { int freq = *(int *)addr; /* * Freq now is in Hz. We need to convert it to the frequency * that the radio wants. This frequency is 10.7MHz above * the actual frequency. We then need to convert to * units of 12.5kHz. We add one to the IFM to make rounding * easier. */ mtx_lock(&sc->sc_mtx); sc->sc_freq = freq; mtx_unlock(&sc->sc_mtx); freq = (freq + 10700001) / 12500; /* This appears to set the frequency */ if (ufm_do_req(sc, UFM_CMD_SET_FREQ, freq >> 8, freq, NULL) != 0) { return (EIO); } /* Not sure what this does */ if (ufm_do_req(sc, UFM_CMD0, 0x96, 0xb7, NULL) != 0) { return (EIO); } return (0); } static int ufm_get_freq(struct ufm_softc *sc, void *addr) { int *valp = (int *)addr; mtx_lock(&sc->sc_mtx); *valp = sc->sc_freq; mtx_unlock(&sc->sc_mtx); return (0); } static int ufm_start(struct ufm_softc *sc, void *addr) { uint8_t ret; if (ufm_do_req(sc, UFM_CMD0, 0x00, 0xc7, &ret)) { return (EIO); } if (ufm_do_req(sc, UFM_CMD2, 0x01, 0x00, &ret)) { return (EIO); } if (ret & 0x1) { return (EIO); } return (0); } static int ufm_stop(struct ufm_softc *sc, void *addr) { if (ufm_do_req(sc, UFM_CMD0, 0x16, 0x1C, NULL)) { return (EIO); } if (ufm_do_req(sc, UFM_CMD2, 0x00, 0x00, NULL)) { return (EIO); } return (0); } static int ufm_get_stat(struct ufm_softc *sc, void *addr) { uint8_t ret; /* * Note, there's a 240ms settle time before the status * will be valid, so sleep that amount. */ usb_pause_mtx(NULL, hz / 4); if (ufm_do_req(sc, UFM_CMD0, 0x00, 0x24, &ret)) { return (EIO); } *(int *)addr = ret; return (0); } static int ufm_ioctl(struct usb_fifo *fifo, u_long cmd, void *addr, int fflags) { struct ufm_softc *sc = usb_fifo_softc(fifo); int error = 0; if ((fflags & (FWRITE | FREAD)) != (FWRITE | FREAD)) { return (EACCES); } switch (cmd) { case FM_SET_FREQ: error = ufm_set_freq(sc, addr); break; case FM_GET_FREQ: error = ufm_get_freq(sc, addr); break; case FM_START: error = ufm_start(sc, addr); break; case FM_STOP: error = ufm_stop(sc, addr); break; case FM_GET_STAT: error = ufm_get_stat(sc, addr); break; default: error = ENOTTY; break; } return (error); } Index: head/sys/dev/usb/serial/ufoma.c =================================================================== --- head/sys/dev/usb/serial/ufoma.c (revision 355393) +++ head/sys/dev/usb/serial/ufoma.c (revision 355394) @@ -1,1270 +1,1269 @@ /* $NetBSD: umodem.c,v 1.45 2002/09/23 05:51:23 simonb Exp $ */ #include __FBSDID("$FreeBSD$"); #define UFOMA_HANDSFREE /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD AND BSD-2-Clause-NetBSD * - * Copyright (c) 2005, Takanori Watanabe - * Copyright (c) 2003, M. Warner Losh . - * All rights reserved. + * Copyright (c) 2005, Takanori Watanabe All rights reserved. + * Copyright (c) 2003 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /*- * Copyright (c) 1998 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Lennart Augustsson (lennart@augustsson.net) at * Carlstedt Research & Technology. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * Comm Class spec: http://www.usb.org/developers/devclass_docs/usbccs10.pdf * http://www.usb.org/developers/devclass_docs/usbcdc11.pdf */ /* * TODO: * - Implement a Call Device for modems without multiplexed commands. */ /* * NOTE: all function names beginning like "ufoma_cfg_" can only * be called from within the config thread function ! */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "usbdevs.h" #define USB_DEBUG_VAR usb_debug #include #include #include typedef struct ufoma_mobile_acm_descriptor { uint8_t bFunctionLength; uint8_t bDescriptorType; uint8_t bDescriptorSubtype; uint8_t bType; uint8_t bMode[1]; } __packed usb_mcpc_acm_descriptor; #define UISUBCLASS_MCPC 0x88 #define UDESC_VS_INTERFACE 0x44 #define UDESCSUB_MCPC_ACM 0x11 #define UMCPC_ACM_TYPE_AB1 0x1 #define UMCPC_ACM_TYPE_AB2 0x2 #define UMCPC_ACM_TYPE_AB5 0x5 #define UMCPC_ACM_TYPE_AB6 0x6 #define UMCPC_ACM_MODE_DEACTIVATED 0x0 #define UMCPC_ACM_MODE_MODEM 0x1 #define UMCPC_ACM_MODE_ATCOMMAND 0x2 #define UMCPC_ACM_MODE_OBEX 0x60 #define UMCPC_ACM_MODE_VENDOR1 0xc0 #define UMCPC_ACM_MODE_VENDOR2 0xfe #define UMCPC_ACM_MODE_UNLINKED 0xff #define UMCPC_CM_MOBILE_ACM 0x0 #define UMCPC_ACTIVATE_MODE 0x60 #define UMCPC_GET_MODETABLE 0x61 #define UMCPC_SET_LINK 0x62 #define UMCPC_CLEAR_LINK 0x63 #define UMCPC_REQUEST_ACKNOWLEDGE 0x31 #define UFOMA_MAX_TIMEOUT 15 /* standard says 10 seconds */ #define UFOMA_CMD_BUF_SIZE 64 /* bytes */ #define UFOMA_BULK_BUF_SIZE 1024 /* bytes */ enum { UFOMA_CTRL_ENDPT_INTR, UFOMA_CTRL_ENDPT_READ, UFOMA_CTRL_ENDPT_WRITE, UFOMA_CTRL_ENDPT_MAX, }; enum { UFOMA_BULK_ENDPT_WRITE, UFOMA_BULK_ENDPT_READ, UFOMA_BULK_ENDPT_MAX, }; struct ufoma_softc { struct ucom_super_softc sc_super_ucom; struct ucom_softc sc_ucom; struct cv sc_cv; struct mtx sc_mtx; struct usb_xfer *sc_ctrl_xfer[UFOMA_CTRL_ENDPT_MAX]; struct usb_xfer *sc_bulk_xfer[UFOMA_BULK_ENDPT_MAX]; uint8_t *sc_modetable; device_t sc_dev; struct usb_device *sc_udev; uint32_t sc_unit; uint16_t sc_line; uint8_t sc_num_msg; uint8_t sc_nobulk; uint8_t sc_ctrl_iface_no; uint8_t sc_ctrl_iface_index; uint8_t sc_data_iface_no; uint8_t sc_data_iface_index; uint8_t sc_cm_cap; uint8_t sc_acm_cap; uint8_t sc_lsr; uint8_t sc_msr; uint8_t sc_modetoactivate; uint8_t sc_currentmode; }; /* prototypes */ static device_probe_t ufoma_probe; static device_attach_t ufoma_attach; static device_detach_t ufoma_detach; static void ufoma_free_softc(struct ufoma_softc *); static usb_callback_t ufoma_ctrl_read_callback; static usb_callback_t ufoma_ctrl_write_callback; static usb_callback_t ufoma_intr_callback; static usb_callback_t ufoma_bulk_write_callback; static usb_callback_t ufoma_bulk_read_callback; static void *ufoma_get_intconf(struct usb_config_descriptor *, struct usb_interface_descriptor *, uint8_t, uint8_t); static void ufoma_cfg_link_state(struct ufoma_softc *); static void ufoma_cfg_activate_state(struct ufoma_softc *, uint16_t); static void ufoma_free(struct ucom_softc *); static void ufoma_cfg_open(struct ucom_softc *); static void ufoma_cfg_close(struct ucom_softc *); static void ufoma_cfg_set_break(struct ucom_softc *, uint8_t); static void ufoma_cfg_get_status(struct ucom_softc *, uint8_t *, uint8_t *); static void ufoma_cfg_set_dtr(struct ucom_softc *, uint8_t); static void ufoma_cfg_set_rts(struct ucom_softc *, uint8_t); static int ufoma_pre_param(struct ucom_softc *, struct termios *); static void ufoma_cfg_param(struct ucom_softc *, struct termios *); static int ufoma_modem_setup(device_t, struct ufoma_softc *, struct usb_attach_arg *); static void ufoma_start_read(struct ucom_softc *); static void ufoma_stop_read(struct ucom_softc *); static void ufoma_start_write(struct ucom_softc *); static void ufoma_stop_write(struct ucom_softc *); static void ufoma_poll(struct ucom_softc *ucom); /*sysctl stuff*/ static int ufoma_sysctl_support(SYSCTL_HANDLER_ARGS); static int ufoma_sysctl_current(SYSCTL_HANDLER_ARGS); static int ufoma_sysctl_open(SYSCTL_HANDLER_ARGS); static const struct usb_config ufoma_ctrl_config[UFOMA_CTRL_ENDPT_MAX] = { [UFOMA_CTRL_ENDPT_INTR] = { .type = UE_INTERRUPT, .endpoint = UE_ADDR_ANY, .direction = UE_DIR_IN, .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, .bufsize = sizeof(struct usb_cdc_notification), .callback = &ufoma_intr_callback, }, [UFOMA_CTRL_ENDPT_READ] = { .type = UE_CONTROL, .endpoint = 0x00, /* Control pipe */ .direction = UE_DIR_ANY, .bufsize = (sizeof(struct usb_device_request) + UFOMA_CMD_BUF_SIZE), .flags = {.short_xfer_ok = 1,}, .callback = &ufoma_ctrl_read_callback, .timeout = 1000, /* 1 second */ }, [UFOMA_CTRL_ENDPT_WRITE] = { .type = UE_CONTROL, .endpoint = 0x00, /* Control pipe */ .direction = UE_DIR_ANY, .bufsize = (sizeof(struct usb_device_request) + 1), .callback = &ufoma_ctrl_write_callback, .timeout = 1000, /* 1 second */ }, }; static const struct usb_config ufoma_bulk_config[UFOMA_BULK_ENDPT_MAX] = { [UFOMA_BULK_ENDPT_WRITE] = { .type = UE_BULK, .endpoint = UE_ADDR_ANY, .direction = UE_DIR_OUT, .bufsize = UFOMA_BULK_BUF_SIZE, .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, .callback = &ufoma_bulk_write_callback, }, [UFOMA_BULK_ENDPT_READ] = { .type = UE_BULK, .endpoint = UE_ADDR_ANY, .direction = UE_DIR_IN, .bufsize = UFOMA_BULK_BUF_SIZE, .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, .callback = &ufoma_bulk_read_callback, }, }; static const struct ucom_callback ufoma_callback = { .ucom_cfg_get_status = &ufoma_cfg_get_status, .ucom_cfg_set_dtr = &ufoma_cfg_set_dtr, .ucom_cfg_set_rts = &ufoma_cfg_set_rts, .ucom_cfg_set_break = &ufoma_cfg_set_break, .ucom_cfg_param = &ufoma_cfg_param, .ucom_cfg_open = &ufoma_cfg_open, .ucom_cfg_close = &ufoma_cfg_close, .ucom_pre_param = &ufoma_pre_param, .ucom_start_read = &ufoma_start_read, .ucom_stop_read = &ufoma_stop_read, .ucom_start_write = &ufoma_start_write, .ucom_stop_write = &ufoma_stop_write, .ucom_poll = &ufoma_poll, .ucom_free = &ufoma_free, }; static device_method_t ufoma_methods[] = { /* Device methods */ DEVMETHOD(device_probe, ufoma_probe), DEVMETHOD(device_attach, ufoma_attach), DEVMETHOD(device_detach, ufoma_detach), DEVMETHOD_END }; static devclass_t ufoma_devclass; static driver_t ufoma_driver = { .name = "ufoma", .methods = ufoma_methods, .size = sizeof(struct ufoma_softc), }; static const STRUCT_USB_HOST_ID ufoma_devs[] = { {USB_IFACE_CLASS(UICLASS_CDC), USB_IFACE_SUBCLASS(UISUBCLASS_MCPC),}, }; DRIVER_MODULE(ufoma, uhub, ufoma_driver, ufoma_devclass, NULL, 0); MODULE_DEPEND(ufoma, ucom, 1, 1, 1); MODULE_DEPEND(ufoma, usb, 1, 1, 1); MODULE_VERSION(ufoma, 1); USB_PNP_HOST_INFO(ufoma_devs); static int ufoma_probe(device_t dev) { struct usb_attach_arg *uaa = device_get_ivars(dev); struct usb_interface_descriptor *id; struct usb_config_descriptor *cd; usb_mcpc_acm_descriptor *mad; int error; if (uaa->usb_mode != USB_MODE_HOST) return (ENXIO); error = usbd_lookup_id_by_uaa(ufoma_devs, sizeof(ufoma_devs), uaa); if (error) return (error); id = usbd_get_interface_descriptor(uaa->iface); cd = usbd_get_config_descriptor(uaa->device); if (id == NULL || cd == NULL) return (ENXIO); mad = ufoma_get_intconf(cd, id, UDESC_VS_INTERFACE, UDESCSUB_MCPC_ACM); if (mad == NULL) return (ENXIO); #ifndef UFOMA_HANDSFREE if ((mad->bType == UMCPC_ACM_TYPE_AB5) || (mad->bType == UMCPC_ACM_TYPE_AB6)) return (ENXIO); #endif return (BUS_PROBE_GENERIC); } static int ufoma_attach(device_t dev) { struct usb_attach_arg *uaa = device_get_ivars(dev); struct ufoma_softc *sc = device_get_softc(dev); struct usb_config_descriptor *cd; struct usb_interface_descriptor *id; struct sysctl_ctx_list *sctx; struct sysctl_oid *soid; usb_mcpc_acm_descriptor *mad; uint8_t elements; int32_t error; sc->sc_udev = uaa->device; sc->sc_dev = dev; sc->sc_unit = device_get_unit(dev); mtx_init(&sc->sc_mtx, "ufoma", NULL, MTX_DEF); ucom_ref(&sc->sc_super_ucom); cv_init(&sc->sc_cv, "CWAIT"); device_set_usb_desc(dev); DPRINTF("\n"); /* setup control transfers */ cd = usbd_get_config_descriptor(uaa->device); id = usbd_get_interface_descriptor(uaa->iface); sc->sc_ctrl_iface_no = id->bInterfaceNumber; sc->sc_ctrl_iface_index = uaa->info.bIfaceIndex; error = usbd_transfer_setup(uaa->device, &sc->sc_ctrl_iface_index, sc->sc_ctrl_xfer, ufoma_ctrl_config, UFOMA_CTRL_ENDPT_MAX, sc, &sc->sc_mtx); if (error) { device_printf(dev, "allocating control USB " "transfers failed\n"); goto detach; } mad = ufoma_get_intconf(cd, id, UDESC_VS_INTERFACE, UDESCSUB_MCPC_ACM); if (mad == NULL) { goto detach; } if (mad->bFunctionLength < sizeof(*mad)) { device_printf(dev, "invalid MAD descriptor\n"); goto detach; } if ((mad->bType == UMCPC_ACM_TYPE_AB5) || (mad->bType == UMCPC_ACM_TYPE_AB6)) { sc->sc_nobulk = 1; } else { sc->sc_nobulk = 0; if (ufoma_modem_setup(dev, sc, uaa)) { goto detach; } } elements = (mad->bFunctionLength - sizeof(*mad) + 1); /* initialize mode variables */ sc->sc_modetable = malloc(elements + 1, M_USBDEV, M_WAITOK); if (sc->sc_modetable == NULL) { goto detach; } sc->sc_modetable[0] = (elements + 1); memcpy(&sc->sc_modetable[1], mad->bMode, elements); sc->sc_currentmode = UMCPC_ACM_MODE_UNLINKED; sc->sc_modetoactivate = mad->bMode[0]; /* clear stall at first run, if any */ mtx_lock(&sc->sc_mtx); usbd_xfer_set_stall(sc->sc_bulk_xfer[UFOMA_BULK_ENDPT_WRITE]); usbd_xfer_set_stall(sc->sc_bulk_xfer[UFOMA_BULK_ENDPT_READ]); mtx_unlock(&sc->sc_mtx); error = ucom_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc, &ufoma_callback, &sc->sc_mtx); if (error) { DPRINTF("ucom_attach failed\n"); goto detach; } ucom_set_pnpinfo_usb(&sc->sc_super_ucom, dev); /*Sysctls*/ sctx = device_get_sysctl_ctx(dev); soid = device_get_sysctl_tree(dev); SYSCTL_ADD_PROC(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "supportmode", CTLFLAG_RD|CTLTYPE_STRING, sc, 0, ufoma_sysctl_support, "A", "Supporting port role"); SYSCTL_ADD_PROC(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "currentmode", CTLFLAG_RD|CTLTYPE_STRING, sc, 0, ufoma_sysctl_current, "A", "Current port role"); SYSCTL_ADD_PROC(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "openmode", CTLFLAG_RW|CTLTYPE_STRING, sc, 0, ufoma_sysctl_open, "A", "Mode to transit when port is opened"); SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "comunit", CTLFLAG_RD, &(sc->sc_super_ucom.sc_unit), 0, "Unit number as USB serial"); return (0); /* success */ detach: ufoma_detach(dev); return (ENXIO); /* failure */ } static int ufoma_detach(device_t dev) { struct ufoma_softc *sc = device_get_softc(dev); ucom_detach(&sc->sc_super_ucom, &sc->sc_ucom); usbd_transfer_unsetup(sc->sc_ctrl_xfer, UFOMA_CTRL_ENDPT_MAX); usbd_transfer_unsetup(sc->sc_bulk_xfer, UFOMA_BULK_ENDPT_MAX); if (sc->sc_modetable) { free(sc->sc_modetable, M_USBDEV); } cv_destroy(&sc->sc_cv); device_claim_softc(dev); ufoma_free_softc(sc); return (0); } UCOM_UNLOAD_DRAIN(ufoma); static void ufoma_free_softc(struct ufoma_softc *sc) { if (ucom_unref(&sc->sc_super_ucom)) { mtx_destroy(&sc->sc_mtx); device_free_softc(sc); } } static void ufoma_free(struct ucom_softc *ucom) { ufoma_free_softc(ucom->sc_parent); } static void * ufoma_get_intconf(struct usb_config_descriptor *cd, struct usb_interface_descriptor *id, uint8_t type, uint8_t subtype) { struct usb_descriptor *desc = (void *)id; while ((desc = usb_desc_foreach(cd, desc))) { if (desc->bDescriptorType == UDESC_INTERFACE) { return (NULL); } if ((desc->bDescriptorType == type) && (desc->bDescriptorSubtype == subtype)) { break; } } return (desc); } static void ufoma_cfg_link_state(struct ufoma_softc *sc) { struct usb_device_request req; int32_t error; req.bmRequestType = UT_WRITE_VENDOR_INTERFACE; req.bRequest = UMCPC_SET_LINK; USETW(req.wValue, UMCPC_CM_MOBILE_ACM); USETW(req.wIndex, sc->sc_ctrl_iface_no); USETW(req.wLength, sc->sc_modetable[0]); ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, &req, sc->sc_modetable, 0, 1000); error = cv_timedwait(&sc->sc_cv, &sc->sc_mtx, hz); if (error) { DPRINTF("NO response\n"); } } static void ufoma_cfg_activate_state(struct ufoma_softc *sc, uint16_t state) { struct usb_device_request req; int32_t error; req.bmRequestType = UT_WRITE_VENDOR_INTERFACE; req.bRequest = UMCPC_ACTIVATE_MODE; USETW(req.wValue, state); USETW(req.wIndex, sc->sc_ctrl_iface_no); USETW(req.wLength, 0); ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, &req, NULL, 0, 1000); error = cv_timedwait(&sc->sc_cv, &sc->sc_mtx, (UFOMA_MAX_TIMEOUT * hz)); if (error) { DPRINTF("No response\n"); } } static void ufoma_ctrl_read_callback(struct usb_xfer *xfer, usb_error_t error) { struct ufoma_softc *sc = usbd_xfer_softc(xfer); struct usb_device_request req; struct usb_page_cache *pc0, *pc1; int len, aframes, nframes; usbd_xfer_status(xfer, NULL, NULL, &aframes, &nframes); switch (USB_GET_STATE(xfer)) { case USB_ST_TRANSFERRED: tr_transferred: if (aframes != nframes) goto tr_setup; pc1 = usbd_xfer_get_frame(xfer, 1); len = usbd_xfer_frame_len(xfer, 1); if (len > 0) ucom_put_data(&sc->sc_ucom, pc1, 0, len); /* FALLTHROUGH */ case USB_ST_SETUP: tr_setup: if (sc->sc_num_msg) { sc->sc_num_msg--; req.bmRequestType = UT_READ_CLASS_INTERFACE; req.bRequest = UCDC_GET_ENCAPSULATED_RESPONSE; USETW(req.wIndex, sc->sc_ctrl_iface_no); USETW(req.wValue, 0); USETW(req.wLength, UFOMA_CMD_BUF_SIZE); pc0 = usbd_xfer_get_frame(xfer, 0); usbd_copy_in(pc0, 0, &req, sizeof(req)); usbd_xfer_set_frame_len(xfer, 0, sizeof(req)); usbd_xfer_set_frame_len(xfer, 1, UFOMA_CMD_BUF_SIZE); usbd_xfer_set_frames(xfer, 2); usbd_transfer_submit(xfer); } return; default: /* Error */ DPRINTF("error = %s\n", usbd_errstr(error)); if (error == USB_ERR_CANCELLED) { return; } goto tr_transferred; } } static void ufoma_ctrl_write_callback(struct usb_xfer *xfer, usb_error_t error) { struct ufoma_softc *sc = usbd_xfer_softc(xfer); struct usb_device_request req; struct usb_page_cache *pc; uint32_t actlen; switch (USB_GET_STATE(xfer)) { case USB_ST_TRANSFERRED: tr_transferred: case USB_ST_SETUP: pc = usbd_xfer_get_frame(xfer, 1); if (ucom_get_data(&sc->sc_ucom, pc, 0, 1, &actlen)) { req.bmRequestType = UT_WRITE_CLASS_INTERFACE; req.bRequest = UCDC_SEND_ENCAPSULATED_COMMAND; USETW(req.wIndex, sc->sc_ctrl_iface_no); USETW(req.wValue, 0); USETW(req.wLength, 1); pc = usbd_xfer_get_frame(xfer, 0); usbd_copy_in(pc, 0, &req, sizeof(req)); usbd_xfer_set_frame_len(xfer, 0, sizeof(req)); usbd_xfer_set_frame_len(xfer, 1, 1); usbd_xfer_set_frames(xfer, 2); usbd_transfer_submit(xfer); } return; default: /* Error */ DPRINTF("error = %s\n", usbd_errstr(error)); if (error == USB_ERR_CANCELLED) { return; } goto tr_transferred; } } static void ufoma_intr_callback(struct usb_xfer *xfer, usb_error_t error) { struct ufoma_softc *sc = usbd_xfer_softc(xfer); struct usb_cdc_notification pkt; struct usb_page_cache *pc; uint16_t wLen; uint16_t temp; uint8_t mstatus; int actlen; usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); switch (USB_GET_STATE(xfer)) { case USB_ST_TRANSFERRED: if (actlen < 8) { DPRINTF("too short message\n"); goto tr_setup; } if (actlen > (int)sizeof(pkt)) { DPRINTF("truncating message\n"); actlen = sizeof(pkt); } pc = usbd_xfer_get_frame(xfer, 0); usbd_copy_out(pc, 0, &pkt, actlen); actlen -= 8; wLen = UGETW(pkt.wLength); if (actlen > wLen) { actlen = wLen; } if ((pkt.bmRequestType == UT_READ_VENDOR_INTERFACE) && (pkt.bNotification == UMCPC_REQUEST_ACKNOWLEDGE)) { temp = UGETW(pkt.wValue); sc->sc_currentmode = (temp >> 8); if (!(temp & 0xff)) { DPRINTF("Mode change failed!\n"); } cv_signal(&sc->sc_cv); } if (pkt.bmRequestType != UCDC_NOTIFICATION) { goto tr_setup; } switch (pkt.bNotification) { case UCDC_N_RESPONSE_AVAILABLE: if (!(sc->sc_nobulk)) { DPRINTF("Wrong serial state!\n"); break; } if (sc->sc_num_msg != 0xFF) { sc->sc_num_msg++; } usbd_transfer_start(sc->sc_ctrl_xfer[UFOMA_CTRL_ENDPT_READ]); break; case UCDC_N_SERIAL_STATE: if (sc->sc_nobulk) { DPRINTF("Wrong serial state!\n"); break; } /* * Set the serial state in ucom driver based on * the bits from the notify message */ if (actlen < 2) { DPRINTF("invalid notification " "length, %d bytes!\n", actlen); break; } DPRINTF("notify bytes = 0x%02x, 0x%02x\n", pkt.data[0], pkt.data[1]); /* currently, lsr is always zero. */ sc->sc_lsr = 0; sc->sc_msr = 0; mstatus = pkt.data[0]; if (mstatus & UCDC_N_SERIAL_RI) { sc->sc_msr |= SER_RI; } if (mstatus & UCDC_N_SERIAL_DSR) { sc->sc_msr |= SER_DSR; } if (mstatus & UCDC_N_SERIAL_DCD) { sc->sc_msr |= SER_DCD; } ucom_status_change(&sc->sc_ucom); break; default: break; } case USB_ST_SETUP: tr_setup: usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); usbd_transfer_submit(xfer); return; default: /* Error */ if (error != USB_ERR_CANCELLED) { /* try to clear stall first */ usbd_xfer_set_stall(xfer); goto tr_setup; } return; } } static void ufoma_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error) { struct ufoma_softc *sc = usbd_xfer_softc(xfer); struct usb_page_cache *pc; uint32_t actlen; switch (USB_GET_STATE(xfer)) { case USB_ST_SETUP: case USB_ST_TRANSFERRED: tr_setup: pc = usbd_xfer_get_frame(xfer, 0); if (ucom_get_data(&sc->sc_ucom, pc, 0, UFOMA_BULK_BUF_SIZE, &actlen)) { usbd_xfer_set_frame_len(xfer, 0, actlen); usbd_transfer_submit(xfer); } return; default: /* Error */ if (error != USB_ERR_CANCELLED) { /* try to clear stall first */ usbd_xfer_set_stall(xfer); goto tr_setup; } return; } } static void ufoma_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) { struct ufoma_softc *sc = usbd_xfer_softc(xfer); struct usb_page_cache *pc; int actlen; usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); switch (USB_GET_STATE(xfer)) { case USB_ST_TRANSFERRED: pc = usbd_xfer_get_frame(xfer, 0); ucom_put_data(&sc->sc_ucom, pc, 0, actlen); case USB_ST_SETUP: tr_setup: usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); usbd_transfer_submit(xfer); return; default: /* Error */ if (error != USB_ERR_CANCELLED) { /* try to clear stall first */ usbd_xfer_set_stall(xfer); goto tr_setup; } return; } } static void ufoma_cfg_open(struct ucom_softc *ucom) { struct ufoma_softc *sc = ucom->sc_parent; /* empty input queue */ if (sc->sc_num_msg != 0xFF) { sc->sc_num_msg++; } if (sc->sc_currentmode == UMCPC_ACM_MODE_UNLINKED) { ufoma_cfg_link_state(sc); } if (sc->sc_currentmode == UMCPC_ACM_MODE_DEACTIVATED) { ufoma_cfg_activate_state(sc, sc->sc_modetoactivate); } } static void ufoma_cfg_close(struct ucom_softc *ucom) { struct ufoma_softc *sc = ucom->sc_parent; ufoma_cfg_activate_state(sc, UMCPC_ACM_MODE_DEACTIVATED); } static void ufoma_cfg_set_break(struct ucom_softc *ucom, uint8_t onoff) { struct ufoma_softc *sc = ucom->sc_parent; struct usb_device_request req; uint16_t wValue; if (sc->sc_nobulk || (sc->sc_currentmode == UMCPC_ACM_MODE_OBEX)) { return; } if (!(sc->sc_acm_cap & USB_CDC_ACM_HAS_BREAK)) { return; } wValue = onoff ? UCDC_BREAK_ON : UCDC_BREAK_OFF; req.bmRequestType = UT_WRITE_CLASS_INTERFACE; req.bRequest = UCDC_SEND_BREAK; USETW(req.wValue, wValue); req.wIndex[0] = sc->sc_ctrl_iface_no; req.wIndex[1] = 0; USETW(req.wLength, 0); ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, &req, NULL, 0, 1000); } static void ufoma_cfg_get_status(struct ucom_softc *ucom, uint8_t *lsr, uint8_t *msr) { struct ufoma_softc *sc = ucom->sc_parent; /* XXX Note: sc_lsr is always zero */ *lsr = sc->sc_lsr; *msr = sc->sc_msr; } static void ufoma_cfg_set_line_state(struct ufoma_softc *sc) { struct usb_device_request req; /* Don't send line state emulation request for OBEX port */ if (sc->sc_currentmode == UMCPC_ACM_MODE_OBEX) { return; } req.bmRequestType = UT_WRITE_CLASS_INTERFACE; req.bRequest = UCDC_SET_CONTROL_LINE_STATE; USETW(req.wValue, sc->sc_line); req.wIndex[0] = sc->sc_ctrl_iface_no; req.wIndex[1] = 0; USETW(req.wLength, 0); ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, &req, NULL, 0, 1000); } static void ufoma_cfg_set_dtr(struct ucom_softc *ucom, uint8_t onoff) { struct ufoma_softc *sc = ucom->sc_parent; if (sc->sc_nobulk) { return; } if (onoff) sc->sc_line |= UCDC_LINE_DTR; else sc->sc_line &= ~UCDC_LINE_DTR; ufoma_cfg_set_line_state(sc); } static void ufoma_cfg_set_rts(struct ucom_softc *ucom, uint8_t onoff) { struct ufoma_softc *sc = ucom->sc_parent; if (sc->sc_nobulk) { return; } if (onoff) sc->sc_line |= UCDC_LINE_RTS; else sc->sc_line &= ~UCDC_LINE_RTS; ufoma_cfg_set_line_state(sc); } static int ufoma_pre_param(struct ucom_softc *ucom, struct termios *t) { return (0); /* we accept anything */ } static void ufoma_cfg_param(struct ucom_softc *ucom, struct termios *t) { struct ufoma_softc *sc = ucom->sc_parent; struct usb_device_request req; struct usb_cdc_line_state ls; if (sc->sc_nobulk || (sc->sc_currentmode == UMCPC_ACM_MODE_OBEX)) { return; } DPRINTF("\n"); memset(&ls, 0, sizeof(ls)); USETDW(ls.dwDTERate, t->c_ospeed); if (t->c_cflag & CSTOPB) { ls.bCharFormat = UCDC_STOP_BIT_2; } else { ls.bCharFormat = UCDC_STOP_BIT_1; } if (t->c_cflag & PARENB) { if (t->c_cflag & PARODD) { ls.bParityType = UCDC_PARITY_ODD; } else { ls.bParityType = UCDC_PARITY_EVEN; } } else { ls.bParityType = UCDC_PARITY_NONE; } switch (t->c_cflag & CSIZE) { case CS5: ls.bDataBits = 5; break; case CS6: ls.bDataBits = 6; break; case CS7: ls.bDataBits = 7; break; case CS8: ls.bDataBits = 8; break; } req.bmRequestType = UT_WRITE_CLASS_INTERFACE; req.bRequest = UCDC_SET_LINE_CODING; USETW(req.wValue, 0); req.wIndex[0] = sc->sc_ctrl_iface_no; req.wIndex[1] = 0; USETW(req.wLength, UCDC_LINE_STATE_LENGTH); ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, &req, &ls, 0, 1000); } static int ufoma_modem_setup(device_t dev, struct ufoma_softc *sc, struct usb_attach_arg *uaa) { struct usb_config_descriptor *cd; struct usb_cdc_acm_descriptor *acm; struct usb_cdc_cm_descriptor *cmd; struct usb_interface_descriptor *id; struct usb_interface *iface; uint8_t i; int32_t error; cd = usbd_get_config_descriptor(uaa->device); id = usbd_get_interface_descriptor(uaa->iface); cmd = ufoma_get_intconf(cd, id, UDESC_CS_INTERFACE, UDESCSUB_CDC_CM); if ((cmd == NULL) || (cmd->bLength < sizeof(*cmd))) { return (EINVAL); } sc->sc_cm_cap = cmd->bmCapabilities; sc->sc_data_iface_no = cmd->bDataInterface; acm = ufoma_get_intconf(cd, id, UDESC_CS_INTERFACE, UDESCSUB_CDC_ACM); if ((acm == NULL) || (acm->bLength < sizeof(*acm))) { return (EINVAL); } sc->sc_acm_cap = acm->bmCapabilities; device_printf(dev, "data interface %d, has %sCM over data, " "has %sbreak\n", sc->sc_data_iface_no, sc->sc_cm_cap & USB_CDC_CM_OVER_DATA ? "" : "no ", sc->sc_acm_cap & USB_CDC_ACM_HAS_BREAK ? "" : "no "); /* get the data interface too */ for (i = 0;; i++) { iface = usbd_get_iface(uaa->device, i); if (iface) { id = usbd_get_interface_descriptor(iface); if (id && (id->bInterfaceNumber == sc->sc_data_iface_no)) { sc->sc_data_iface_index = i; usbd_set_parent_iface(uaa->device, i, uaa->info.bIfaceIndex); break; } } else { device_printf(dev, "no data interface\n"); return (EINVAL); } } error = usbd_transfer_setup(uaa->device, &sc->sc_data_iface_index, sc->sc_bulk_xfer, ufoma_bulk_config, UFOMA_BULK_ENDPT_MAX, sc, &sc->sc_mtx); if (error) { device_printf(dev, "allocating BULK USB " "transfers failed\n"); return (EINVAL); } return (0); } static void ufoma_start_read(struct ucom_softc *ucom) { struct ufoma_softc *sc = ucom->sc_parent; /* start interrupt transfer */ usbd_transfer_start(sc->sc_ctrl_xfer[UFOMA_CTRL_ENDPT_INTR]); /* start data transfer */ if (sc->sc_nobulk) { usbd_transfer_start(sc->sc_ctrl_xfer[UFOMA_CTRL_ENDPT_READ]); } else { usbd_transfer_start(sc->sc_bulk_xfer[UFOMA_BULK_ENDPT_READ]); } } static void ufoma_stop_read(struct ucom_softc *ucom) { struct ufoma_softc *sc = ucom->sc_parent; /* stop interrupt transfer */ usbd_transfer_stop(sc->sc_ctrl_xfer[UFOMA_CTRL_ENDPT_INTR]); /* stop data transfer */ if (sc->sc_nobulk) { usbd_transfer_stop(sc->sc_ctrl_xfer[UFOMA_CTRL_ENDPT_READ]); } else { usbd_transfer_stop(sc->sc_bulk_xfer[UFOMA_BULK_ENDPT_READ]); } } static void ufoma_start_write(struct ucom_softc *ucom) { struct ufoma_softc *sc = ucom->sc_parent; if (sc->sc_nobulk) { usbd_transfer_start(sc->sc_ctrl_xfer[UFOMA_CTRL_ENDPT_WRITE]); } else { usbd_transfer_start(sc->sc_bulk_xfer[UFOMA_BULK_ENDPT_WRITE]); } } static void ufoma_stop_write(struct ucom_softc *ucom) { struct ufoma_softc *sc = ucom->sc_parent; if (sc->sc_nobulk) { usbd_transfer_stop(sc->sc_ctrl_xfer[UFOMA_CTRL_ENDPT_WRITE]); } else { usbd_transfer_stop(sc->sc_bulk_xfer[UFOMA_BULK_ENDPT_WRITE]); } } static struct umcpc_modetostr_tab{ int mode; char *str; }umcpc_modetostr_tab[]={ {UMCPC_ACM_MODE_DEACTIVATED, "deactivated"}, {UMCPC_ACM_MODE_MODEM, "modem"}, {UMCPC_ACM_MODE_ATCOMMAND, "handsfree"}, {UMCPC_ACM_MODE_OBEX, "obex"}, {UMCPC_ACM_MODE_VENDOR1, "vendor1"}, {UMCPC_ACM_MODE_VENDOR2, "vendor2"}, {UMCPC_ACM_MODE_UNLINKED, "unlinked"}, {0, NULL} }; static char *ufoma_mode_to_str(int mode) { int i; for(i = 0 ;umcpc_modetostr_tab[i].str != NULL; i++){ if(umcpc_modetostr_tab[i].mode == mode){ return umcpc_modetostr_tab[i].str; } } return NULL; } static int ufoma_str_to_mode(char *str) { int i; for(i = 0 ;umcpc_modetostr_tab[i].str != NULL; i++){ if(strcmp(str, umcpc_modetostr_tab[i].str)==0){ return umcpc_modetostr_tab[i].mode; } } return -1; } static int ufoma_sysctl_support(SYSCTL_HANDLER_ARGS) { struct ufoma_softc *sc = (struct ufoma_softc *)oidp->oid_arg1; struct sbuf sb; int i; char *mode; sbuf_new(&sb, NULL, 1, SBUF_AUTOEXTEND); for(i = 1; i < sc->sc_modetable[0]; i++){ mode = ufoma_mode_to_str(sc->sc_modetable[i]); if(mode !=NULL){ sbuf_cat(&sb, mode); }else{ sbuf_printf(&sb, "(%02x)", sc->sc_modetable[i]); } if(i < (sc->sc_modetable[0]-1)) sbuf_cat(&sb, ","); } sbuf_trim(&sb); sbuf_finish(&sb); sysctl_handle_string(oidp, sbuf_data(&sb), sbuf_len(&sb), req); sbuf_delete(&sb); return 0; } static int ufoma_sysctl_current(SYSCTL_HANDLER_ARGS) { struct ufoma_softc *sc = (struct ufoma_softc *)oidp->oid_arg1; char *mode; char subbuf[]="(XXX)"; mode = ufoma_mode_to_str(sc->sc_currentmode); if(!mode){ mode = subbuf; snprintf(subbuf, sizeof(subbuf), "(%02x)", sc->sc_currentmode); } sysctl_handle_string(oidp, mode, strlen(mode), req); return 0; } static int ufoma_sysctl_open(SYSCTL_HANDLER_ARGS) { struct ufoma_softc *sc = (struct ufoma_softc *)oidp->oid_arg1; char *mode; char subbuf[40]; int newmode; int error; int i; mode = ufoma_mode_to_str(sc->sc_modetoactivate); if(mode){ strncpy(subbuf, mode, sizeof(subbuf)); }else{ snprintf(subbuf, sizeof(subbuf), "(%02x)", sc->sc_modetoactivate); } error = sysctl_handle_string(oidp, subbuf, sizeof(subbuf), req); if(error != 0 || req->newptr == NULL){ return error; } if((newmode = ufoma_str_to_mode(subbuf)) == -1){ return EINVAL; } for(i = 1 ; i < sc->sc_modetable[0] ; i++){ if(sc->sc_modetable[i] == newmode){ sc->sc_modetoactivate = newmode; return 0; } } return EINVAL; } static void ufoma_poll(struct ucom_softc *ucom) { struct ufoma_softc *sc = ucom->sc_parent; usbd_transfer_poll(sc->sc_ctrl_xfer, UFOMA_CTRL_ENDPT_MAX); usbd_transfer_poll(sc->sc_bulk_xfer, UFOMA_BULK_ENDPT_MAX); } Index: head/sys/dev/usb/serial/umodem.c =================================================================== --- head/sys/dev/usb/serial/umodem.c (revision 355393) +++ head/sys/dev/usb/serial/umodem.c (revision 355394) @@ -1,1042 +1,1041 @@ /* $NetBSD: umodem.c,v 1.45 2002/09/23 05:51:23 simonb Exp $ */ #include __FBSDID("$FreeBSD$"); /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD AND BSD-2-Clause-NetBSD * - * Copyright (c) 2003, M. Warner Losh . - * All rights reserved. + * Copyright (c) 2003 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /*- * Copyright (c) 1998 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Lennart Augustsson (lennart@augustsson.net) at * Carlstedt Research & Technology. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * Comm Class spec: http://www.usb.org/developers/devclass_docs/usbccs10.pdf * http://www.usb.org/developers/devclass_docs/usbcdc11.pdf * http://www.usb.org/developers/devclass_docs/cdc_wmc10.zip */ /* * TODO: * - Add error recovery in various places; the big problem is what * to do in a callback if there is an error. * - Implement a Call Device for modems without multiplexed commands. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "usbdevs.h" #include "usb_if.h" #include #define USB_DEBUG_VAR umodem_debug #include #include #include #include #ifdef USB_DEBUG static int umodem_debug = 0; static SYSCTL_NODE(_hw_usb, OID_AUTO, umodem, CTLFLAG_RW, 0, "USB umodem"); SYSCTL_INT(_hw_usb_umodem, OID_AUTO, debug, CTLFLAG_RWTUN, &umodem_debug, 0, "Debug level"); #endif static const STRUCT_USB_DUAL_ID umodem_dual_devs[] = { /* Generic Modem class match */ {USB_IFACE_CLASS(UICLASS_CDC), USB_IFACE_SUBCLASS(UISUBCLASS_ABSTRACT_CONTROL_MODEL), USB_IFACE_PROTOCOL(UIPROTO_CDC_AT)}, {USB_IFACE_CLASS(UICLASS_CDC), USB_IFACE_SUBCLASS(UISUBCLASS_ABSTRACT_CONTROL_MODEL), USB_IFACE_PROTOCOL(UIPROTO_CDC_NONE)}, }; static const STRUCT_USB_HOST_ID umodem_host_devs[] = { /* Huawei Modem class match */ {USB_VENDOR(USB_VENDOR_HUAWEI), USB_IFACE_CLASS(UICLASS_VENDOR), USB_IFACE_SUBCLASS(0x02), USB_IFACE_PROTOCOL(0x01)}, {USB_VENDOR(USB_VENDOR_HUAWEI), USB_IFACE_CLASS(UICLASS_VENDOR), USB_IFACE_SUBCLASS(0x02), USB_IFACE_PROTOCOL(0x02)}, {USB_VENDOR(USB_VENDOR_HUAWEI), USB_IFACE_CLASS(UICLASS_VENDOR), USB_IFACE_SUBCLASS(0x02), USB_IFACE_PROTOCOL(0x10)}, {USB_VENDOR(USB_VENDOR_HUAWEI), USB_IFACE_CLASS(UICLASS_VENDOR), USB_IFACE_SUBCLASS(0x02), USB_IFACE_PROTOCOL(0x12)}, {USB_VENDOR(USB_VENDOR_HUAWEI), USB_IFACE_CLASS(UICLASS_VENDOR), USB_IFACE_SUBCLASS(0x02), USB_IFACE_PROTOCOL(0x61)}, {USB_VENDOR(USB_VENDOR_HUAWEI), USB_IFACE_CLASS(UICLASS_VENDOR), USB_IFACE_SUBCLASS(0x02), USB_IFACE_PROTOCOL(0x62)}, {USB_VENDOR(USB_VENDOR_HUAWEI),USB_IFACE_CLASS(UICLASS_CDC), USB_IFACE_SUBCLASS(UISUBCLASS_ABSTRACT_CONTROL_MODEL), USB_IFACE_PROTOCOL(0xFF)}, /* Kyocera AH-K3001V */ {USB_VPI(USB_VENDOR_KYOCERA, USB_PRODUCT_KYOCERA_AHK3001V, 1)}, {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC5720, 1)}, {USB_VPI(USB_VENDOR_CURITEL, USB_PRODUCT_CURITEL_PC5740, 1)}, }; /* * As speeds for umodem devices increase, these numbers will need to * be increased. They should be good for G3 speeds and below. * * TODO: The TTY buffers should be increased! */ #define UMODEM_BUF_SIZE 1024 enum { UMODEM_BULK_WR, UMODEM_BULK_RD, UMODEM_INTR_WR, UMODEM_INTR_RD, UMODEM_N_TRANSFER, }; #define UMODEM_MODVER 1 /* module version */ struct umodem_softc { struct ucom_super_softc sc_super_ucom; struct ucom_softc sc_ucom; struct usb_xfer *sc_xfer[UMODEM_N_TRANSFER]; struct usb_device *sc_udev; struct mtx sc_mtx; uint16_t sc_line; uint8_t sc_lsr; /* local status register */ uint8_t sc_msr; /* modem status register */ uint8_t sc_ctrl_iface_no; uint8_t sc_data_iface_no; uint8_t sc_iface_index[2]; uint8_t sc_cm_over_data; uint8_t sc_cm_cap; /* CM capabilities */ uint8_t sc_acm_cap; /* ACM capabilities */ uint8_t sc_line_coding[32]; /* used in USB device mode */ uint8_t sc_abstract_state[32]; /* used in USB device mode */ }; static device_probe_t umodem_probe; static device_attach_t umodem_attach; static device_detach_t umodem_detach; static usb_handle_request_t umodem_handle_request; static void umodem_free_softc(struct umodem_softc *); static usb_callback_t umodem_intr_read_callback; static usb_callback_t umodem_intr_write_callback; static usb_callback_t umodem_write_callback; static usb_callback_t umodem_read_callback; static void umodem_free(struct ucom_softc *); static void umodem_start_read(struct ucom_softc *); static void umodem_stop_read(struct ucom_softc *); static void umodem_start_write(struct ucom_softc *); static void umodem_stop_write(struct ucom_softc *); static void umodem_get_caps(struct usb_attach_arg *, uint8_t *, uint8_t *); static void umodem_cfg_get_status(struct ucom_softc *, uint8_t *, uint8_t *); static int umodem_pre_param(struct ucom_softc *, struct termios *); static void umodem_cfg_param(struct ucom_softc *, struct termios *); static int umodem_ioctl(struct ucom_softc *, uint32_t, caddr_t, int, struct thread *); static void umodem_cfg_set_dtr(struct ucom_softc *, uint8_t); static void umodem_cfg_set_rts(struct ucom_softc *, uint8_t); static void umodem_cfg_set_break(struct ucom_softc *, uint8_t); static void *umodem_get_desc(struct usb_attach_arg *, uint8_t, uint8_t); static usb_error_t umodem_set_comm_feature(struct usb_device *, uint8_t, uint16_t, uint16_t); static void umodem_poll(struct ucom_softc *ucom); static void umodem_find_data_iface(struct usb_attach_arg *uaa, uint8_t, uint8_t *, uint8_t *); static const struct usb_config umodem_config[UMODEM_N_TRANSFER] = { [UMODEM_BULK_WR] = { .type = UE_BULK, .endpoint = UE_ADDR_ANY, .direction = UE_DIR_TX, .if_index = 0, .bufsize = UMODEM_BUF_SIZE, .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, .callback = &umodem_write_callback, .usb_mode = USB_MODE_DUAL, }, [UMODEM_BULK_RD] = { .type = UE_BULK, .endpoint = UE_ADDR_ANY, .direction = UE_DIR_RX, .if_index = 0, .bufsize = UMODEM_BUF_SIZE, .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, .callback = &umodem_read_callback, .usb_mode = USB_MODE_DUAL, }, [UMODEM_INTR_WR] = { .type = UE_INTERRUPT, .endpoint = UE_ADDR_ANY, .direction = UE_DIR_TX, .if_index = 1, .flags = {.pipe_bof = 1,.short_xfer_ok = 1,.no_pipe_ok = 1,}, .bufsize = 0, /* use wMaxPacketSize */ .callback = &umodem_intr_write_callback, .usb_mode = USB_MODE_DEVICE, }, [UMODEM_INTR_RD] = { .type = UE_INTERRUPT, .endpoint = UE_ADDR_ANY, .direction = UE_DIR_RX, .if_index = 1, .flags = {.pipe_bof = 1,.short_xfer_ok = 1,.no_pipe_ok = 1,}, .bufsize = 0, /* use wMaxPacketSize */ .callback = &umodem_intr_read_callback, .usb_mode = USB_MODE_HOST, }, }; static const struct ucom_callback umodem_callback = { .ucom_cfg_get_status = &umodem_cfg_get_status, .ucom_cfg_set_dtr = &umodem_cfg_set_dtr, .ucom_cfg_set_rts = &umodem_cfg_set_rts, .ucom_cfg_set_break = &umodem_cfg_set_break, .ucom_cfg_param = &umodem_cfg_param, .ucom_pre_param = &umodem_pre_param, .ucom_ioctl = &umodem_ioctl, .ucom_start_read = &umodem_start_read, .ucom_stop_read = &umodem_stop_read, .ucom_start_write = &umodem_start_write, .ucom_stop_write = &umodem_stop_write, .ucom_poll = &umodem_poll, .ucom_free = &umodem_free, }; static device_method_t umodem_methods[] = { /* USB interface */ DEVMETHOD(usb_handle_request, umodem_handle_request), /* Device interface */ DEVMETHOD(device_probe, umodem_probe), DEVMETHOD(device_attach, umodem_attach), DEVMETHOD(device_detach, umodem_detach), DEVMETHOD_END }; static devclass_t umodem_devclass; static driver_t umodem_driver = { .name = "umodem", .methods = umodem_methods, .size = sizeof(struct umodem_softc), }; DRIVER_MODULE(umodem, uhub, umodem_driver, umodem_devclass, NULL, 0); MODULE_DEPEND(umodem, ucom, 1, 1, 1); MODULE_DEPEND(umodem, usb, 1, 1, 1); MODULE_VERSION(umodem, UMODEM_MODVER); USB_PNP_DUAL_INFO(umodem_dual_devs); USB_PNP_HOST_INFO(umodem_host_devs); static int umodem_probe(device_t dev) { struct usb_attach_arg *uaa = device_get_ivars(dev); int error; DPRINTFN(11, "\n"); error = usbd_lookup_id_by_uaa(umodem_host_devs, sizeof(umodem_host_devs), uaa); if (error) { error = usbd_lookup_id_by_uaa(umodem_dual_devs, sizeof(umodem_dual_devs), uaa); if (error) return (error); } return (BUS_PROBE_GENERIC); } static int umodem_attach(device_t dev) { struct usb_attach_arg *uaa = device_get_ivars(dev); struct umodem_softc *sc = device_get_softc(dev); struct usb_cdc_cm_descriptor *cmd; struct usb_cdc_union_descriptor *cud; uint8_t i; int error; device_set_usb_desc(dev); mtx_init(&sc->sc_mtx, "umodem", NULL, MTX_DEF); ucom_ref(&sc->sc_super_ucom); sc->sc_ctrl_iface_no = uaa->info.bIfaceNum; sc->sc_iface_index[1] = uaa->info.bIfaceIndex; sc->sc_udev = uaa->device; umodem_get_caps(uaa, &sc->sc_cm_cap, &sc->sc_acm_cap); /* get the data interface number */ cmd = umodem_get_desc(uaa, UDESC_CS_INTERFACE, UDESCSUB_CDC_CM); if ((cmd == NULL) || (cmd->bLength < sizeof(*cmd))) { cud = usbd_find_descriptor(uaa->device, NULL, uaa->info.bIfaceIndex, UDESC_CS_INTERFACE, 0xFF, UDESCSUB_CDC_UNION, 0xFF); if ((cud == NULL) || (cud->bLength < sizeof(*cud))) { DPRINTF("Missing descriptor. " "Assuming data interface is next.\n"); if (sc->sc_ctrl_iface_no == 0xFF) { goto detach; } else { uint8_t class_match = 0; /* set default interface number */ sc->sc_data_iface_no = 0xFF; /* try to find the data interface backwards */ umodem_find_data_iface(uaa, uaa->info.bIfaceIndex - 1, &sc->sc_data_iface_no, &class_match); /* try to find the data interface forwards */ umodem_find_data_iface(uaa, uaa->info.bIfaceIndex + 1, &sc->sc_data_iface_no, &class_match); /* check if nothing was found */ if (sc->sc_data_iface_no == 0xFF) goto detach; } } else { sc->sc_data_iface_no = cud->bSlaveInterface[0]; } } else { sc->sc_data_iface_no = cmd->bDataInterface; } device_printf(dev, "data interface %d, has %sCM over " "data, has %sbreak\n", sc->sc_data_iface_no, sc->sc_cm_cap & USB_CDC_CM_OVER_DATA ? "" : "no ", sc->sc_acm_cap & USB_CDC_ACM_HAS_BREAK ? "" : "no "); /* get the data interface too */ for (i = 0;; i++) { struct usb_interface *iface; struct usb_interface_descriptor *id; iface = usbd_get_iface(uaa->device, i); if (iface) { id = usbd_get_interface_descriptor(iface); if (id && (id->bInterfaceNumber == sc->sc_data_iface_no)) { sc->sc_iface_index[0] = i; usbd_set_parent_iface(uaa->device, i, uaa->info.bIfaceIndex); break; } } else { device_printf(dev, "no data interface\n"); goto detach; } } if (usb_test_quirk(uaa, UQ_ASSUME_CM_OVER_DATA)) { sc->sc_cm_over_data = 1; } else { if (sc->sc_cm_cap & USB_CDC_CM_OVER_DATA) { if (sc->sc_acm_cap & USB_CDC_ACM_HAS_FEATURE) { error = umodem_set_comm_feature (uaa->device, sc->sc_ctrl_iface_no, UCDC_ABSTRACT_STATE, UCDC_DATA_MULTIPLEXED); /* ignore any errors */ } sc->sc_cm_over_data = 1; } } error = usbd_transfer_setup(uaa->device, sc->sc_iface_index, sc->sc_xfer, umodem_config, UMODEM_N_TRANSFER, sc, &sc->sc_mtx); if (error) { device_printf(dev, "Can't setup transfer\n"); goto detach; } /* clear stall at first run, if USB host mode */ if (uaa->usb_mode == USB_MODE_HOST) { mtx_lock(&sc->sc_mtx); usbd_xfer_set_stall(sc->sc_xfer[UMODEM_BULK_WR]); usbd_xfer_set_stall(sc->sc_xfer[UMODEM_BULK_RD]); mtx_unlock(&sc->sc_mtx); } ucom_set_usb_mode(&sc->sc_super_ucom, uaa->usb_mode); error = ucom_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc, &umodem_callback, &sc->sc_mtx); if (error) { device_printf(dev, "Can't attach com\n"); goto detach; } ucom_set_pnpinfo_usb(&sc->sc_super_ucom, dev); return (0); detach: umodem_detach(dev); return (ENXIO); } static void umodem_find_data_iface(struct usb_attach_arg *uaa, uint8_t iface_index, uint8_t *p_data_no, uint8_t *p_match_class) { struct usb_interface_descriptor *id; struct usb_interface *iface; iface = usbd_get_iface(uaa->device, iface_index); /* check for end of interfaces */ if (iface == NULL) return; id = usbd_get_interface_descriptor(iface); /* check for non-matching interface class */ if (id->bInterfaceClass != UICLASS_CDC_DATA || id->bInterfaceSubClass != UISUBCLASS_DATA) { /* if we got a class match then return */ if (*p_match_class) return; } else { *p_match_class = 1; } DPRINTFN(11, "Match at index %u\n", iface_index); *p_data_no = id->bInterfaceNumber; } static void umodem_start_read(struct ucom_softc *ucom) { struct umodem_softc *sc = ucom->sc_parent; /* start interrupt endpoint, if any */ usbd_transfer_start(sc->sc_xfer[UMODEM_INTR_RD]); /* start read endpoint */ usbd_transfer_start(sc->sc_xfer[UMODEM_BULK_RD]); } static void umodem_stop_read(struct ucom_softc *ucom) { struct umodem_softc *sc = ucom->sc_parent; /* stop interrupt endpoint, if any */ usbd_transfer_stop(sc->sc_xfer[UMODEM_INTR_RD]); /* stop read endpoint */ usbd_transfer_stop(sc->sc_xfer[UMODEM_BULK_RD]); } static void umodem_start_write(struct ucom_softc *ucom) { struct umodem_softc *sc = ucom->sc_parent; usbd_transfer_start(sc->sc_xfer[UMODEM_INTR_WR]); usbd_transfer_start(sc->sc_xfer[UMODEM_BULK_WR]); } static void umodem_stop_write(struct ucom_softc *ucom) { struct umodem_softc *sc = ucom->sc_parent; usbd_transfer_stop(sc->sc_xfer[UMODEM_INTR_WR]); usbd_transfer_stop(sc->sc_xfer[UMODEM_BULK_WR]); } static void umodem_get_caps(struct usb_attach_arg *uaa, uint8_t *cm, uint8_t *acm) { struct usb_cdc_cm_descriptor *cmd; struct usb_cdc_acm_descriptor *cad; cmd = umodem_get_desc(uaa, UDESC_CS_INTERFACE, UDESCSUB_CDC_CM); if ((cmd == NULL) || (cmd->bLength < sizeof(*cmd))) { DPRINTF("no CM desc (faking one)\n"); *cm = USB_CDC_CM_DOES_CM | USB_CDC_CM_OVER_DATA; } else *cm = cmd->bmCapabilities; cad = umodem_get_desc(uaa, UDESC_CS_INTERFACE, UDESCSUB_CDC_ACM); if ((cad == NULL) || (cad->bLength < sizeof(*cad))) { DPRINTF("no ACM desc\n"); *acm = 0; } else *acm = cad->bmCapabilities; } static void umodem_cfg_get_status(struct ucom_softc *ucom, uint8_t *lsr, uint8_t *msr) { struct umodem_softc *sc = ucom->sc_parent; DPRINTF("\n"); /* XXX Note: sc_lsr is always zero */ *lsr = sc->sc_lsr; *msr = sc->sc_msr; } static int umodem_pre_param(struct ucom_softc *ucom, struct termios *t) { return (0); /* we accept anything */ } static void umodem_cfg_param(struct ucom_softc *ucom, struct termios *t) { struct umodem_softc *sc = ucom->sc_parent; struct usb_cdc_line_state ls; struct usb_device_request req; DPRINTF("sc=%p\n", sc); memset(&ls, 0, sizeof(ls)); USETDW(ls.dwDTERate, t->c_ospeed); ls.bCharFormat = (t->c_cflag & CSTOPB) ? UCDC_STOP_BIT_2 : UCDC_STOP_BIT_1; ls.bParityType = (t->c_cflag & PARENB) ? ((t->c_cflag & PARODD) ? UCDC_PARITY_ODD : UCDC_PARITY_EVEN) : UCDC_PARITY_NONE; switch (t->c_cflag & CSIZE) { case CS5: ls.bDataBits = 5; break; case CS6: ls.bDataBits = 6; break; case CS7: ls.bDataBits = 7; break; case CS8: ls.bDataBits = 8; break; } DPRINTF("rate=%d fmt=%d parity=%d bits=%d\n", UGETDW(ls.dwDTERate), ls.bCharFormat, ls.bParityType, ls.bDataBits); req.bmRequestType = UT_WRITE_CLASS_INTERFACE; req.bRequest = UCDC_SET_LINE_CODING; USETW(req.wValue, 0); req.wIndex[0] = sc->sc_ctrl_iface_no; req.wIndex[1] = 0; USETW(req.wLength, sizeof(ls)); ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, &req, &ls, 0, 1000); } static int umodem_ioctl(struct ucom_softc *ucom, uint32_t cmd, caddr_t data, int flag, struct thread *td) { struct umodem_softc *sc = ucom->sc_parent; int error = 0; DPRINTF("cmd=0x%08x\n", cmd); switch (cmd) { case USB_GET_CM_OVER_DATA: *(int *)data = sc->sc_cm_over_data; break; case USB_SET_CM_OVER_DATA: if (*(int *)data != sc->sc_cm_over_data) { /* XXX change it */ } break; default: DPRINTF("unknown\n"); error = ENOIOCTL; break; } return (error); } static void umodem_cfg_set_dtr(struct ucom_softc *ucom, uint8_t onoff) { struct umodem_softc *sc = ucom->sc_parent; struct usb_device_request req; DPRINTF("onoff=%d\n", onoff); if (onoff) sc->sc_line |= UCDC_LINE_DTR; else sc->sc_line &= ~UCDC_LINE_DTR; req.bmRequestType = UT_WRITE_CLASS_INTERFACE; req.bRequest = UCDC_SET_CONTROL_LINE_STATE; USETW(req.wValue, sc->sc_line); req.wIndex[0] = sc->sc_ctrl_iface_no; req.wIndex[1] = 0; USETW(req.wLength, 0); ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, &req, NULL, 0, 1000); } static void umodem_cfg_set_rts(struct ucom_softc *ucom, uint8_t onoff) { struct umodem_softc *sc = ucom->sc_parent; struct usb_device_request req; DPRINTF("onoff=%d\n", onoff); if (onoff) sc->sc_line |= UCDC_LINE_RTS; else sc->sc_line &= ~UCDC_LINE_RTS; req.bmRequestType = UT_WRITE_CLASS_INTERFACE; req.bRequest = UCDC_SET_CONTROL_LINE_STATE; USETW(req.wValue, sc->sc_line); req.wIndex[0] = sc->sc_ctrl_iface_no; req.wIndex[1] = 0; USETW(req.wLength, 0); ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, &req, NULL, 0, 1000); } static void umodem_cfg_set_break(struct ucom_softc *ucom, uint8_t onoff) { struct umodem_softc *sc = ucom->sc_parent; struct usb_device_request req; uint16_t temp; DPRINTF("onoff=%d\n", onoff); if (sc->sc_acm_cap & USB_CDC_ACM_HAS_BREAK) { temp = onoff ? UCDC_BREAK_ON : UCDC_BREAK_OFF; req.bmRequestType = UT_WRITE_CLASS_INTERFACE; req.bRequest = UCDC_SEND_BREAK; USETW(req.wValue, temp); req.wIndex[0] = sc->sc_ctrl_iface_no; req.wIndex[1] = 0; USETW(req.wLength, 0); ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, &req, NULL, 0, 1000); } } static void umodem_intr_write_callback(struct usb_xfer *xfer, usb_error_t error) { int actlen; usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); switch (USB_GET_STATE(xfer)) { case USB_ST_TRANSFERRED: DPRINTF("Transferred %d bytes\n", actlen); /* FALLTHROUGH */ case USB_ST_SETUP: tr_setup: break; default: /* Error */ if (error != USB_ERR_CANCELLED) { /* start clear stall */ usbd_xfer_set_stall(xfer); goto tr_setup; } break; } } static void umodem_intr_read_callback(struct usb_xfer *xfer, usb_error_t error) { struct usb_cdc_notification pkt; struct umodem_softc *sc = usbd_xfer_softc(xfer); struct usb_page_cache *pc; uint16_t wLen; int actlen; usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); switch (USB_GET_STATE(xfer)) { case USB_ST_TRANSFERRED: if (actlen < 8) { DPRINTF("received short packet, " "%d bytes\n", actlen); goto tr_setup; } if (actlen > (int)sizeof(pkt)) { DPRINTF("truncating message\n"); actlen = sizeof(pkt); } pc = usbd_xfer_get_frame(xfer, 0); usbd_copy_out(pc, 0, &pkt, actlen); actlen -= 8; wLen = UGETW(pkt.wLength); if (actlen > wLen) { actlen = wLen; } if (pkt.bmRequestType != UCDC_NOTIFICATION) { DPRINTF("unknown message type, " "0x%02x, on notify pipe!\n", pkt.bmRequestType); goto tr_setup; } switch (pkt.bNotification) { case UCDC_N_SERIAL_STATE: /* * Set the serial state in ucom driver based on * the bits from the notify message */ if (actlen < 2) { DPRINTF("invalid notification " "length, %d bytes!\n", actlen); break; } DPRINTF("notify bytes = %02x%02x\n", pkt.data[0], pkt.data[1]); /* Currently, lsr is always zero. */ sc->sc_lsr = 0; sc->sc_msr = 0; if (pkt.data[0] & UCDC_N_SERIAL_RI) { sc->sc_msr |= SER_RI; } if (pkt.data[0] & UCDC_N_SERIAL_DSR) { sc->sc_msr |= SER_DSR; } if (pkt.data[0] & UCDC_N_SERIAL_DCD) { sc->sc_msr |= SER_DCD; } ucom_status_change(&sc->sc_ucom); break; default: DPRINTF("unknown notify message: 0x%02x\n", pkt.bNotification); break; } case USB_ST_SETUP: tr_setup: usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); usbd_transfer_submit(xfer); return; default: /* Error */ if (error != USB_ERR_CANCELLED) { /* try to clear stall first */ usbd_xfer_set_stall(xfer); goto tr_setup; } return; } } static void umodem_write_callback(struct usb_xfer *xfer, usb_error_t error) { struct umodem_softc *sc = usbd_xfer_softc(xfer); struct usb_page_cache *pc; uint32_t actlen; switch (USB_GET_STATE(xfer)) { case USB_ST_SETUP: case USB_ST_TRANSFERRED: tr_setup: pc = usbd_xfer_get_frame(xfer, 0); if (ucom_get_data(&sc->sc_ucom, pc, 0, UMODEM_BUF_SIZE, &actlen)) { usbd_xfer_set_frame_len(xfer, 0, actlen); usbd_transfer_submit(xfer); } return; default: /* Error */ if (error != USB_ERR_CANCELLED) { /* try to clear stall first */ usbd_xfer_set_stall(xfer); goto tr_setup; } return; } } static void umodem_read_callback(struct usb_xfer *xfer, usb_error_t error) { struct umodem_softc *sc = usbd_xfer_softc(xfer); struct usb_page_cache *pc; int actlen; usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); switch (USB_GET_STATE(xfer)) { case USB_ST_TRANSFERRED: DPRINTF("actlen=%d\n", actlen); pc = usbd_xfer_get_frame(xfer, 0); ucom_put_data(&sc->sc_ucom, pc, 0, actlen); case USB_ST_SETUP: tr_setup: usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); usbd_transfer_submit(xfer); return; default: /* Error */ if (error != USB_ERR_CANCELLED) { /* try to clear stall first */ usbd_xfer_set_stall(xfer); goto tr_setup; } return; } } static void * umodem_get_desc(struct usb_attach_arg *uaa, uint8_t type, uint8_t subtype) { return (usbd_find_descriptor(uaa->device, NULL, uaa->info.bIfaceIndex, type, 0xFF, subtype, 0xFF)); } static usb_error_t umodem_set_comm_feature(struct usb_device *udev, uint8_t iface_no, uint16_t feature, uint16_t state) { struct usb_device_request req; struct usb_cdc_abstract_state ast; DPRINTF("feature=%d state=%d\n", feature, state); req.bmRequestType = UT_WRITE_CLASS_INTERFACE; req.bRequest = UCDC_SET_COMM_FEATURE; USETW(req.wValue, feature); req.wIndex[0] = iface_no; req.wIndex[1] = 0; USETW(req.wLength, UCDC_ABSTRACT_STATE_LENGTH); USETW(ast.wState, state); return (usbd_do_request(udev, NULL, &req, &ast)); } static int umodem_detach(device_t dev) { struct umodem_softc *sc = device_get_softc(dev); DPRINTF("sc=%p\n", sc); ucom_detach(&sc->sc_super_ucom, &sc->sc_ucom); usbd_transfer_unsetup(sc->sc_xfer, UMODEM_N_TRANSFER); device_claim_softc(dev); umodem_free_softc(sc); return (0); } UCOM_UNLOAD_DRAIN(umodem); static void umodem_free_softc(struct umodem_softc *sc) { if (ucom_unref(&sc->sc_super_ucom)) { mtx_destroy(&sc->sc_mtx); device_free_softc(sc); } } static void umodem_free(struct ucom_softc *ucom) { umodem_free_softc(ucom->sc_parent); } static void umodem_poll(struct ucom_softc *ucom) { struct umodem_softc *sc = ucom->sc_parent; usbd_transfer_poll(sc->sc_xfer, UMODEM_N_TRANSFER); } static int umodem_handle_request(device_t dev, const void *preq, void **pptr, uint16_t *plen, uint16_t offset, uint8_t *pstate) { struct umodem_softc *sc = device_get_softc(dev); const struct usb_device_request *req = preq; uint8_t is_complete = *pstate; DPRINTF("sc=%p\n", sc); if (!is_complete) { if ((req->bmRequestType == UT_WRITE_CLASS_INTERFACE) && (req->bRequest == UCDC_SET_LINE_CODING) && (req->wIndex[0] == sc->sc_ctrl_iface_no) && (req->wIndex[1] == 0x00) && (req->wValue[0] == 0x00) && (req->wValue[1] == 0x00)) { if (offset == 0) { *plen = sizeof(sc->sc_line_coding); *pptr = &sc->sc_line_coding; } else { *plen = 0; } return (0); } else if ((req->bmRequestType == UT_WRITE_CLASS_INTERFACE) && (req->wIndex[0] == sc->sc_ctrl_iface_no) && (req->wIndex[1] == 0x00) && (req->bRequest == UCDC_SET_COMM_FEATURE)) { if (offset == 0) { *plen = sizeof(sc->sc_abstract_state); *pptr = &sc->sc_abstract_state; } else { *plen = 0; } return (0); } else if ((req->bmRequestType == UT_WRITE_CLASS_INTERFACE) && (req->wIndex[0] == sc->sc_ctrl_iface_no) && (req->wIndex[1] == 0x00) && (req->bRequest == UCDC_SET_CONTROL_LINE_STATE)) { *plen = 0; return (0); } else if ((req->bmRequestType == UT_WRITE_CLASS_INTERFACE) && (req->wIndex[0] == sc->sc_ctrl_iface_no) && (req->wIndex[1] == 0x00) && (req->bRequest == UCDC_SEND_BREAK)) { *plen = 0; return (0); } } return (ENXIO); /* use builtin handler */ } Index: head/sys/dev/usb/ufm_ioctl.h =================================================================== --- head/sys/dev/usb/ufm_ioctl.h (revision 355393) +++ head/sys/dev/usb/ufm_ioctl.h (revision 355394) @@ -1,45 +1,44 @@ /* $FreeBSD$ */ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2001 M. Warner Losh - * All rights reserved. + * Copyright (c) 2001 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions, and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * This code is based on ugen.c and ulpt.c developed by Lennart Augustsson. * This code includes software developed by the NetBSD Foundation, Inc. and * its contributors. */ #ifndef _UFM_IOCTL_H_ #define _UFM_IOCTL_H_ #include #define FM_SET_FREQ _IOWR('U', 200, int) #define FM_GET_FREQ _IOWR('U', 201, int) #define FM_START _IOWR('U', 202, int) #define FM_STOP _IOWR('U', 203, int) #define FM_GET_STAT _IOWR('U', 204, int) #endif /* _UFM_IOCTL_H_ */ Index: head/sys/dev/wi/if_wivar.h =================================================================== --- head/sys/dev/wi/if_wivar.h (revision 355393) +++ head/sys/dev/wi/if_wivar.h (revision 355394) @@ -1,189 +1,189 @@ /*- * SPDX-License-Identifier: BSD-4-Clause * - * Copyright (c) 2002 M Warner Losh . * Copyright (c) 1997, 1998, 1999 * Bill Paul . All rights reserved. + * Copyright (c) 2002 M Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Bill Paul. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ /* * Encryption controls. We can enable or disable encryption as * well as specify up to 4 encryption keys. We can also specify * which of the four keys will be used for transmit encryption. */ #define WI_RID_ENCRYPTION 0xFC20 #define WI_RID_AUTHTYPE 0xFC21 #define WI_RID_DEFLT_CRYPT_KEYS 0xFCB0 #define WI_RID_TX_CRYPT_KEY 0xFCB1 #define WI_RID_WEP_AVAIL 0xFD4F #define WI_RID_P2_TX_CRYPT_KEY 0xFC23 #define WI_RID_P2_CRYPT_KEY0 0xFC24 #define WI_RID_P2_CRYPT_KEY1 0xFC25 #define WI_RID_MICROWAVE_OVEN 0xFC25 #define WI_RID_P2_CRYPT_KEY2 0xFC26 #define WI_RID_P2_CRYPT_KEY3 0xFC27 #define WI_RID_P2_ENCRYPTION 0xFC28 #define WI_RID_ROAMING_MODE 0xFC2D #define WI_RID_CUR_TX_RATE 0xFD44 /* current TX rate */ #define WI_MAX_AID 256 /* max stations for ap operation */ struct wi_vap { struct ieee80211vap wv_vap; void (*wv_recv_mgmt)(struct ieee80211_node *, struct mbuf *, int, const struct ieee80211_rx_stats *rxs, int, int); int (*wv_newstate)(struct ieee80211vap *, enum ieee80211_state, int); }; #define WI_VAP(vap) ((struct wi_vap *)(vap)) struct wi_softc { struct ieee80211com sc_ic; struct mbufq sc_snd; device_t sc_dev; struct mtx sc_mtx; struct callout sc_watchdog; int sc_unit; int wi_gone; int sc_enabled; int sc_reset; int sc_firmware_type; #define WI_NOTYPE 0 #define WI_LUCENT 1 #define WI_INTERSIL 2 #define WI_SYMBOL 3 int sc_pri_firmware_ver; /* Primary firmware */ int sc_sta_firmware_ver; /* Station firmware */ unsigned int sc_nic_id; /* Type of NIC */ char * sc_nic_name; int wi_bus_type; /* Bus attachment type */ struct resource * local; int local_rid; struct resource * iobase; int iobase_rid; struct resource * irq; int irq_rid; struct resource * mem; int mem_rid; bus_space_handle_t wi_localhandle; bus_space_tag_t wi_localtag; bus_space_handle_t wi_bhandle; bus_space_tag_t wi_btag; bus_space_handle_t wi_bmemhandle; bus_space_tag_t wi_bmemtag; void * wi_intrhand; struct ieee80211_channel *wi_channel; int wi_io_addr; int wi_cmd_count; int sc_flags; int sc_bap_id; int sc_bap_off; int sc_porttype; u_int16_t sc_portnum; u_int16_t sc_encryption; u_int16_t sc_monitor_port; u_int16_t sc_chanmask; /* RSSI interpretation */ u_int16_t sc_min_rssi; /* clamp sc_min_rssi < RSSI */ u_int16_t sc_max_rssi; /* clamp RSSI < sc_max_rssi */ u_int16_t sc_dbm_offset; /* dBm ~ RSSI - sc_dbm_offset */ int sc_buflen; /* TX buffer size */ int sc_ntxbuf; #define WI_NTXBUF 3 struct { int d_fid; int d_len; } sc_txd[WI_NTXBUF]; /* TX buffers */ int sc_txnext; /* index of next TX */ int sc_txcur; /* index of current TX*/ int sc_tx_timer; struct wi_counters sc_stats; u_int16_t sc_ibss_port; struct timeval sc_last_syn; int sc_false_syns; u_int16_t sc_txbuf[IEEE80211_MAX_LEN/2]; struct wi_tx_radiotap_header sc_tx_th; struct wi_rx_radiotap_header sc_rx_th; }; /* maximum consecutive false change-of-BSSID indications */ #define WI_MAX_FALSE_SYNS 10 #define WI_FLAGS_HAS_ENHSECURITY 0x0001 #define WI_FLAGS_HAS_WPASUPPORT 0x0002 #define WI_FLAGS_HAS_ROAMING 0x0020 #define WI_FLAGS_HAS_FRAGTHR 0x0200 #define WI_FLAGS_HAS_DBMADJUST 0x0400 #define WI_FLAGS_RUNNING 0x0800 #define WI_FLAGS_PROMISC 0x1000 struct wi_card_ident { u_int16_t card_id; char *card_name; u_int8_t firm_type; }; #define WI_PRISM_MIN_RSSI 0x1b #define WI_PRISM_MAX_RSSI 0x9a #define WI_PRISM_DBM_OFFSET 100 /* XXX */ #define WI_LUCENT_MIN_RSSI 47 #define WI_LUCENT_MAX_RSSI 138 #define WI_LUCENT_DBM_OFFSET 149 #define WI_RSSI_TO_DBM(sc, rssi) (MIN((sc)->sc_max_rssi, \ MAX((sc)->sc_min_rssi, (rssi))) - (sc)->sc_dbm_offset) #define WI_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) #define WI_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) #define WI_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->sc_mtx, MA_OWNED) int wi_attach(device_t); int wi_detach(device_t); int wi_shutdown(device_t); int wi_alloc(device_t, int); void wi_free(device_t); extern devclass_t wi_devclass; void wi_intr(void *); int wi_mgmt_xmit(struct wi_softc *, caddr_t, int); void wi_stop(struct wi_softc *, int); void wi_init(struct wi_softc *); Index: head/sys/i386/include/_bus.h =================================================================== --- head/sys/i386/include/_bus.h (revision 355393) +++ head/sys/i386/include/_bus.h (revision 355394) @@ -1,52 +1,51 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2005 M. Warner Losh. - * All rights reserved. + * Copyright (c) 2005 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions, and the following disclaimer, * without modification, immediately at the beginning of the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef I386_INCLUDE__BUS_H #define I386_INCLUDE__BUS_H /* * Bus address and size types */ #ifdef PAE typedef uint64_t bus_addr_t; #else typedef uint32_t bus_addr_t; #endif typedef uint32_t bus_size_t; /* * Access methods for bus resources and address space. */ typedef int bus_space_tag_t; typedef u_int bus_space_handle_t; #endif /* I386_INCLUDE__BUS_H */ Index: head/sys/mips/cavium/uart_cpu_octeonusart.c =================================================================== --- head/sys/mips/cavium/uart_cpu_octeonusart.c (revision 355393) +++ head/sys/mips/cavium/uart_cpu_octeonusart.c (revision 355394) @@ -1,176 +1,175 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * + * Copyright (c) 2006 Wojciech A. Koszek All rights reserved. * Copyright (c) 2009 M. Warner Losh - * Copyright (c) 2006 Wojciech A. Koszek - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id$ */ #include "opt_uart.h" #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include bus_space_tag_t uart_bus_space_io; bus_space_tag_t uart_bus_space_mem; /* * Specailized uart bus space. We present a 1 apart byte oriented * bus to the outside world, but internally translate to/from the 8-apart * 64-bit word bus that's on the octeon. We only support simple read/write * in this space. Everything else is undefined. */ static uint8_t ou_bs_r_1(void *t, bus_space_handle_t handle, bus_size_t offset) { return (cvmx_read64_uint64(handle + offset)); } static uint16_t ou_bs_r_2(void *t, bus_space_handle_t handle, bus_size_t offset) { return (cvmx_read64_uint64(handle + offset)); } static uint32_t ou_bs_r_4(void *t, bus_space_handle_t handle, bus_size_t offset) { return (cvmx_read64_uint64(handle + offset)); } static uint64_t ou_bs_r_8(void *t, bus_space_handle_t handle, bus_size_t offset) { return (cvmx_read64_uint64(handle + offset)); } static void ou_bs_w_1(void *t, bus_space_handle_t bsh, bus_size_t offset, uint8_t value) { cvmx_write64_uint64(bsh + offset, value); } static void ou_bs_w_2(void *t, bus_space_handle_t bsh, bus_size_t offset, uint16_t value) { cvmx_write64_uint64(bsh + offset, value); } static void ou_bs_w_4(void *t, bus_space_handle_t bsh, bus_size_t offset, uint32_t value) { cvmx_write64_uint64(bsh + offset, value); } static void ou_bs_w_8(void *t, bus_space_handle_t bsh, bus_size_t offset, uint64_t value) { cvmx_write64_uint64(bsh + offset, value); } struct bus_space octeon_uart_tag = { .bs_map = generic_bs_map, .bs_unmap = generic_bs_unmap, .bs_subregion = generic_bs_subregion, .bs_barrier = generic_bs_barrier, .bs_r_1 = ou_bs_r_1, .bs_r_2 = ou_bs_r_2, .bs_r_4 = ou_bs_r_4, .bs_r_8 = ou_bs_r_8, .bs_w_1 = ou_bs_w_1, .bs_w_2 = ou_bs_w_2, .bs_w_4 = ou_bs_w_4, .bs_w_8 = ou_bs_w_8, }; extern struct uart_class uart_oct16550_class; int uart_cpu_eqres(struct uart_bas *b1, struct uart_bas *b2) { return ((b1->bsh == b2->bsh && b1->bst == b2->bst) ? 1 : 0); } int uart_cpu_getdev(int devtype, struct uart_devinfo *di) { struct uart_class *class = &uart_oct16550_class; /* * These fields need to be setup corretly for uart_getenv to * work in all cases. */ uart_bus_space_io = NULL; /* No io map for this device */ uart_bus_space_mem = &octeon_uart_tag; di->bas.bst = uart_bus_space_mem; /* * If env specification for UART exists it takes precedence: * hw.uart.console="mm:0xf1012000" or similar */ if (uart_getenv(devtype, di, class) == 0) return (0); /* * Fallback to UART0 for console. */ di->ops = uart_getops(class); di->bas.chan = 0; /* XXX */ if (bus_space_map(di->bas.bst, CVMX_MIO_UARTX_RBR(0), uart_getrange(class), 0, &di->bas.bsh) != 0) return (ENXIO); di->bas.regshft = 3; di->bas.rclk = 0; di->baudrate = 115200; di->databits = 8; di->stopbits = 1; di->parity = UART_PARITY_NONE; return (0); } Index: head/sys/mips/include/_bus.h =================================================================== --- head/sys/mips/include/_bus.h (revision 355393) +++ head/sys/mips/include/_bus.h (revision 355394) @@ -1,52 +1,51 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2005 M. Warner Losh. - * All rights reserved. + * Copyright (c) 2005 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions, and the following disclaimer, * without modification, immediately at the beginning of the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * from: src/sys/i386/include/_bus.h,v 1.1 2005/04/18 21:45:33 imp * $FreeBSD$ */ #ifndef MIPS_INCLUDE__BUS_H #define MIPS_INCLUDE__BUS_H /* * Bus address and size types */ #if defined(CPU_CNMIPS) && !defined(__mips_n64) typedef uint64_t bus_addr_t; #else typedef uintptr_t bus_addr_t; #endif typedef uintptr_t bus_size_t; /* * Access methods for bus resources and address space. */ typedef struct bus_space *bus_space_tag_t; typedef bus_addr_t bus_space_handle_t; #endif /* MIPS_INCLUDE__BUS_H */ Index: head/sys/mips/include/elf.h =================================================================== --- head/sys/mips/include/elf.h (revision 355393) +++ head/sys/mips/include/elf.h (revision 355394) @@ -1,215 +1,215 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD AND BSD-2-Clause-NetBSD * - * Copyright (c) 2013 M. Warner Losh. + * Copyright (c) 2013 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ /*- * Copyright (c) 2013 The NetBSD Foundation, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * See below starting with the line with $NetBSD...$ for code this applies to. */ #ifndef __MIPS_ELF_H #define __MIPS_ELF_H /* FreeBSD specific bits - derived from FreeBSD specific files and changes to old elf.h */ /* * Define __ELF_WORD_SIZE based on the ABI, if not defined yet. This sets * the proper defaults when we're not trying to do 32-bit on 64-bit systems. * We include both 32 and 64 bit versions so we can support multiple ABIs. */ #ifndef __ELF_WORD_SIZE #if defined(__mips_n64) #define __ELF_WORD_SIZE 64 #else #define __ELF_WORD_SIZE 32 #endif #endif #include #include #include #define ELF_ARCH EM_MIPS #define ELF_ARCH32 EM_MIPS #define ELF_MACHINE_OK(x) ((x) == ELF_ARCH) /* Define "machine" characteristics */ #if __ELF_WORD_SIZE == 32 #define ELF_TARG_CLASS ELFCLASS32 #else #define ELF_TARG_CLASS ELFCLASS64 #endif #ifdef __MIPSEB__ #define ELF_TARG_DATA ELFDATA2MSB #else #define ELF_TARG_DATA ELFDATA2LSB #endif #define ELF_TARG_MACH EM_MIPS #define ELF_TARG_VER 1 /* * Auxiliary vector entries for passing information to the interpreter. * * The i386 supplement to the SVR4 ABI specification names this "auxv_t", * but POSIX lays claim to all symbols ending with "_t". */ typedef struct { /* Auxiliary vector entry on initial stack */ int a_type; /* Entry type. */ union { int a_val; /* Integer value. */ void *a_ptr; /* Address. */ void (*a_fcn)(void); /* Function pointer (not used). */ } a_un; } Elf32_Auxinfo; typedef struct { /* Auxiliary vector entry on initial stack */ long a_type; /* Entry type. */ union { long a_val; /* Integer value. */ void *a_ptr; /* Address. */ void (*a_fcn)(void); /* Function pointer (not used). */ } a_un; } Elf64_Auxinfo; __ElfType(Auxinfo); #define ET_DYN_LOAD_ADDR 0x0120000 /* * Constant to mark start of symtab/strtab saved by trampoline */ #define SYMTAB_MAGIC 0x64656267 /* from NetBSD's sys/mips/include/elf_machdep.h $NetBSD: elf_machdep.h,v 1.18 2013/05/23 21:39:49 christos Exp $ */ /* mips relocs. */ #define R_MIPS_NONE 0 #define R_MIPS_16 1 #define R_MIPS_32 2 #define R_MIPS_REL32 3 #define R_MIPS_REL R_MIPS_REL32 #define R_MIPS_26 4 #define R_MIPS_HI16 5 /* high 16 bits of symbol value */ #define R_MIPS_LO16 6 /* low 16 bits of symbol value */ #define R_MIPS_GPREL16 7 /* GP-relative reference */ #define R_MIPS_LITERAL 8 /* Reference to literal section */ #define R_MIPS_GOT16 9 /* Reference to global offset table */ #define R_MIPS_GOT R_MIPS_GOT16 #define R_MIPS_PC16 10 /* 16 bit PC relative reference */ #define R_MIPS_CALL16 11 /* 16 bit call thru glbl offset tbl */ #define R_MIPS_CALL R_MIPS_CALL16 #define R_MIPS_GPREL32 12 /* 13, 14, 15 are not defined at this point. */ #define R_MIPS_UNUSED1 13 #define R_MIPS_UNUSED2 14 #define R_MIPS_UNUSED3 15 /* * The remaining relocs are apparently part of the 64-bit Irix ELF ABI. */ #define R_MIPS_SHIFT5 16 #define R_MIPS_SHIFT6 17 #define R_MIPS_64 18 #define R_MIPS_GOT_DISP 19 #define R_MIPS_GOT_PAGE 20 #define R_MIPS_GOT_OFST 21 #define R_MIPS_GOT_HI16 22 #define R_MIPS_GOT_LO16 23 #define R_MIPS_SUB 24 #define R_MIPS_INSERT_A 25 #define R_MIPS_INSERT_B 26 #define R_MIPS_DELETE 27 #define R_MIPS_HIGHER 28 #define R_MIPS_HIGHEST 29 #define R_MIPS_CALL_HI16 30 #define R_MIPS_CALL_LO16 31 #define R_MIPS_SCN_DISP 32 #define R_MIPS_REL16 33 #define R_MIPS_ADD_IMMEDIATE 34 #define R_MIPS_PJUMP 35 #define R_MIPS_RELGOT 36 #define R_MIPS_JALR 37 /* TLS relocations */ #define R_MIPS_TLS_DTPMOD32 38 /* Module number 32 bit */ #define R_MIPS_TLS_DTPREL32 39 /* Module-relative offset 32 bit */ #define R_MIPS_TLS_DTPMOD64 40 /* Module number 64 bit */ #define R_MIPS_TLS_DTPREL64 41 /* Module-relative offset 64 bit */ #define R_MIPS_TLS_GD 42 /* 16 bit GOT offset for GD */ #define R_MIPS_TLS_LDM 43 /* 16 bit GOT offset for LDM */ #define R_MIPS_TLS_DTPREL_HI16 44 /* Module-relative offset, high 16 bits */ #define R_MIPS_TLS_DTPREL_LO16 45 /* Module-relative offset, low 16 bits */ #define R_MIPS_TLS_GOTTPREL 46 /* 16 bit GOT offset for IE */ #define R_MIPS_TLS_TPREL32 47 /* TP-relative offset, 32 bit */ #define R_MIPS_TLS_TPREL64 48 /* TP-relative offset, 64 bit */ #define R_MIPS_TLS_TPREL_HI16 49 /* TP-relative offset, high 16 bits */ #define R_MIPS_TLS_TPREL_LO16 50 /* TP-relative offset, low 16 bits */ #define R_MIPS_max 51 #define R_TYPE(name) __CONCAT(R_MIPS_,name) #define R_MIPS16_min 100 #define R_MIPS16_26 100 #define R_MIPS16_GPREL 101 #define R_MIPS16_GOT16 102 #define R_MIPS16_CALL16 103 #define R_MIPS16_HI16 104 #define R_MIPS16_LO16 105 #define R_MIPS16_max 106 #define R_MIPS_COPY 126 #define R_MIPS_JUMP_SLOT 127 #endif /* __MIPS_ELF_H */ Index: head/sys/mips/mips/ptrace_machdep.c =================================================================== --- head/sys/mips/mips/ptrace_machdep.c (revision 355393) +++ head/sys/mips/mips/ptrace_machdep.c (revision 355394) @@ -1,39 +1,38 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2009 M. Warner Losh. - * All rights reserved. + * Copyright (c) 2009 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #if 0 #include __FBSDID("$FreeBSD$"); /* * This file is a place holder for MIPS. Some models of MIPS may need special * functions here, but for now nothing is needed. The MI parts of ptrace * suffice. */ #endif Index: head/sys/powerpc/include/_bus.h =================================================================== --- head/sys/powerpc/include/_bus.h (revision 355393) +++ head/sys/powerpc/include/_bus.h (revision 355394) @@ -1,50 +1,49 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2005 M. Warner Losh. - * All rights reserved. + * Copyright (c) 2005 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions, and the following disclaimer, * without modification, immediately at the beginning of the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef POWERPC_INCLUDE__BUS_H #define POWERPC_INCLUDE__BUS_H #include /* * Bus address and size types */ typedef vm_paddr_t bus_addr_t; typedef vm_size_t bus_size_t; /* * Access methods for bus resources and address space. */ typedef struct bus_space *bus_space_tag_t; typedef vm_offset_t bus_space_handle_t; #endif /* POWERPC_INCLUDE__BUS_H */ Index: head/sys/riscv/include/_bus.h =================================================================== --- head/sys/riscv/include/_bus.h (revision 355393) +++ head/sys/riscv/include/_bus.h (revision 355394) @@ -1,46 +1,45 @@ /*- - * Copyright (c) 2005 M. Warner Losh. - * All rights reserved. + * Copyright (c) 2005 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions, and the following disclaimer, * without modification, immediately at the beginning of the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _MACHINE__BUS_H_ #define _MACHINE__BUS_H_ /* * Addresses (in bus space). */ typedef u_long bus_addr_t; typedef u_long bus_size_t; /* * Access methods for bus space. */ typedef u_long bus_space_handle_t; typedef struct bus_space *bus_space_tag_t; #endif /* !_MACHINE__BUS_H_ */ Index: head/sys/sparc64/include/_bus.h =================================================================== --- head/sys/sparc64/include/_bus.h (revision 355393) +++ head/sys/sparc64/include/_bus.h (revision 355394) @@ -1,41 +1,40 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2005 M. Warner Losh. - * All rights reserved. + * Copyright (c) 2005 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions, and the following disclaimer, * without modification, immediately at the beginning of the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef SPARC64_INCLUDE__BUS_H #define SPARC64_INCLUDE__BUS_H typedef u_long bus_addr_t; typedef u_long bus_size_t; typedef u_long bus_space_handle_t; typedef struct bus_space_tag *bus_space_tag_t; #endif /* SPARC64_INCLUDE__BUS_H */ Index: head/tools/tools/git/git-svn-rebase =================================================================== --- head/tools/tools/git/git-svn-rebase (revision 355393) +++ head/tools/tools/git/git-svn-rebase (revision 355394) @@ -1,57 +1,57 @@ #!/bin/sh # $FreeBSD$ # SPDX-License-Identifier: BSD-2-Clause-FreeBSD # -# Copyright (c) 2018 M. Warner Losh +# Copyright (c) 2018 M. Warner Losh # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # simple script to keep all my branches up to date while tracking # FreeBSD (or any upstream svn source) with git. Run it often, and it # will rebase all the branches so they don't get too stale. # Takes no args, and acts goofy if you have really old branches # which is why stable/* and mfc* are excluded. Caution to should be taken # when using this. # FAIL= echo ----------------- Checkout master for svn rebase ------------ git checkout master echo ----------------- Rebasing our master to svn upstream ------------ git svn rebase for i in $(git branch --no-merge | grep -v stable/ | grep -v mfc); do echo ----------------- Rebasing $i to the tip of master ------------ git rebase master $i || { echo "****************** REBASE OF $i FAILED, ABORTING *****************" FAIL="$FAIL $i" git rebase --abort } done echo ----------------- Checkout out master again ------------ git checkout master git branch if [ -n "$FAIL" ]; then echo Failed branches: $FAIL fi Index: head/tools/tools/nanobsd/dhcpd/common =================================================================== --- head/tools/tools/nanobsd/dhcpd/common (revision 355393) +++ head/tools/tools/nanobsd/dhcpd/common (revision 355394) @@ -1,258 +1,258 @@ # $FreeBSD$ #- -# Copyright (c) 2014 M. Warner Losh. +# Copyright (c) 2014 M. Warner Losh # Copyright (c) 2010 iXsystems, Inc. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL iXsystems, Inc OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # # This file is heavily derived from both Sam Leffler's Avilia config, # as well as the BSDRP project's config file. Neither of these have # an explicit copyright/license statement, but are implicitly BSDL. This # example has been taken from the FreeNAS project (an early version) and # simplified to meet the needs of the example. # # NB: You want the other file NANO_PMAKE="make -j $(sysctl -n hw.ncpu)" NANO_CFG_BASE=$(pwd) NANO_CFG_BASE=${NANO_CFG_BASE%/dhcpd} NANO_SRC=$(pwd) NANO_SRC=${NANO_SRC%/tools/tools/nanobsd/dhcpd} NANO_OBJ=${NANO_SRC}/../dhcpd/obj # Where cust_pkg() finds packages to install #XXX: Is this the right place? #NANO_PORTS=$(realpath ${NANO_SRC}/../ports) NANO_PORTS=/usr/ports NANO_PACKAGE_DIR=${NANO_SRC}/${NANO_TOOLS}/Pkg NANO_DATADIR=${NANO_OBJ}/_.data NANO_DATASIZE=40960 NANO_INIT_IMG2=0 unset MAKEOBJDIRPREFIX # this to go into nanobsd.sh NANO_PORTS=${NANO_PORTS:-/usr/ports} customize_cmd cust_allow_ssh_root add_etc_make_conf() { touch ${NANO_WORLDDIR}/etc/make.conf } customize_cmd add_etc_make_conf clean_usr_local() { LOCAL_DIR=${NANO_WORLDDIR}/usr/local pprint 2 "Clean and create world directory (${LOCAL_DIR})" if rm -rf ${LOCAL_DIR}/ > /dev/null 2>&1 ; then true else chflags -R noschg ${LOCAL_DIR}/ rm -rf ${LOCAL_DIR}/ fi for f in bin etc lib libdata libexec sbin share; do mkdir -p ${LOCAL_DIR}/$f done } customize_cmd clean_usr_local cust_install_machine_files() { echo "cd ${NANO_CFG_BASE}/Files" cd ${NANO_CFG_BASE}/Files find . -print | grep -Ev '/(CVS|\.git|\.hg|\.svn)' | cpio -dumpv ${NANO_WORLDDIR} } customize_cmd cust_install_files customize_cmd cust_install_machine_files buildenv() { cd ${NANO_SRC} env __MAKE_CONF=${NANO_MAKE_CONF_BUILD} DESTDIR=${NANO_WORLDDIR} make buildenv } NANO_MAKEFS="makefs -B big \ -o bsize=4096,fsize=512,density=8192,optimization=space" export NANO_MAKEFS # NB: leave c++ enabled so devd can be built CONF_BUILD=" WITHOUT_ACPI=true WITHOUT_ATM=true WITHOUT_AUDIT=true WITHOUT_BLUETOOTH=true WITHOUT_CALENDAR=true WITHOUT_DICT=true WITHOUT_EXAMPLES=true WITHOUT_GAMES=true WITHOUT_GCOV=true WITHOUT_HTML=true WITHOUT_IPFILTER=true WITHOUT_LOCALES=true WITHOUT_LPR=true WITHOUT_MAN=true WITHOUT_NETCAT=true WITHOUT_NIS=true WITHOUT_NLS=true WITHOUT_NS_CACHING=true WITHOUT_PROFILE=true WITHOUT_SENDMAIL=true WITHOUT_SHAREDOCS=true WITHOUT_SYSCONS=true WITHOUT_LIB32=true " CONF_INSTALL="$CONF_BUILD INSTALL_NODEBUG=t NOPORTDOCS=t NO_INSTALL_MANPAGES=t " # The following would help... # WITHOUT_TOOLCHAIN=true can't build ports # WITHOUT_INSTALLLIB=true libgcc.a PKG_ONLY_MAKE_CONF=" WITHOUT_TOOLCHAIN=true WITHOUT_INSTALLLIB=true " NANO_PACKAGE_ONLY=1 # install a package from a pre-built binary do_add_pkg () { # Need to create ${NANO_OBJ}/ports in this add_pkg_${port} function set -x mkdir -p ${NANO_OBJ}/ports/distfiles mkdir -p ${NANO_OBJ}/ports/packages mkdir -p ${NANO_WORLDDIR}/usr/ports/packages mkdir -p ${NANO_WORLDDIR}/usr/ports/distfiles mount -t nullfs -o noatime ${NANO_OBJ}/ports/packages \ ${NANO_WORLDDIR}/usr/ports/packages mount -t nullfs -o noatime ${NANO_OBJ}/ports/distfiles \ ${NANO_WORLDDIR}/usr/ports/distfiles CR env ASSUME_ALWAYS_YES=YES SIGNATURE_TYPE=none /usr/sbin/pkg add /usr/ports/packages/All/$1.txz umount ${NANO_WORLDDIR}/usr/ports/distfiles umount ${NANO_WORLDDIR}/usr/ports/packages rmdir ${NANO_WORLDDIR}/usr/ports/packages rmdir ${NANO_WORLDDIR}/usr/ports/distfiles rmdir ${NANO_WORLDDIR}/usr/ports set +x } # Build a port (with the side effect of creating a package) do_add_port () { local port_path port_path=$1 shift set -x # Need to create ${NANO_OBJ}/ports in this add_port_${port} function mkdir -p ${NANO_OBJ}/ports/distfiles mkdir -p ${NANO_OBJ}/ports/packages mkdir -p ${NANO_PORTS}/packages mkdir -p ${NANO_PORTS}/distfiles mkdir -p ${NANO_WORLDDIR}/usr/src mkdir -p ${NANO_WORLDDIR}/usr/ports mount -t nullfs -o noatime ${NANO_SRC} ${NANO_WORLDDIR}/usr/src mount -t nullfs -o noatime ${NANO_PORTS} ${NANO_WORLDDIR}/usr/ports mount -t nullfs -o noatime ${NANO_OBJ}/ports/packages \ ${NANO_WORLDDIR}/usr/ports/packages mount -t nullfs -o noatime ${NANO_OBJ}/ports/distfiles \ ${NANO_WORLDDIR}/usr/ports/distfiles mkdir -p ${NANO_WORLDDIR}/dev mount -t devfs devfs ${NANO_WORLDDIR}/dev mkdir -p ${NANO_WORLDDIR}/usr/workdir cp /etc/resolv.conf ${NANO_WORLDDIR}/etc/resolv.conf # OK, a little inefficient, but likely not enough to worry about. CR ldconfig /lib /usr/lib /usr/local/lib CR ldconfig -R CR ldconfig -r # Improvement: Don't know why package-recursive don't works here CR "env UNAME_p=${NANO_ARCH} TARGET=${NANO_ARCH} \ TARGET_ARCH=${NANO_ARCH} PORTSDIR=${NANO_PORTS} make \ __MAKE_CONF=${NANO_MAKE_CONF_BUILD} \ WRKDIRPREFIX=/usr/workdir -C /usr/ports/$port_path \ package-recursive BATCH=yes $* clean FORCE_PKG_REGISTER=t" rm ${NANO_WORLDDIR}/etc/resolv.conf rm -rf ${NANO_WORLDDIR}/usr/obj rm -rf ${NANO_WORLDDIR}/usr/workdir umount ${NANO_WORLDDIR}/dev umount ${NANO_WORLDDIR}/usr/ports/packages umount ${NANO_WORLDDIR}/usr/ports/distfiles umount ${NANO_WORLDDIR}/usr/ports umount ${NANO_WORLDDIR}/usr/src set +x } # Need to check if this function works with cross-compiling architecture!!!! # Recursive complex fonction: Generate one function for each ports add_port () { local port_path=$1 local port=`echo $1 | sed -e 's/\//_/'` shift # Check if package already exist # Need to: # 1. check ARCH of this package! # 2. Add a trap cd ${NANO_PORTS}/${port_path} PKG_NAME=`env PORTSDIR=${NANO_PORTS} make __MAKE_CONF=${NANO_MAKE_CONF_BUILD} package-name` if [ -f ${NANO_OBJ}/ports/packages/All/${PKG_NAME}.txz ]; then # Pkg file found: Generate add_pkg_NAME function eval " add_pkg_${port} () { do_add_pkg ${PKG_NAME} } customize_cmd add_pkg_${port} " else # No pkg file: Generate add_port_NAME function eval " add_port_${port} () { do_add_port ${port_path} $* } customize_cmd add_port_${port} " NANO_PACKAGE_ONLY=0 fi } die() { echo "$*" exit 1 } # Automatically include the packaging port here so it is always first so it # builds the port and adds the package so we can add other packages. add_port ports-mgmt/pkg rp=$(realpath ${NANO_OBJ}/) __a=`mount | grep ${rp} | awk '{print length($3), $3;}' | sort -rn | awk '{$1=""; print;}'` if [ -n "$__a" ]; then echo "unmounting $__a" umount $__a fi NANO_BOOTLOADER="boot/boot0" Index: head/tools/tools/nanobsd/dhcpd/os-base =================================================================== --- head/tools/tools/nanobsd/dhcpd/os-base (revision 355393) +++ head/tools/tools/nanobsd/dhcpd/os-base (revision 355394) @@ -1,194 +1,194 @@ # $FreeBSD$ #- -# Copyright (c) 2014 M. Warner Losh. +# Copyright (c) 2014 M. Warner Losh # Copyright (c) 2010-2011 iXsystems, Inc. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL iXsystems, Inc. OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # This file is heavily derived from both Sam Leffler's Avilia config, # as well as the BSDRP project's config file. Neither of these have # an explicit copyright/license statement, but are implicitly BSDL. This # example has been taken from the FreeNAS project and simplified to meet # the needs of the example. # # Pull in common definitions. . common NANO_BOOT0CFG="-o packet -s 1 -m 3 -t 18" # /var -> ~10MB (look through rc.initdiskless for the formula of how this # number is calculated out). Since we hope to run NANO_RAM_TMPVARSIZE=10240 NANO_IMAGES=2 FlashDevice generic 2g if [ "$DEBUG" = 1 ]; then DEBUG_BUILD=" DEBUG_FLAGS= -g " else DEBUG_INSTALL=" INSTALL_NODEBUG= t " fi CONF_INSTALL="$CONF_BUILD ${DEBUG_BUILD} " CONF_INSTALL="$CONF_INSTALL ${DEBUG_INSTALL} " add_port security/sudo add_port ftp/curl if [ "${NANO_PACKAGE_ONLY}" -eq 1 ]; then CONF_INSTALL="${CONF_INSTALL} ${PKG_ONLY_MAKE_CONF} " echo "Automatically building a thin image with packages" else echo "Automatically building a * * F A T * * image so we can build ports" fi VARS="MASTER_SITE_BACKUP MASTER_SITE_OVERRIDE PACKAGEROOT PACKAGESITE" for var in $VARS; do val=$(eval echo "\$$var") if [ -n "$val" ]; then CONF_INSTALL="${CONF_INSTALL} $var=$val" fi done if [ "$PACKAGE_PREP_BUILD" = 1 ]; then echo "Skipping post-package customize steps" do_image=false else hack_nsswitch_conf ( ) { # Remove all references to NIS in the nsswitch.conf file # Not sure this is still needed, but FreeNAS has it... sed -i.bak -es/nis/files/g ${NANO_WORLDDIR}/etc/nsswitch.conf rm -f ${NANO_WORLDDIR}/etc/nsswitch.conf.bak } customize_cmd hack_nsswitch_conf save_build ( ) { VERSION_FILE=${NANO_WORLDDIR}/etc/version if [ "${SVNREVISION}" = "${REVISION}" ]; then echo "${NANO_NAME}" > "${VERSION_FILE}" else echo "${NANO_NAME} (${SVNREVISION})" > "${VERSION_FILE}" fi } customize_cmd save_build remove_patch_divots ( ) { find ${NANO_WORLDDIR} -name \*.orig -or -name \*.rej -delete } customize_cmd remove_patch_divots configure_mnt_md ( ) { mkdir -m 755 -p ${NANO_WORLDDIR}/conf/base/mnt echo 2048 > ${NANO_WORLDDIR}/conf/base/mnt/md_size } customize_cmd configure_mnt_md shrink_md_fbsize() { # We have a lot of little files on our memory disks. Let's decrease # the block and frag size to fit more little files on them (this # halves our space requirement by ~50% on /etc and /var on 8.x -- # and gives us more back on 9.x as the default block and frag size # are 4 times larger). sed -i '' -e 's,-S -i 4096,-S -i 4096 -b 4096 -f 512,' \ ${NANO_WORLDDIR}/etc/rc.initdiskless } customize_cmd shrink_md_fbsize if [ "${DEBUG}" = 1 ]; then unmute_console_logging() { # /var is small. Don't fill it up with messages from console.log # because it's a chatty log. sed -i '' -e 's/#console.info/console.info/' \ "${NANO_WORLDDIR}/etc/syslog.conf" } customize_cmd unmute_console_logging fi product_custom() { gzip -v9 ${NANO_WORLDDIR}/boot/kernel/kernel # kill includes (saves 14MB) find ${NANO_WORLDDIR}/usr/local/include \! -name 'pyconfig.h' -type f | xargs rm -f # kill docs (saves 22MB) rm -rf ${NANO_WORLDDIR}/usr/local/share/doc rm -rf ${NANO_WORLDDIR}/usr/local/share/gtk-doc # and info (2MB) rm -rf ${NANO_WORLDDIR}/usr/local/info # and man pages (4.4MB) rm -rf ${NANO_WORLDDIR}/usr/local/man # and examples (1.7M) rm -rf ${NANO_WORLDDIR}/usr/local/share/examples # and groff_fonts junk (3MB) rm -rf ${NANO_WORLDDIR}/usr/share/groff_font rm -rf ${NANO_WORLDDIR}/usr/share/tmac rm -rf ${NANO_WORLDDIR}/usr/share/me # Kill all .a's and .la's that are installed (20MB+) find ${NANO_WORLDDIR} -name \*.a -or -name \*.la -delete # magic.mgc is just a speed optimization. Kill it for 1.7MB rm -f ${NANO_WORLDDIR}/usr/share/misc/magic.mgc # Last second tweaks chown -R root:wheel ${NANO_WORLDDIR}/root chmod 0755 ${NANO_WORLDDIR}/root/* chmod 0755 ${NANO_WORLDDIR}/* chown -R root:wheel ${NANO_WORLDDIR}/etc chown -R root:wheel ${NANO_WORLDDIR}/boot chown root:wheel ${NANO_WORLDDIR}/ chown root:wheel ${NANO_WORLDDIR}/usr find ${NANO_WORLDDIR} -type f -name "*~" -delete find ${NANO_WORLDDIR}/usr/local -type f -name "*.po" -delete find ${NANO_WORLDDIR} -type f -name "*.service" -delete } late_customize_cmd product_custom fi # [ $PACKAGE_PREP_BUILD = 1 ] Index: head/tools/tools/nanobsd/embedded/beaglebone.cfg =================================================================== --- head/tools/tools/nanobsd/embedded/beaglebone.cfg (revision 355393) +++ head/tools/tools/nanobsd/embedded/beaglebone.cfg (revision 355394) @@ -1,36 +1,36 @@ # $FreeBSD$ #- -# Copyright (c) 2015 M. Warner Losh. +# Copyright (c) 2015 M. Warner Losh # Copyright (c) 2010-2011 iXsystems, Inc. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL iXsystems, Inc. OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # NANO_ARCH=armv7 NANO_KERNEL=BEAGLEBONE NANO_DRIVE=mmcsd0 NANO_NAME=beaglebone NANO_BOOT_PKG=u-boot-beaglebone NANO_CPUTYPE=cortex-a8 . common # Pull in common definitions, keep last Index: head/tools/tools/nanobsd/embedded/common =================================================================== --- head/tools/tools/nanobsd/embedded/common (revision 355393) +++ head/tools/tools/nanobsd/embedded/common (revision 355394) @@ -1,660 +1,660 @@ # $FreeBSD$ #- -# Copyright (c) 2015 M. Warner Losh. +# Copyright (c) 2015 M. Warner Losh # Copyright (c) 2010-2011 iXsystems, Inc. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL iXsystems, Inc OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # # This file is heavily derived from both Sam Leffler's Avilia config, # as well as the BSDRP project's config file. Neither of these have # an explicit copyright/license statement, but are implicitly BSDL. This # example has been taken from the FreeNAS project (an early version) and # simplified to meet the needs of the example. # # NB: You want the other file as the command line arg :) # Missing in base: # o mkimg setting active partition # o mkimg starting at arbitrary offset (needed for A10, et al) # o mtools still needed because we have no makefs -t msdos # o nanobsd doesn't record changes to WORLDTEMP in customization # scripts yet, so we have kludge to pick up all files # o easy way for pkg to grab files from other repos and put that # data on the image # o Need to have some way to create / resize the s4 slice to do ping # pong bouncing between s3 and s4 for an arbitrary image. we can resize # one slice, not two # o hints in the uboot ports for how to create the image # # Missing here # o documentation for how to run the qemu images # o msdos mtools fallback # o special boot for !x86 !arm platforms # o qemu image for arm # o qemu image for aarch64 # o qemu image for armv6/armv7 # o easy support for different image / vm formats # o need to promote much of this to nanobsd.sh and friends # o uses old kludge to build image w/o ownership being right # for many files. Should move to mtree-dedup.awk. # o support for EFI images # o support for GPT partitioning # # Long Term # o common tooling for creating images for odd-ball platforms # o support for boot loaders other than uboot in the image # or via special instructions # o no pony support; sadly, you cannot have a pony # if [ -z $NANO_NAME ]; then echo "NANO_NAME not defined. Use foo.cfg instead." fi NANO_SLICE_FAT_SIZE=32m NANO_SLICE_CFG_SIZE=32m NANO_BOOT2CFG="-h -S115200" NANO_RAM_ETCSIZE=8192 NANO_RAM_TMPVARSIZE=8192 NANO_IMAGES=2 NANO_PMAKE="make -j $(sysctl -n hw.ncpu)" NANO_CFG_BASE=$(pwd) NANO_CFG_BASE=$(realpath ${NANO_CFG_BASE}/..) NANO_SRC=$(realpath ${NANO_CFG_BASE}/../../..) #### XXX share obj if [ -z ${NANO_CPUTYPE} ]; then NANO_OBJ=${NANO_SRC}/../embedded/obj else # Alas, I can't set OBJTREE to ${MACHINE}.${MACHINE_ARCH}.${CPUTYPE} # so this will have to do until I can. NANO_OBJ=${NANO_SRC}/../embedded/obj.${NANO_CPUTYPE} fi NANO_LOG=${NANO_OBJ}/../${NANO_NAME} NANO_DISKIMGDIR=${NANO_OBJ}/../images NANO_WORLDDIR=${NANO_LOG}/_.w NANO_INIT_IMG2=0 NANO_NOPRIV_BUILD=t unset MAKEOBJDIRPREFIX mkdir -p ${NANO_OBJ} NANO_OBJ=$(realpath ${NANO_OBJ}) mkdir -p ${NANO_LOG} NANO_LOG=$(realpath ${NANO_LOG}) mkdir -p ${NANO_WORLDDIR} NANO_WORLDDIR=$(realpath ${NANO_WORLDDIR}) mkdir -p ${NANO_DISKIMGDIR} NANO_DISKIMGDIR=$(realpath ${NANO_DISKIMGDIR}) NANO_FAT_DIR=${NANO_LOG}/_.fat customize_cmd cust_allow_ssh_root add_etc_make_conf ( ) ( touch ${NANO_WORLDDIR}/etc/make.conf ) customize_cmd add_etc_make_conf cust_install_machine_files ( ) ( echo "cd ${NANO_CFG_BASE}/Files" cd ${NANO_CFG_BASE}/Files find . -print | grep -Ev '/(CVS|\.svn|\.hg|\.git)' | cpio -dumpv ${NANO_WORLDDIR} ) customize_cmd cust_install_files customize_cmd cust_install_machine_files # NB: leave c++ enabled so devd can be built CONF_BUILD=" LOCAL_XTOOL_DIRS=usr.bin/mkimg WITHOUT_ACPI=true WITHOUT_ATM=true WITHOUT_AUDIT=true WITHOUT_BLUETOOTH=true WITHOUT_CALENDAR=true WITHOUT_DICT=true WITHOUT_EXAMPLES=true WITHOUT_GAMES=true WITHOUT_GCOV=true WITHOUT_HTML=true WITHOUT_IPFILTER=true WITHOUT_LOCALES=true WITHOUT_LPR=true WITHOUT_MAN=true WITHOUT_NETCAT=true WITHOUT_NIS=true WITHOUT_NLS=true WITHOUT_NS_CACHING=true WITHOUT_PROFILE=true WITHOUT_SENDMAIL=true WITHOUT_SHAREDOCS=true WITHOUT_SYSCONS=true WITHOUT_LIB32=true WITHOUT_TESTS=true WITHOUT_DEBUG_FILES=t WITHOUT_KERNEL_SYMBOLS=t " CONF_INSTALL="$CONF_BUILD INSTALL_NODEBUG=t NOPORTDOCS=t NO_INSTALL_MANPAGES=t " # The following would help... # WITHOUT_TOOLCHAIN=true can't build ports # WITHOUT_INSTALLLIB=true libgcc.a # # from the build PKG_ONLY_MAKE_CONF=" WITHOUT_TOOLCHAIN=true WITHOUT_INSTALLLIB=true " NANO_PACKAGE_ONLY=1 # Creates images for all the formats that use MBR / GPT # split later if the #ifdef soup gets too bad. create_diskimage_gpt ( ) ( pprint 2 "build diskimage gpt ${NANO_NAME}" create_diskimage_mbr $* ) create_diskimage_mbr ( ) ( local fmt [ -z ${NANO_DISKIMAGE_FORMAT} ] || fmt=".${NANO_DISKIMAGE_FORMAT}" pprint 2 "build diskimage ${NANO_NAME}" pprint 3 "log: ${NANO_LOG}/_.di" pprint 3 "image in: ${NANO_DISKIMGDIR}/_.disk.image.${NANO_NAME}${fmt}" ( local extra i sz fmt fmtarg bootmbr bootbsd skiparg set -o xtrace # Tell mtools not to be too picky export MTOOLS_SKIP_CHECK=1 [ -z ${NANO_DISKIMAGE_FORMAT} ] || fmtarg="-f ${NANO_DISKIMAGE_FORMAT}" [ -z ${NANO_DISKIMAGE_FORMAT} ] || fmt=".${NANO_DISKIMAGE_FORMAT}" bootmbr=${NANO_BOOT_MBR:+-b ${NANO_BOOT_MBR}} bootbsd=${NANO_BOOT_BSD:+-b ${NANO_BOOT_BSD}} skiparg=${NANO_MBR_FIRST_SKIP:+-S ${NANO_MBR_FIRST_SKIP}} for i in s1 s2 s3 s4 p1 p2 p3 p4 p5 empty; do rm -fr ${NANO_LOG}/_.${i}* done # Populate the FAT partition, if needed if [ -n "${NANO_SLICE_FAT}" ]; then echo Creating MSDOS partition for kernel newfs_msdos -C ${NANO_SLICE_FAT_SIZE} -F 16 -L ${NANO_NAME} \ ${NANO_LOG}/_.${NANO_SLICE_FAT} if [ -d ${NANO_FAT_DIR} ]; then # Need to copy files from ${NANO_FATDIR} with mtools, or use # makefs -t msdos once that's supported mcopy -i ${NANO_LOG}/_.${NANO_SLICE_FAT} ${NANO_FAT_DIR}/* :: fi fi # Populate the Powerpc boot image, if needed if [ "${NANO_LAYOUT}" = powerpc64-ibm ]; then dd if=${NANO_WORLDDIR}/boot/boot1.elf of=${NANO_LOG}/_.s1 bs=800k count=1 conv=sync fi # Populate the / partition, and place it into a slice with a # bsd label [ -z ${NANO_NOPRIV_BUILD} ] || extra="-F ${NANO_METALOG}" sz=${NANO_SLICE_ROOT_SIZE:+-s ${NANO_SLICE_ROOT_SIZE}} eval "${NANO_MAKEFS_UFS}" ${extra} $sz "${NANO_LOG}/_.${NANO_ROOT}" \ "${NANO_WORLDDIR}" case ${NANO_DISK_SCHEME} in mbr) mkimg -s bsd ${bootbsd} -p freebsd-ufs:=${NANO_LOG}/_.${NANO_ROOT} \ -o ${NANO_LOG}/_.${NANO_SLICE_ROOT} eval $NANO_SLICE_CFG=freebsd eval $NANO_SLICE_ROOT=freebsd ;; gpt) eval $NANO_SLICE_CFG=freebsd-ufs eval $NANO_SLICE_ROOT=freebsd-ufs ;; esac # Populate the /cfg partition, empty if none given if [ -z "${NANO_CFGDIR}" ]; then echo "Faking cfg dir, it's empty" NANO_CFGDIR=${NANO_LOG}/_.empty mkdir -p ${NANO_CFGDIR} fi # XXX -F cfg-mtree eval "${NANO_MAKEFS_UFS}" -s ${NANO_SLICE_CFG_SIZE} \ "${NANO_LOG}/_.${NANO_SLICE_CFG}" "${NANO_CFGDIR}" # data slice not supported since we need the part for FAT for # booting # Now shuffle all the slices together into the proper layout if [ -n "$NANO_SLICE_FAT" ]; then eval $NANO_SLICE_FAT=fat16b fi out=${NANO_DISKIMGDIR}/_.disk.image.${NANO_NAME}${fmt} # below depends on https://reviews.freebsd.org/D4403 not yet in the tree # but there's problems: it marks all partitions as active, so you have to # boot off partition 3 or 2 by hand if you're playing around with this WIP case ${NANO_LAYOUT} in std-embedded) mkimg -a 3 ${skiparg} ${fmtarg} ${bootmbr} -s mbr -p ${s1}:=${NANO_LOG}/_.s1 \ -p ${s2}:=${NANO_LOG}/_.s2 \ -p ${s3}:=${NANO_LOG}/_.s3 \ -o ${out} ;; std-x86) # s3 is cfg, s1 is /, s2 is other / (s2 is created in first boot script) mkimg -a 1 ${fmtarg} ${bootmbr} -s mbr -p ${s1}:=${NANO_LOG}/_.s1 \ -p- \ -p ${s3}:=${NANO_LOG}/_.s3 \ -o ${out} ;; std-uefi) # s1 is boot, s2 is cfg, s3 is /, not sure how to make that # boot (marked as active) with mkimg yet mkimg -a 2 ${fmtarg} ${bootmbr} -s mbr \ -p efi:=${NANO_WORLDDIR}/boot/efiboot.img \ -p ${s2}:=${NANO_LOG}/_.s2 \ -p ${s3}:=${NANO_LOG}/_.s3 \ -o ${out} ;; std-uefi-bios) # p1 is boot for uefi, p2 is boot for gpt, p3 is cfg, p4 is / # and p5 is alt-root (after resize) mkimg -a 2 ${fmtarg} ${bootmbr} -s gpt \ -p efi:=${NANO_WORLDDIR}/boot/efiboot.img \ -p freebsd-boot:=${NAANO_WORLDDIR}/boot/gptboot \ -p ${p3}:=${NANO_LOG}/_.p3 \ -p ${p4}:=${NANO_LOG}/_.p4 \ -o ${out} ;; powerpc64-ibm) # A lie to make the boot loader work, it boots the first BSD partition # it finds, regardless of the active flag. s2=fat16b # boot image is on a special partition, ala std-embedded, but that # partition isn't FAT with special files, but a copy of the boot # loader itself. mkimg -a 1 ${fmtarg} -s mbr -p prepboot:=${NANO_LOG}/_.s1 \ -p ${s2}:=${NANO_LOG}/_.s2 \ -p ${s3}:=${NANO_LOG}/_.s3a \ -o ${out} ;; esac rm -f ${out}.xz xz -9 --keep ${out} ) > ${NANO_LOG}/_.di 2>&1 ) die( ) { echo "$*" exit 1 } # Automatically include the packaging port here so it is always first so it # builds the port and adds the package so we can add other packages. #XXX Doesn't work for cross build, so punting until I can integreate qemu-static #XXX or poudriere, both of which require priv'd execution. Or qemu-system, #XXX which is super, super slow. #add_port ports-mgmt/pkg #add_port security/sudo #add_port ftp/curl rp=$(realpath ${NANO_OBJ}/) __a=`mount | grep ${rp} | awk '{print length($3), $3;}' | sort -rn | awk '{$1=""; print;}'` if [ -n "$__a" ]; then echo "unmounting $__a" umount $__a fi if [ "$DEBUG" = 1 ]; then DEBUG_BUILD=" DEBUG_FLAGS= -g " else DEBUG_INSTALL=" INSTALL_NODEBUG= t " fi CONF_INSTALL="$CONF_BUILD ${DEBUG_BUILD} " CONF_INSTALL="$CONF_INSTALL ${DEBUG_INSTALL} " if [ "${NANO_PACKAGE_ONLY}" -eq 1 ]; then CONF_INSTALL="${CONF_INSTALL} ${PKG_ONLY_MAKE_CONF} " echo "Automatically building a thin image with packages" else echo "Automatically building a * * F A T * * image so we can build ports" fi VARS="MASTER_SITE_BACKUP MASTER_SITE_OVERRIDE PACKAGEROOT PACKAGESITE" for var in $VARS; do val=$(eval echo "\$$var") if [ -n "$val" ]; then CONF_INSTALL="${CONF_INSTALL} $var=$val" fi done typical_embedded ( ) ( # Need to create rc.conf before we copy over /etc to /conf/base/etc # so now's a good time. local rc=${NANO_WORLDDIR}/etc/rc.conf echo "hostname=nanobsd-${NANO_NAME}" > $rc echo "growfs_enable=YES" >> $rc echo "growfs_type=nanobsd-pingpong" >> $rc echo "ntpdate_enable=YES" >> $rc echo "ifconfig_DEFAULT=DHCP" >> $rc echo "ntpdate_hosts='0.freebsd.pool.ntp.org 1.freebsd.pool.ntp.org'" >> $rc # Make sure that firstboot scripts run so growfs works. # Note: still some issues remvoing this XXX touch ${NANO_WORLDDIR}/firstboot ) customize_cmd typical_embedded fix_pkg ( ) ( chdir ${NANO_WORLDDIR} mkdir -p pkg mkdir -p pkg/db mkdir -p pkg/cache mkdir -p pkg/tmp # Needed for pkg bootstrap mkdir -p usr/local/etc # Will get moved to local/etc ( echo 'PKG_DBDIR = "/pkg/db"' echo 'PKG_CACHEDIR = "/pkg/cache"' echo 'DEFAULT_ALWAYS_YES = "yes"' echo 'ASSUME_ALWAYS_YES = "yes"' ) >> usr/local/etc/pkg.conf [ -z ${NANO_NOPRIV_BUILD} ] || ( echo "./pkg type=dir uname=root gname=wheel mode=0755" echo "./pkg/cache type=dir uname=root gname=wheel mode=0755" echo "./pkg/db type=dir uname=root gname=wheel mode=0755" echo "./pkg/tmp type=dir uname=root gname=wheel mode=0755" ) >> ${NANO_METALOG} ) customize_cmd fix_pkg save_build ( ) ( VERSION_FILE=${NANO_WORLDDIR}/etc/version if [ "${SVNREVISION}" = "${REVISION}" ]; then echo "${NANO_NAME}" > "${VERSION_FILE}" else echo "${NANO_NAME} (${SVNREVISION})" > "${VERSION_FILE}" fi ) customize_cmd save_build shrink_md_fbsize ( ) ( # We have a lot of little files on our memory disks. Let's decrease # the block and frag size to fit more little files on them (this # halves our space requirement by ~50% on /etc and /var on 8.x -- # and gives us more back on 9.x as the default block and frag size # are 4 times larger). sed -i '' -e 's,-S -i 4096,-S -i 4096 -b 4096 -f 512,' \ ${NANO_WORLDDIR}/etc/rc.initdiskless ) customize_cmd shrink_md_fbsize customize_cmd cust_comconsole dos_boot_part ( ) ( local d=/usr/local/share/u-boot/${NANO_BOOT_PKG} local f=${NANO_FAT_DIR} # For now, just copy all the files. However, for iMX6 and Allwinner, # we'll need to put a special boot block at a fixed location # on the disk as well. rm -rf $f mkdir $f chdir $f cp ${d}/* . # Also copy ubldr. u-boot will load it and it will load the kernel # from the ufs partition cp ${NANO_WORLDDIR}/boot/ubldr . cp ${NANO_WORLDDIR}/boot/ubldr.bin . # We have to touch the saveenv file touch uEnv.txt # Now we need to copy over dtb files from the build. cp ${NANO_WORLDDIR}/boot/dtb/*.dtb . ) if [ -n "$NANO_BOOT_PKG" ]; then d=/usr/local/share/u-boot/${NANO_BOOT_PKG} if [ ! -d ${d} ]; then echo ${NANO_BOOT_PKG} not installed. Sadly, it must be. exit 1 fi if [ ! -x /usr/local/bin/mcopy ]; then echo mtools not installed. Sadly, we gotta have it. exit 1 fi customize_cmd dos_boot_part fi product_custom ( ) ( # not quite ready to tweak these in nopriv build if [ -z ${NANO_NOPRIV_BUILD} ]; then # Last second tweaks -- generally not needed chown -R root:wheel ${NANO_WORLDDIR}/root chmod 0755 ${NANO_WORLDDIR}/root/* chmod 0755 ${NANO_WORLDDIR}/* chown -R root:wheel ${NANO_WORLDDIR}/etc chown -R root:wheel ${NANO_WORLDDIR}/boot chown root:wheel ${NANO_WORLDDIR}/ chown root:wheel ${NANO_WORLDDIR}/usr fi ) late_customize_cmd product_custom # # Convenience routines to bring up many settings for standard environments # # # For each architecture, we have a standard set of settings to the extent # it makes sense. For architectures that don't have a standard environment # cfg files need to either define a lot of settings, provide their own disk # imaging, or set which of the variants we support. No subshells, since we # set global variables # std_aarch64 ( ) { } std_amd64 ( ) { std_i386 } std_arm ( ) { } std_armv6 ( ) { } std_armv7 ( ) { } std_i386 ( ) { # Default values, if not overridden in .cfg file : ${NANO_KERNEL:=GENERIC} : ${NANO_DRIVE:=ada0} : ${NANO_LAYOUT:=std-x86} : ${NANO_BOOT_MBR:=${NANO_WORLDDIR}/boot/boot0sio} : ${NANO_BOOT_BSD:=${NANO_WORLDDIR}/boot/boot} } std_mips ( ) { NANO_ENDIAN=big } std_mipsel ( ) { } std_mips64 ( ) { NANO_ENDIAN=big } std_mips64el ( ) { } std_powerpc ( ) { NANO_ENDIAN=big } std_powerpc64 ( ) { NANO_LAYOUT=powerpc64-ibm NANO_ENDIAN=big } std_sparc64 ( ) { NANO_ENDIAN=big } # # QEMU settings for the standard environments # qemu_env ( ) { NANO_DISKIMAGE_FORMAT=qcow2 } # other standard environments will go here eval std_${NANO_ARCH} # Slice 1: FAT for ROM loading bootstrap # Slice 2: Config partition # Slice 3: FreeBSD partition (sized exactly) # Slice 4: FreeBSD partition (empty) # on first boot, we resize slice 3 & 4 to be 1/2 of what's # left over on the SD card after slice 1 and 2 are taken # off the top. We also resize the 'a' partion on first boot # to the size of the partition for the ping/pong upgrade. # This feature needs support in the rc.d bootup script. # # Ideally, we'd not put BSD labels on the MBR disks. # However, we can't boot off raw MBR disks. First, # boot2 defaults to 'a' partition, and freaks out # unless you tell it to use 'c'. But even if we # hack that, then /boot/loader wants to load off # of 'c' partition. If you fix that, then we'll # try to mount root, but sanity checks prevent # slices from working. # : ${NANO_ENDIAN:=little} # make -V something to figure it out? : ${NANO_LAYOUT:=std-embedded} : ${NANO_MAKEFS_UFS:=makefs -t ffs -B ${NANO_ENDIAN}} : ${NANO_DISK_SCHEME:=mbr} # No others really supported ATM (well, gpt) case ${NANO_LAYOUT} in std-embedded) NANO_SLICE_FAT=s1 NANO_SLICE_CFG=s2 NANO_SLICE_ROOT=s3 NANO_SLICE_ALTROOT=s4 NANO_ROOT=${NANO_SLICE_ROOT}a NANO_ALTROOT=${NANO_SLICE_ALTROOT}a ;; std-x86) NANO_SLICE_CFG=s3 NANO_SLICE_ROOT=s1 NANO_SLICE_ALTROOT=s2 NANO_ROOT=${NANO_SLICE_ROOT}a NANO_ALTROOT=${NANO_SLICE_ALTROOT}a ;; powerpc64-ibm) NANO_SLICE_PPCBOOT=s1 NANO_SLICE_CFG=s2 NANO_SLICE_ROOT=s3 NANO_SLICE_ALTROOT=s4 NANO_ROOT=${NANO_SLICE_ROOT}a NANO_ALTROOT=${NANO_SLICE_ALTROOT}a ;; powerpc64-apple) echo Not yet exit 1 ;; std-uefi) NANO_SLICE_UEFI=s1 NANO_SLICE_CFG=s2 NANO_SLICE_ROOT=s3 NANO_SLICE_ALTROOT=s4 NANO_ROOT=${NANO_SLICE_ROOT} NANO_ALTROOT=${NANO_SLICE_ALTROOT} ;; std-uefi-bios) NANO_DISK_SCHEME=gpt NANO_SLICE_UEFI=p1 NANO_SLICE_BOOT=p2 NANO_SLICE_CFG=p3 NANO_SLICE_ROOT=p4 NANO_SLICE_ALTROOT=p5 NANO_ROOT=${NANO_SLICE_ROOT} NANO_ALTROOT=${NANO_SLICE_ALTROOT} ;; *) echo Unknown Layout ${NANO_LAYOUT} exit 1 ;; esac NANO_SLICE_DATA= # Not included # Each major disk scheme has its own routine. Generally # this is for mbr, gpt, etc. These are generally are widely # shared, but some specialized formats won't be shared. create_diskimage ( ) ( eval create_diskimage_${NANO_DISK_SCHEME} ) # Set the path to the same path we use for buldworld to use latest mkimg NANO_TARGET=$(cd ${NANO_SRC}; ${NANO_MAKE} TARGET_ARCH=${NANO_ARCH} -V _TARGET) NANO_TMPPATH=$(cd ${NANO_SRC}; ${NANO_MAKE} MK_AUTO_OBJ=no TARGET=${NANO_TARGET} TARGET_ARCH=${NANO_ARCH} -f Makefile.inc1 buildenv -V TMPPATH) export PATH="${NANO_TMPPATH}:${PATH}" Index: head/tools/tools/nanobsd/embedded/i386.cfg =================================================================== --- head/tools/tools/nanobsd/embedded/i386.cfg (revision 355393) +++ head/tools/tools/nanobsd/embedded/i386.cfg (revision 355394) @@ -1,34 +1,34 @@ # $FreeBSD$ #- -# Copyright (c) 2015 M. Warner Losh. +# Copyright (c) 2015 M. Warner Losh # Copyright (c) 2010-2011 iXsystems, Inc. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL iXsystems, Inc. OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # NANO_ARCH=i386 NANO_KERNEL=GENERIC NANO_DRIVE=ada0 NANO_NAME=i386 . common # Pull in common definitions, keep last Index: head/tools/tools/nanobsd/embedded/pandaboard.cfg =================================================================== --- head/tools/tools/nanobsd/embedded/pandaboard.cfg (revision 355393) +++ head/tools/tools/nanobsd/embedded/pandaboard.cfg (revision 355394) @@ -1,36 +1,36 @@ # $FreeBSD$ #- -# Copyright (c) 2016 M. Warner Losh. +# Copyright (c) 2016 M. Warner Losh # Copyright (c) 2010-2011 iXsystems, Inc. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL iXsystems, Inc. OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # NANO_ARCH=armv7 NANO_KERNEL=PANDABOARD NANO_DRIVE=mmcsd0 NANO_NAME=pandaboard NANO_BOOT_PKG=u-boot-pandaboard NANO_CPUTYPE=cortex-a9 . common # Pull in common definitions, keep last Index: head/tools/tools/nanobsd/embedded/qemu-amd64-uefi-bios.cfg =================================================================== --- head/tools/tools/nanobsd/embedded/qemu-amd64-uefi-bios.cfg (revision 355393) +++ head/tools/tools/nanobsd/embedded/qemu-amd64-uefi-bios.cfg (revision 355394) @@ -1,43 +1,43 @@ # $FreeBSD$ #- -# Copyright (c) 2015 M. Warner Losh. +# Copyright (c) 2015 M. Warner Losh # Copyright (c) 2010-2011 iXsystems, Inc. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL iXsystems, Inc. OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # NANO_ARCH=amd64 NANO_NAME=qemu-amd64-uefi-bios NANO_LAYOUT=std-uefi-bios . common # Pull in common definitions qemu_env # # Run with # qemu-system-x86_64 -m 512 -serial stdio -bios OVMF.fd \ # -hda _.disk.image.qemu-amd64-uefi.qcow2 # OVMF.fd is from # http://sourceforge.net/projects/edk2/files/OVMF/OVMF-X64-r15214.zip # Index: head/tools/tools/nanobsd/embedded/qemu-amd64-uefi.cfg =================================================================== --- head/tools/tools/nanobsd/embedded/qemu-amd64-uefi.cfg (revision 355393) +++ head/tools/tools/nanobsd/embedded/qemu-amd64-uefi.cfg (revision 355394) @@ -1,43 +1,43 @@ # $FreeBSD$ #- -# Copyright (c) 2015 M. Warner Losh. +# Copyright (c) 2015 M. Warner Losh # Copyright (c) 2010-2011 iXsystems, Inc. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL iXsystems, Inc. OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # NANO_ARCH=amd64 NANO_NAME=qemu-amd64-uefi NANO_LAYOUT=std-uefi . common # Pull in common definitions qemu_env # # Run with # qemu-system-x86_64 -m 512 -serial stdio -bios OVMF.fd \ # -hda _.disk.image.qemu-amd64-uefi.qcow2 # OVMF.fd is from # http://sourceforge.net/projects/edk2/files/OVMF/OVMF-X64-r15214.zip # Index: head/tools/tools/nanobsd/embedded/qemu-amd64.cfg =================================================================== --- head/tools/tools/nanobsd/embedded/qemu-amd64.cfg (revision 355393) +++ head/tools/tools/nanobsd/embedded/qemu-amd64.cfg (revision 355394) @@ -1,39 +1,39 @@ # $FreeBSD$ #- -# Copyright (c) 2015 M. Warner Losh. +# Copyright (c) 2015 M. Warner Losh # Copyright (c) 2010-2011 iXsystems, Inc. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL iXsystems, Inc. OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # NANO_ARCH=amd64 NANO_NAME=qemu-amd64 . common # Pull in common definitions qemu_env # Run with: # qemu-system-x86_64 -m 512 -hdd $file -serial telnet::4444,server -nographic # To get some breathing room on the image: # qemu-img resize $file +2G Index: head/tools/tools/nanobsd/embedded/qemu-armv7.cfg =================================================================== --- head/tools/tools/nanobsd/embedded/qemu-armv7.cfg (revision 355393) +++ head/tools/tools/nanobsd/embedded/qemu-armv7.cfg (revision 355394) @@ -1,48 +1,48 @@ # $FreeBSD$ #- # Copyright (c) 2016 Andrew Turner. All Rights Reserved. -# Copyright (c) 2015 M. Warner Losh. +# Copyright (c) 2015 M. Warner Losh # Copyright (c) 2010-2011 iXsystems, Inc. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL iXsystems, Inc. OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # NANO_ARCH=armv7 NANO_DRIVE=vtbd0 NANO_KERNEL=GENERIC NANO_NAME=qemu-armv7 NANO_LAYOUT=std-uefi-bios NANO_CPUTYPE=cortexa . common # Pull in common definitions qemu_env # # Run with # qemu-system-arm -m 512 -M virt -serial stdio -bios QEMU_EFI.fd \ # -drive if=none,file=_.disk.image.qemu-armv7.qcow2,id=hd0 \ # -device virtio-blk-device,drive=hd0 # QEMU_EFI.fd is from # http://releases.linaro.org/components/kernel/uefi-linaro/15.12/release/qemu/ # Index: head/tools/tools/nanobsd/embedded/qemu-i386.cfg =================================================================== --- head/tools/tools/nanobsd/embedded/qemu-i386.cfg (revision 355393) +++ head/tools/tools/nanobsd/embedded/qemu-i386.cfg (revision 355394) @@ -1,34 +1,34 @@ # $FreeBSD$ #- -# Copyright (c) 2015 M. Warner Losh. +# Copyright (c) 2015 M. Warner Losh # Copyright (c) 2010-2011 iXsystems, Inc. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL iXsystems, Inc. OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # NANO_ARCH=i386 NANO_NAME=qemu-i386 . common # Pull in common definitions qemu_env Index: head/tools/tools/nanobsd/embedded/qemu-mips.cfg =================================================================== --- head/tools/tools/nanobsd/embedded/qemu-mips.cfg (revision 355393) +++ head/tools/tools/nanobsd/embedded/qemu-mips.cfg (revision 355394) @@ -1,36 +1,36 @@ # $FreeBSD$ #- -# Copyright (c) 2015 M. Warner Losh. +# Copyright (c) 2015 M. Warner Losh # Copyright (c) 2010-2011 iXsystems, Inc. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL iXsystems, Inc. OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # NANO_ARCH=mips NANO_KERNEL=MALTA NANO_DRIVE=ada0 NANO_NAME=qemu-mips . common # Pull in common definitions qemu_env Index: head/tools/tools/nanobsd/embedded/qemu-mips64.cfg =================================================================== --- head/tools/tools/nanobsd/embedded/qemu-mips64.cfg (revision 355393) +++ head/tools/tools/nanobsd/embedded/qemu-mips64.cfg (revision 355394) @@ -1,36 +1,36 @@ # $FreeBSD$ #- -# Copyright (c) 2015 M. Warner Losh. +# Copyright (c) 2015 M. Warner Losh # Copyright (c) 2010-2011 iXsystems, Inc. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL iXsystems, Inc. OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # NANO_ARCH=mips NANO_KERNEL=MALTA64 NANO_DRIVE=ada0 NANO_NAME=qemu-mips64 . common # Pull in common definitions qemu_env Index: head/tools/tools/nanobsd/embedded/qemu-powerpc.cfg =================================================================== --- head/tools/tools/nanobsd/embedded/qemu-powerpc.cfg (revision 355393) +++ head/tools/tools/nanobsd/embedded/qemu-powerpc.cfg (revision 355394) @@ -1,37 +1,37 @@ # $FreeBSD$ #- -# Copyright (c) 2015 M. Warner Losh. +# Copyright (c) 2015 M. Warner Losh # Copyright (c) 2010-2011 iXsystems, Inc. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL iXsystems, Inc. OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # Open question: do we have one for MAC G4 and one for Book-E? NANO_ARCH=powerpc NANO_KERNEL=GENERIC NANO_DRIVE=ada0 NANO_NAME=qemu-powerpc . common # Pull in common definitions qemu_env Index: head/tools/tools/nanobsd/embedded/qemu-powerpc64.cfg =================================================================== --- head/tools/tools/nanobsd/embedded/qemu-powerpc64.cfg (revision 355393) +++ head/tools/tools/nanobsd/embedded/qemu-powerpc64.cfg (revision 355394) @@ -1,36 +1,36 @@ # $FreeBSD$ #- -# Copyright (c) 2015 M. Warner Losh. +# Copyright (c) 2015 M. Warner Losh # Copyright (c) 2010-2011 iXsystems, Inc. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL iXsystems, Inc. OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # NANO_ARCH=powerpc64 NANO_KERNEL=GENERIC64 NANO_DRIVE=ada0 NANO_NAME=qemu-powerpc64 . common # Pull in common definitions qemu_env Index: head/tools/tools/nanobsd/embedded/qemu-sparc64.cfg =================================================================== --- head/tools/tools/nanobsd/embedded/qemu-sparc64.cfg (revision 355393) +++ head/tools/tools/nanobsd/embedded/qemu-sparc64.cfg (revision 355394) @@ -1,36 +1,36 @@ # $FreeBSD$ #- -# Copyright (c) 2015 M. Warner Losh. +# Copyright (c) 2015 M. Warner Losh # Copyright (c) 2010-2011 iXsystems, Inc. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL iXsystems, Inc. OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # NANO_ARCH=sparc64 NANO_KERNEL=GENERIC NANO_DRIVE=ada0 NANO_NAME=qemu-sparc64 . common # Pull in common definitions qemu_env Index: head/tools/tools/nanobsd/embedded/rpi.cfg =================================================================== --- head/tools/tools/nanobsd/embedded/rpi.cfg (revision 355393) +++ head/tools/tools/nanobsd/embedded/rpi.cfg (revision 355394) @@ -1,36 +1,36 @@ # $FreeBSD$ #- -# Copyright (c) 2015 M. Warner Losh. +# Copyright (c) 2015 M. Warner Losh # Copyright (c) 2010-2011 iXsystems, Inc. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL iXsystems, Inc. OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # NANO_ARCH=armv6 NANO_KERNEL=RPI-B NANO_DRIVE=mmcsd0 NANO_NAME=rpi-b NANO_BOOT_PKG=u-boot-rpi NANO_CPUTYPE=arm1176jzf-s . common # Pull in common definitions, keep last Index: head/tools/tools/nanobsd/embedded/rpi2.cfg =================================================================== --- head/tools/tools/nanobsd/embedded/rpi2.cfg (revision 355393) +++ head/tools/tools/nanobsd/embedded/rpi2.cfg (revision 355394) @@ -1,35 +1,35 @@ # $FreeBSD$ #- -# Copyright (c) 2015 M. Warner Losh. +# Copyright (c) 2015 M. Warner Losh # Copyright (c) 2010-2011 iXsystems, Inc. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL iXsystems, Inc. OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # NANO_ARCH=armv7 NANO_KERNEL=RPI2 NANO_DRIVE=mmcsd0 NANO_NAME=rpi2 NANO_BOOT_PKG=u-boot-rpi2 . common # Pull in common definitions, keep last Index: head/tools/tools/nanobsd/embedded/rpi3.cfg =================================================================== --- head/tools/tools/nanobsd/embedded/rpi3.cfg (revision 355393) +++ head/tools/tools/nanobsd/embedded/rpi3.cfg (revision 355394) @@ -1,35 +1,35 @@ # $FreeBSD$ #- -# Copyright (c) 2015 M. Warner Losh. +# Copyright (c) 2015 M. Warner Losh # Copyright (c) 2010-2011 iXsystems, Inc. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL iXsystems, Inc. OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # NANO_ARCH=aarch64 NANO_KERNEL=GENERIC-UP NANO_DRIVE=mmcsd0 NANO_NAME=rpi3 NANO_BOOT_PKG=u-boot-rpi3 . common # Pull in common definitions, keep last Index: head/tools/tools/nanobsd/legacy.sh =================================================================== --- head/tools/tools/nanobsd/legacy.sh (revision 355393) +++ head/tools/tools/nanobsd/legacy.sh (revision 355394) @@ -1,203 +1,203 @@ #!/bin/sh # -# Copyright (c) 2005 Poul-Henning Kamp. -# Copyright (c) 2016 M. Warner Losh. -# All rights reserved. +# Copyright (c) 2005 Poul-Henning Kamp All rights reserved. +# Copyright (c) 2016 M. Warner Losh +# # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # $FreeBSD$ # # Media geometry, only relevant if bios doesn't understand LBA. [ -n "$NANO_SECTS" ] || NANO_SECTS=63 [ -n "$NANO_HEADS" ] || NANO_HEADS=16 # Functions and variable definitions used by the legacy nanobsd # image building system. create_diskimage ( ) ( pprint 2 "build diskimage" pprint 3 "log: ${NANO_LOG}/_.di" ( echo $NANO_MEDIASIZE $NANO_IMAGES \ $NANO_SECTS $NANO_HEADS \ $NANO_CODESIZE $NANO_CONFSIZE $NANO_DATASIZE | awk ' { printf "# %s\n", $0 # size of cylinder in sectors cs = $3 * $4 # number of full cylinders on media cyl = int ($1 / cs) # output fdisk geometry spec, truncate cyls to 1023 if (cyl <= 1023) print "g c" cyl " h" $4 " s" $3 else print "g c" 1023 " h" $4 " s" $3 if ($7 > 0) { # size of data partition in full cylinders dsl = int (($7 + cs - 1) / cs) } else { dsl = 0; } # size of config partition in full cylinders csl = int (($6 + cs - 1) / cs) if ($5 == 0) { # size of image partition(s) in full cylinders isl = int ((cyl - dsl - csl) / $2) } else { isl = int (($5 + cs - 1) / cs) } # First image partition start at second track print "p 1 165 " $3, isl * cs - $3 c = isl * cs; # Second image partition (if any) also starts offset one # track to keep them identical. if ($2 > 1) { print "p 2 165 " $3 + c, isl * cs - $3 c += isl * cs; } # Config partition starts at cylinder boundary. print "p 3 165 " c, csl * cs c += csl * cs # Data partition (if any) starts at cylinder boundary. if ($7 > 0) { print "p 4 165 " c, dsl * cs } else if ($7 < 0 && $1 > c) { print "p 4 165 " c, $1 - c } else if ($1 < c) { print "Disk space overcommitted by", \ c - $1, "sectors" > "/dev/stderr" exit 2 } # Force slice 1 to be marked active. This is necessary # for booting the image from a USB device to work. print "a 1" } ' > ${NANO_LOG}/_.fdisk IMG=${NANO_DISKIMGDIR}/${NANO_IMGNAME} MNT=${NANO_OBJ}/_.mnt mkdir -p ${MNT} if [ "${NANO_MD_BACKING}" = "swap" ] ; then MD=`mdconfig -a -t swap -s ${NANO_MEDIASIZE} -x ${NANO_SECTS} \ -y ${NANO_HEADS}` else echo "Creating md backing file..." rm -f ${IMG} dd if=/dev/zero of=${IMG} seek=${NANO_MEDIASIZE} count=0 MD=`mdconfig -a -t vnode -f ${IMG} -x ${NANO_SECTS} \ -y ${NANO_HEADS}` fi trap "echo 'Running exit trap code' ; df -i ${MNT} ; nano_umount ${MNT} || true ; mdconfig -d -u $MD" 1 2 15 EXIT fdisk -i -f ${NANO_LOG}/_.fdisk ${MD} fdisk ${MD} # XXX: params # XXX: pick up cached boot* files, they may not be in image anymore. if [ -f ${NANO_WORLDDIR}/${NANO_BOOTLOADER} ]; then boot0cfg -B -b ${NANO_WORLDDIR}/${NANO_BOOTLOADER} ${NANO_BOOT0CFG} ${MD} fi if [ -f ${NANO_WORLDDIR}/boot/boot ]; then bsdlabel -w -B -b ${NANO_WORLDDIR}/boot/boot ${MD}${NANO_SLICE_ROOT} else bsdlabel -w ${MD}${NANO_SLICE_ROOT} fi bsdlabel ${MD}${NANO_SLICE_ROOT} # Create first image populate_slice /dev/${MD}${NANO_ROOT} ${NANO_WORLDDIR} ${MNT} "${NANO_ROOT}" mount /dev/${MD}${NANO_ROOT} ${MNT} echo "Generating mtree..." ( cd "${MNT}" && mtree -c ) > ${NANO_LOG}/_.mtree ( cd "${MNT}" && du -k ) > ${NANO_LOG}/_.du nano_umount "${MNT}" if [ $NANO_IMAGES -gt 1 -a $NANO_INIT_IMG2 -gt 0 ] ; then # Duplicate to second image (if present) echo "Duplicating to second image..." dd conv=sparse if=/dev/${MD}${NANO_SLICE_ROOT} of=/dev/${MD}${NANO_SLICE_ALTROOT} bs=64k mount /dev/${MD}${NANO_ALTROOT} ${MNT} for f in ${MNT}/etc/fstab ${MNT}/conf/base/etc/fstab do sed -i "" "s=${NANO_DRIVE}${NANO_SLICE_ROOT}=${NANO_DRIVE}${NANO_SLICE_ALTROOT}=g" $f done nano_umount ${MNT} # Override the label from the first partition so we # don't confuse glabel with duplicates. if [ -n "${NANO_LABEL}" ]; then tunefs -L ${NANO_LABEL}"${NANO_ALTROOT}" /dev/${MD}${NANO_ALTROOT} fi fi # Create Config slice populate_cfg_slice /dev/${MD}${NANO_SLICE_CFG} "${NANO_CFGDIR}" ${MNT} "${NANO_SLICE_CFG}" # Create Data slice, if any. if [ -n "$NANO_SLICE_DATA" -a "$NANO_SLICE_CFG" = "$NANO_SLICE_DATA" -a \ "$NANO_DATASIZE" -ne 0 ]; then pprint 2 "NANO_SLICE_DATA is the same as NANO_SLICE_CFG, fix." exit 2 fi if [ $NANO_DATASIZE -ne 0 -a -n "$NANO_SLICE_DATA" ] ; then populate_data_slice /dev/${MD}${NANO_SLICE_DATA} "${NANO_DATADIR}" ${MNT} "${NANO_SLICE_DATA}" fi if [ "${NANO_MD_BACKING}" = "swap" ] ; then if [ ${NANO_IMAGE_MBRONLY} ]; then echo "Writing out _.disk.mbr..." dd if=/dev/${MD} of=${NANO_DISKIMGDIR}/_.disk.mbr bs=512 count=1 else echo "Writing out ${NANO_IMGNAME}..." dd if=/dev/${MD} of=${IMG} bs=64k fi echo "Writing out ${NANO_IMGNAME}..." dd conv=sparse if=/dev/${MD} of=${IMG} bs=64k fi if ${do_copyout_partition} ; then echo "Writing out ${NANO_IMG1NAME}..." dd conv=sparse if=/dev/${MD}${NANO_SLICE_ROOT} \ of=${NANO_DISKIMGDIR}/${NANO_IMG1NAME} bs=64k fi mdconfig -d -u $MD trap - 1 2 15 EXIT ) > ${NANO_LOG}/_.di 2>&1 ) Index: head/tools/tools/nanobsd/mtree-dedup.awk =================================================================== --- head/tools/tools/nanobsd/mtree-dedup.awk (revision 355393) +++ head/tools/tools/nanobsd/mtree-dedup.awk (revision 355394) @@ -1,201 +1,201 @@ #!/usr/bin/awk -f # -# Copyright (c) 2015 M. Warner Losh. +# Copyright (c) 2015 M. Warner Losh # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # $FreeBSD$ # # # Takes a meta-log created by installworld and friends, plus # additions from NanoBSD to augment its build to communicate when # files move around after installworld / installkernel phase of # NanoBSD. # # All mtree lines from the metafile have a path, followed by # a number of keywords. # # This script recognizes the following new keywords # # unlink[=x] remove the path from the output. # copy_from=x create new entry for path copied from # the keywords from x. # move_from=x create new entry for path copied from # the keywords from x. Remove path from # the output. # # In addition, when path matches a previous entry, the # new entry and previous entry are merged. # # Special note: when uid and uname are both present, # uid is ignored. Ditto gid/gname. # # Also, the paths above have to match exactly, so X # should start with "./". # function die(str) { print str > "/dev/stderr"; exit 1; } function kv(str) { if (split(str, xxx, "=") == 2) { kv_key = xxx[1]; kv_value = xxx[2]; } else { kv_key = str; kv_value = nv; } } # Output the mtree for path based on the kvs. function mtree_from_kvs(path, kvs) { lv = path " "; for (k in kvs) { if (kvs[k] == nv) lv = lv k " "; else lv = lv k "=" kvs[k] " "; } return lv; } # Parse the mtree line into path + KVs. Use a sentinal value # for a bare keyword, which is extremely unlikely to be used # for real. function line2kv(kvs, str) { delete kvs; n = split(str, yyy, " "); for (i = 2; i <= n; i++) { s = yyy[i]; if (split(s, xxx, "=") == 2) kvs[xxx[1]] = xxx[2]; else kvs[s] = nv; } } # old += new function merge_kvs(old, new) { for (k in new) { # uname / uid -- last one wins. if (k == "uid" && "uname" in old) delete old["uname"] if (k == "uname" && "uid" in old) delete old["uid"]; # gname / gid -- last one wins. if (k == "gid" && "gname" in old) delete old["gname"] if (k == "gname" && "gid" in old) delete old["gid"]; # Otherwise newest value wins old[k] = new[k]; } } # Process the line we've read in, per the comments below function process_line(path, new) { # Clear kvs line2kv(new_kvs, new); if ("unlink" in new_kvs) { # A file removed # Sanity check to see if tree[path] exists? # Makes sure when foo/bar/baz exists and foo/bar # unlinked, baz is gone (for all baz). if (path !~ "^\./") die("bad path in : " new); delete tree[path]; # unlink return; # } else if (new_kvs["append_from"]) { # not implemented } else if ("copy_from" in new_kvs) { # A file copied from another location, preserve its # attribute for new file. # Also merge any new attributes from this line. from = new_kvs["copy_from"]; if (from !~ "^\./") die("bad path in : " new); delete new_kvs["copy_from"]; line2kv(old_kvs, tree[from]); # old_kvs = kv's in entry merge_kvs(old_kvs, new_kvs); # old_kvs += new_kvs tree[path] = mtree_from_kvs(path, old_kvs); } else if ("move_from" in new_kvs) { # A file moved from another location, preserve its # attribute for new file, and scrag old location # Also merge any new attributes from this line. from = new_kvs["move_from"]; if (from !~ "^\./") die("bad path in : " new); delete new_kvs["move_from"]; line2kv(old_kvs, tree[from]); # old_kvs = kv's in entry merge_kvs(old_kvs, new_kvs); # old_kvs += new_kvs tree[path] = mtree_from_kvs(path, old_kvs); delete tree[from]; # unlink } else if (tree[path]) { # Update existing entry with new line line2kv(old_kvs, tree[path]); # old_kvs = kv's in entry merge_kvs(old_kvs, new_kvs); # old_kvs += new_kvs tree[path] = mtree_from_kvs(path, old_kvs); } else { # Add entry plus defaults delete old_kvs; merge_kvs(old_kvs, defaults); merge_kvs(old_kvs, new_kvs); tree[path] = mtree_from_kvs(path, old_kvs); } } BEGIN { nv = "___NO__VALUE___"; while ((getline < "/dev/stdin") > 0) { if ($1 ~ "^#") continue; if ($1 == "/set") { for (i = 2; i <= NF; i++) { kv($i); defaults[kv_key] = kv_value; } } else if ($1 == "/unset") { for (i = 2; i <= NF; i++) { kv($i); delete defaults[kv_key]; } } else process_line($1, $0); } # Print the last set of defaults. This will carry # over, I think, to makefs' defaults print mtree_from_kvs("/set", defaults) for (x in tree) print tree[x]; } Index: head/usr.sbin/dumpcis/dumpcis.8 =================================================================== --- head/usr.sbin/dumpcis/dumpcis.8 (revision 355393) +++ head/usr.sbin/dumpcis/dumpcis.8 (revision 355394) @@ -1,48 +1,47 @@ .\" .\" Copyright (c) 2006 M. Warner Losh -.\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" 3. The name of the author may not be used to endorse or promote products .\" derived from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR .\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES .\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. .\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, .\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT .\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .\" $FreeBSD$ .\" .Dd October 18, 2006 .Dt DUMPCIS 8 .Os .Sh NAME .Nm dumpcis .Nd PC Card and Cardbus (PCMCIA) CIS display tool .Sh SYNOPSIS .Nm .Ar .Sh DESCRIPTION The .Nm utility translates a raw CIS stream into human readable form. .Sh SEE ALSO .Xr cardbus 4 , .Xr cbb 4 , .Xr pccard 4 .Sh AUTHORS The original version was written by .An Warner Losh Aq Mt imp@FreeBSD.org . Index: head/usr.sbin/dumpcis/main.c =================================================================== --- head/usr.sbin/dumpcis/main.c (revision 355393) +++ head/usr.sbin/dumpcis/main.c (revision 355394) @@ -1,60 +1,60 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2006 M. Warner Losh. + * Copyright (c) 2006 M. Warner Losh * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include "readcis.h" static void scanfile(char *name) { int fd; struct tuple_list *tl; fd = open(name, O_RDONLY); if (fd < 0) return; tl = readcis(fd); if (tl) { printf("Configuration data for file %s\n", name); dumpcis(tl); freecis(tl); } close(fd); } int main(int argc, char **argv) { for (argc--, argv++; argc; argc--, argv++) scanfile(*argv); return 0; }