""" Hardware detection and setup for bktr, saa, audio wiring """ ## MODULE IMPORTS ######################################################## import commands, os, ossaudiodev, time import btcopyright, buildprefs ## MODULE COPYRIGHT ###################################################### MODULE_AUTHOR = btcopyright.MY_NAME MODULE_AUTHOR_EMAIL = btcopyright.MY_EMAIL MODULE_COPYRIGHT = btcopyright.MY_COPYRIGHT MODULE_LICENSE = btcopyright.BSD_LICENSE MODULE_LICENSE_TEXT = btcopyright.BSD_LICENSE_TEXT ## MODULE CONSTANTS ###################################################### # BKTR TV card defines (in order, see /usr/src/sys/dev/bktr/bktr_card.c) UNKNOWN = "Unknown" MIRO = "Pinnacle/Miro TV" HAUPPAUGE = "Hauppauge WinCast/TV" STB = "STB TV/PCI" INTEL = "Intel Smart Video III/VideoLogic Captivator PCI" IMS_TURBO = "IMS TV Turbo" AVER_MEDIA = "AVer Media TV/FM" OSPREY = "MMAC Osprey" NEC_PK = "NEC PK-UG-X017" IO_BCTV2 = "I/O DATA GV-BCTV2/PCI" FLYVIDEO = "FlyVideo" ZOLTRIX = "Zoltrix" KISS = "KISS TV/FM PCI" VIDEO_HIGHWAY_XTREME = "Video Highway Xtreme" ASKEY_DYNALINK_MAGIC_TVIEW = "Askey/Dynalink Magic TView" LEADTEK = "Leadtek Winfast TV 2000" TERRATVPLUS = "TerraTVplus" IO_BCTV3 = "I/O DATA GV-BCTV3/PCI" AOPEN_VA1000 = "AOpen VA1000" PINNACLE_PCTV_RAVE = "Pinnacle PCTV Rave" PIXELVIEW_PLAYTV_PAK = "PixelView PlayTV Pak" TERRATVALUE = "TerraTec TValue" PIXELVIEW_PLAYTV_PRO_REV_4C = "PixelView PlayTV Pro REV-4C" # BKTR cards for convenience BKTR_CARDS = [UNKNOWN, MIRO, HAUPPAUGE, STB, INTEL, IMS_TURBO, AVER_MEDIA, OSPREY, IO_BCTV2, FLYVIDEO, ZOLTRIX, KISS, VIDEO_HIGHWAY_XTREME, ASKEY_DYNALINK_MAGIC_TVIEW, LEADTEK, TERRATVPLUS, IO_BCTV3, AOPEN_VA1000, PINNACLE_PCTV_RAVE, PIXELVIEW_PLAYTV_PAK, TERRATVALUE, PIXELVIEW_PLAYTV_PRO_REV_4C] # BKTR tuner defines (in order, see /usr/src/sys/dev/bktr/bktr_tuner.c) NO_TUNER = "None" TEMIC_NTSC = "Temic NTSC" TEMIC_PAL = "Temic PAL" TEMIC_SECAM = "Temic SECAM" PHILIPS_NTSC = "Philips NTSC" PHILIPS_PAL = "Philips PAL" PHILIPS_SECAM = "Philips SECAM" TEMIC_PALI = "Temic PAL I" PHILIPS_PALI = "Philips PAL I" PHILIPS_FR1236_NTSC = "Philips FR1236 NTSC FM" PHILIPS_FR1216_PAL = "Philips FR1216 PAL FM" PHILIPS_FR1236_SECAM = "Philips FR1236 SECAM FM" ALPS_TSCH5 = "ALPS TSCH5 NTSC FM" ALPS_TSBH1 = "ALPS TSBH1 NTSC" MT2032 = "Microtune MT2032" LG_TPI8PSB12P_PAL = "LG TPI8PSB12P PAL" # BKTR tuners for convenience BKTR_TUNERS = [NO_TUNER, TEMIC_NTSC, TEMIC_PAL, TEMIC_SECAM, PHILIPS_NTSC, PHILIPS_PAL, PHILIPS_SECAM, TEMIC_PALI, PHILIPS_PALI, PHILIPS_FR1236_NTSC, PHILIPS_FR1216_PAL, PHILIPS_FR1236_SECAM, ALPS_TSCH5, ALPS_TSBH1, MT2032, LG_TPI8PSB12P_PAL] # Input norms description NORM_NTSC = "NTSC" NORM_PAL = "PAL" NORM_SECAM = "SECAM" NORMS = [NORM_NTSC, NORM_PAL, NORM_SECAM] # Same but for SAA STD_PAL_B_G = "PAL B/G" STD_PAL_I = "PAL I" STD_PAL_D_K = "PAL D/K" STD_PAL_L = "PAL L" STD_PAL_LACCENT = "PAL L'" STD_NTSC = "NTSC M/N" STD_NTSC_JAPAN = "NTSC Japan" STD_SECAM_B_G = "SECAM B/G" STD_SECAM_D_K = "SECAM D/K" STD_SECAM_L = "SECAM L" STD_SECAM_LACCENT = "SECAM L'" STANDARDS = [STD_PAL_B_G, STD_PAL_I, STD_PAL_D_K, STD_PAL_L, STD_PAL_LACCENT, STD_NTSC, STD_NTSC_JAPAN, STD_SECAM_B_G, STD_SECAM_D_K, STD_SECAM_L, STD_SECAM_LACCENT] # Mixer channels (in self defined order) MIXER_LINE = ossaudiodev.SOUND_MIXER_LINE MIXER_LINE1 = ossaudiodev.SOUND_MIXER_LINE1 MIXER_LINE2 = ossaudiodev.SOUND_MIXER_LINE2 MIXER_LINE3 = ossaudiodev.SOUND_MIXER_LINE3 MIXER_MIC = ossaudiodev.SOUND_MIXER_MIC MIXER_VIDEO = ossaudiodev.SOUND_MIXER_VIDEO # Mixer channels for convenience MIXER_CHANNELS = [MIXER_LINE, MIXER_LINE1, MIXER_LINE2, MIXER_LINE3, MIXER_MIC, MIXER_VIDEO] MIXER_CHANNEL_NAMES = ["line", "line1", "line2", "line3", "mic", "video"] # SAA cards/vendors # see http://linuxtv.org/cgi-bin/viewcvs.cgi/video4linux/doc/ UNKNOWN_SAA = "Unknown card/vendor" ADS = "ADS Tech Instant TV" ASUS = "ASUS TV-FM 713x" AVERMEDIA = "AverMedia AverTV series (also Medion)" BEHOLDER = "Beholder BeholdTV" COMPAL = "LifeView FlyTV Platinum Mini2 (Compal)" COMPRO = "Compro VideoMate TV" ELITEGROUP = "Elitegroup ECS TVP3XP" ELSA = "LSA EX-VISION" GOTVIEW = "GoTView 7135 PCI" KNC_ONE = "KNC One TV-Station DVR" LIFEVIEW = "LifeView FlyVideo" MATROX = "Matrox CronosPlus" MEDION = "Medion 7134" PHILIPS = "Philips (also Empress, SKNet, KNC/Typhoon, AOpen VA1000)" PINNACLE = "Pinnacle PCTV" RTD = "RTD Embedded Technologies VFG73x0" TERRATEC = "Terratec Cinergy" UPMOST = "Upmost Purple TV" # SAA cards/vendors as list SAA_CARDS = [UNKNOWN_SAA, ADS, ASUS, AVERMEDIA, BEHOLDER, COMPAL, COMPRO, ELITEGROUP, ELSA, GOTVIEW, KNC_ONE, LIFEVIEW, MATROX, MEDION, PHILIPS, PINNACLE, RTD, TERRATEC, UPMOST] # SAA cards vendor codes (note: hex numbers as strings) # see http://linuxtv.org/cgi-bin/viewcvs.cgi/video4linux/doc/ VENDOR_UNKNOWN = "0xffff" VENDOR_ADS = "0x1421" VENDOR_ASUS = "0x1043" VENDOR_AVERMEDIA = "0x1461" VENDOR_BEHOLDER = "0x0000" # Is this Gammagraphx? VENDOR_COMPAL = "0x14c0" # Branded Lifeview FlyTV Platinum Mini2 VENDOR_COMPRO = "0x185b" VENDOR_ELITEGROUP = "0x1019" VENDOR_ELSA = "0x1048" VENDOR_GOTVIEW = "0x5456" VENDOR_KNC_ONE = "0x1894" VENDOR_LIFEVIEW = "0x5168" VENDOR_MATROX = "0x102b" VENDOR_MEDION = "0x16be" VENDOR_PHILIPS = "0x1131" # Many branded differently VENDOR_PINNACLE = "0x11bd" VENDOR_RTD = "0x1435" VENDOR_TERRATEC = "0x153b" VENDOR_UPMOST = "0x12ab" # Is this Yuan Yuan? # SAA cards vendor codes as list SAA_VENDORS = [VENDOR_UNKNOWN, VENDOR_ADS, VENDOR_ASUS, VENDOR_AVERMEDIA, VENDOR_BEHOLDER, VENDOR_COMPAL, VENDOR_COMPRO, VENDOR_ELITEGROUP, VENDOR_ELSA, VENDOR_GOTVIEW, VENDOR_KNC_ONE, VENDOR_LIFEVIEW, VENDOR_MATROX, VENDOR_MEDION, VENDOR_PHILIPS, VENDOR_TERRATEC, VENDOR_PINNACLE, VENDOR_RTD, VENDOR_UPMOST] # SAA TUNER API TYPES API_PHILIPS = "Philips" API_PHILIPS_MK3 = "Philips MK3" API_TEMIC = "Temic" API_ALPS = "Alps" API_LG = "LG" # SAA TUNER API TYPE LIST SAA_TUNERS = [API_PHILIPS, API_PHILIPS_MK3, API_TEMIC, API_ALPS, API_LG] # PWC vendor codes and names list # http://raaf.atspace.org PWC_VENDORS = [ ("0xffff", "Unknown vendor"), ("0x06be", "AME"), ("0x069a", "Askey"), ("0x041b", "Creative Labs"), ("0x046d", "Logitech"), ("0x0471", "Philips"), ("0x055d", "Samsung"), ("0x04cc", "Sotec"), ("0x0d81", "Visionite") ] # PWC product codes and names list PWC_PRODUCTS = [ ("0xffff", "Unknown model"), ("0x0302", "Philips PCA645VC"), ("0x0303", "Philips PCA646VC"), ("0x0304", "Askey VC010 type 2"), ("0x0307", "Philips PCVC675K (Vesta)"), ("0x0308", "Philips PCVC680K (Vesta Pro)"), ("0x030c", "Philips PCVC690K (Vesta Pro Scan)"), ("0x0310", "Philips PCVC730K (ToUCam Fun)/PCVC830 (ToUCam II)"), ("0x0311", "Philips PCVC740K (ToUCam Pro)/PCVC840 (ToUCam II)"), ("0x0312", "Philips PCVC750K (ToUCam Pro Scan)"), ("0x0313", "Philips PCVC720K/40 (ToUCam XS)"), ("0x0329", "Philips SPC900NC"), ("0x0001", "Askey VC010 type 1"), ("0x08b0", "Logitech QuickCam Pro 3000"), ("0x08b1", "Logitech QuickCam Notebook Pro"), ("0x08b2", "Logitech QuickCam Pro 4000"), ("0x08b3", "Logitech QuickCam Zoom"), ("0x08b4", "Logitech QuickCam Zoom (new model)"), ("0x08b5", "Logitech QuickCam Orbit/Sphere"), ("0x08b6", "Logitech QuickCam (reserved ID)"), ("0x08b7", "Logitech QuickCam (reserved ID)"), ("0x08b8", "Logitech QuickCam (reserved ID)"), ("0x9000", "Samsung MPC-C10"), ("0x9001", "Samsung MPC-C30"), ("0x9002", "Samsung SNC-35E"), ("0x400c", "Creative Labs Webcam 5"), ("0x4011", "Creative Labs Webcam Pro Ex"), ("0x8116", "Sotec Afina Eye"), ("0x8116", "AME Co. Afina Eye"), ("0x1910", "Visionite VCS-UC300"), ("0x1900", "Visionite VCS-UM100") ] # Paths to config files DEVFS_CONF = "/etc/devfs.conf" LOADER_CONF = "/boot/loader.conf" SYSCTL_CONF = "/etc/sysctl.conf" # Devices AUDIO_DEVICE = "/dev/dsp" BKTR_DEVICE = "/dev/bktr" MIXER_DEVICE = "/dev/mixer" TUNER_DEVICE = "/dev/tuner" SAA_DEVICE = "/dev/saa0" SAU_DEVICE = "/dev/sau0" IIC_DEVICE = "/dev/iic0" PWC_DEVICE = "/dev/video0" # Commands DEVFS_RESTART = "/etc/rc.d/devfs restart " DMESG_BKTR = "dmesg | grep bktr0 | grep tuner " DMESG_BOOT_BKTR = "cat /var/run/dmesg.boot | grep bktr0 | grep tuner " KLDLOAD = "kldload " KLDSTAT_SND = "kldstat | grep snd_ | awk '{ print $5 }' " KLDSTAT_BKTR = "kldstat | grep bktr.ko | awk '{ print $5 }' " KLDSTAT_SAA = "kldstat | grep saa.ko | awk '{ print $5 }' " KLDSTAT_IIC = "kldstat | grep iic.ko | awk '{ print $5 }' " KLDSTAT_PWC = "kldstat | grep pwc.ko | awk '{ print $5 }' " KLDUNLOAD = "kldunload " PW_GROUPMOD = "pw groupmod operator -m " SYSCTL = "sysctl" SYSCTL_BKTR_MSGBUF = "sysctl kern.msgbuf | grep bktr0 | grep tuner " SYSCTL_BKTR_CARD = "hw.bt848.card" SYSCTL_BKTR_CARD_GET = "sysctl -n " + SYSCTL_BKTR_CARD SYSCTL_BKTR_CARD_SET = "sysctl " + SYSCTL_BKTR_CARD + "=" SYSCTL_BKTR_CHIP = "sysctl -n dev.bktr.0.%desc " SYSCTL_BKTR_TUNER = "hw.bt848.tuner" SYSCTL_BKTR_TUNER_GET = "sysctl -n " + SYSCTL_BKTR_TUNER SYSCTL_BKTR_TUNER_SET = "sysctl " + SYSCTL_BKTR_TUNER + "=" SYSCTL_SND_CHIP = "sysctl -n dev.pcm.0.%desc " # Phillips should be Philips, mis-spelled in pci_vendors SYSCTL_SAA_CHIP = "sysctl -n dev.saa.0.%desc | awk '{ print $1, $2 }' | sed s/Phillips/Philips/" SYSCTL_SAA_SUBVENDOR = "sysctl -n dev.saa.0.%pnpinfo | awk '{ print $3 }' | sed s/subvendor=// " SYSCTL_PWC_VENDOR = "sysctl -n dev.pwc.0.%pnpinfo | awk '{ print $1 }' | sed s/vendor=//" SYSCTL_PWC_PRODUCT = "sysctl -n dev.pwc.0.%pnpinfo | awk '{ print $2 }' | sed s/product=//" # For convenience BKTR_MODULE = "bktr.ko" SAA_MODULE = "saa.ko" IIC_MODULE = "iic.ko" PWC_MODULE = "pwc.ko" DELTA_HEADER = "\n## Appended by btsetup (kbtv) " DEVFS_OWN_PERM = """ ## BEGIN BKTR own bktr0 root:operator own tuner0 root:operator perm bktr0 0660 perm tuner0 0660 ## END BKTR """ DEVFS_OWN_PERM_SAA = """ ## BEGIN SAA own iic0 root:operator own saa0 root:operator own sau0 root:operator perm iic0 0660 perm saa0 0660 perm sau0 0660 ## END SAA """ # In PWC case perm are made stricter DEFS_OWN_PERM_PWC = """ ## BEGIN PWC own video0 root:operator perm video0 0660 ## END PWC """ SAMPLE_SIZE = 256 SND_DRIVER = "snd_driver" SOUND_MODULE_GLOB = "snd_*" SYSCTL_OVERRIDE = " bool, bool Uses os.stat() to perform a stat() system call on BKTR_DEVICE and TUNER_DEVICE and checks the user's group memberships. True if permissions, ownership, and group membership are as required. Likewise, False if not, or on failure. This for both devices. The imposed requirements are: - RW permissions for owner and group, none for others - Ownership by root:operator (UID 0, GID 5) - User must be a member of the operator group Note that by default FreeBSD creates these nodes owned by root:wheel. The wheel group is undesirable if common practice is followed where RW permissions are set for the group while making the user a member of the group. The operator group is better suited and commonly used for this. """ p, u, g = False, False, False ret = False i = 0 for dev in (BKTR_DEVICE, TUNER_DEVICE): try: st = os.stat(dev) except OSError: # No device or something return (False, False) if oct(st[0])[3:] == "660": p = True if st[4] == 0: u = True if st[5] == 5: u = (u and True) try: if 5 in os.getgroups(): g = True except OSError: pass if i == 0: ret = p and u and g i += 1 return (ret, p and u and g) def saa_access(): """ -> bool, bool, bool Uses os.stat() to perform a stat() system call on SAA_DEVICE, SAU_DEVICE, and IIC_DEVICE and checks the user's group memberships. True if permissions, ownership, and group membership are as required. Likewise, False if not, or on failure. This for all three devices. The imposed requirements are: - RW permissions for owner and group, none for others - Ownership by root:operator (UID 0, GID 5) - User must be a member of the operator group Note that by default FreeBSD creates these nodes owned by root:wheel. The wheel group is undesirable if common practice is followed where RW permissions are set for the group while making the user a member of the group. The operator group is better suited and commonly used for this. """ p, u, g = False, False, False ret, ret2 = False, False i = 0 for dev in (SAA_DEVICE, SAU_DEVICE, IIC_DEVICE): try: st = os.stat(dev) except OSError: # No device or something return (False, False, False) if oct(st[0])[3:] == "660": p = True if st[4] == 0: u = True if st[5] == 5: u = (u and True) try: if 5 in os.getgroups(): g = True except OSError: pass if i == 0: ret = p and u and g if i == 1: ret2 = p and u and g i += 1 return (ret, ret2, p and u and g) def pwc_access(): """ -> bool Uses os.stat() to perform a stat() system call on PWC_DEVICE and checks the user's group memberships. True if permissions, ownership, and group membership are as required. Likewise, False if not, or on failure. The imposed requirements are: - RW permissions for owner and group, none for others - Ownership by root:operator (UID 0, GID 5) - User must be a member of the operator group Note that by default the pwc driver creates this node owned by root:operator already, but with RW permissions for anyone. While understandable, this is undesirable and potentially unsafe. """ p, u, g = False, False, False ret = False i = 0 try: st = os.stat(PWC_DEVICE) except OSError: # No device or something return False if oct(st[0])[3:] == "660": p = True if st[4] == 0: u = True if st[5] == 5: u = (u and True) try: if 5 in os.getgroups(): g = True except OSError: pass return p and u and g def bktr_access_commit(): """ -> bool Attempts to change and write the required permissions and ownership (see bktr_access()). Returns True on success, False on failure. You must have UID 0 (root). This function will write to DEVFS_CONF and then restart devfs. Note that this function does not check if the rules in DEVFS_OWN_PERM are already in the config file, and appends the same thing over and over if asked. """ try: if os.getuid() == 0: try: fd = open(DEVFS_CONF, "a") fd.write(DELTA_HEADER + time.ctime()) fd.write(DEVFS_OWN_PERM) fd.close() except IOError: return False if commands.getoutput(DEVFS_RESTART) == "": return True except OSError: pass return False def saa_access_commit(): """ -> bool Attempts to change and write the required permissions and ownership (see saa_access()). Returns True on success, False on failure. You must have UID 0 (root). This function will write to DEVFS_CONF and then restart devfs. Same as the bktr_access_commit() function but using DEVFS_OWN_PERM_SAA. Note that this function does not check if the rules in DEVFS_OWN_PERM are already in the config file, and appends the same thing over and over if asked. """ try: if os.getuid() == 0: try: fd = open(DEVFS_CONF, "a") fd.write(DELTA_HEADER + time.ctime()) fd.write(DEVFS_OWN_PERM_SAA) fd.close() except IOError: return False if commands.getoutput(DEVFS_RESTART) == "": return True except OSError: pass return False def pwc_access_commit(): """ -> bool Attempts to change and write the required permissions and ownership (see pwc_access()). Returns True on success, False on failure. You must have UID 0 (root). This function will write to DEVFS_CONF and then restart devfs. Note that this function does not check if the rules in DEVFS_OWN_PERM are already in the config file, and appends the same thing over and over if asked. """ try: if os.getuid() == 0: try: fd = open(DEVFS_CONF, "a") fd.write(DELTA_HEADER + time.ctime()) fd.write(DEVFS_OWN_PERM_PWC) fd.close() except IOError: return False if commands.getoutput(DEVFS_RESTART) == "": return True except OSError: pass return False def bktr_user_add(uid): """ -> bool Attempts to add uid (string or int) as an additional member of the operator group using PW_GROUPMOD. Returns True on success, False on failure. You must have UID 0 (root). """ if not type(uid) == type(""): if not type(uid) == type(1000): return False else: uid = str(uid) try: if os.getuid() == 0: if commands.getoutput(PW_GROUPMOD + uid) == "": return True except OSError: pass return False def saa_user_add(uid): """ -> bool Calls bktr_user_add(uid), which is not bktr specific. """ return bktr_user_add(uid) def pwc_user_add(uid): """ -> bool Calls bktr_user_add(uid), which is not bktr specific. """ return bktr_user_add(uid) def bktr_norm(): """ -> string Returns the input norm, "NTSC", "PAL", "SECAM". Calls the function bktr_card_tuner() to get the tuner string and extracts the norm from that. The norms are also in NORMS. Returns "" on failure. """ tuner = bktr_card_tuner()[1] if tuner != "": for n in NORMS: if n in tuner: return n if "MT2032" in tuner: return NORM_PAL return "" def saa_norm(): """ -> string Returns the input norm (broadcasting standard), one of "PAL B/G", "PAL I", "PAL D/K", "PAL L", "PAL L'", "NTSC M/N", "NTSC Japan", "SECAM B/G", "SECAM D/K", "SECAM L", or "SECAM L'". This reflects a compile time setting. """ if buildprefs.SAA_TUNER_STD == buildprefs.SAA_TUNER_STD_PAL_I: return STD_PAL_I elif buildprefs.SAA_TUNER_STD == buildprefs.SAA_TUNER_STD_PAL_D_K: return STD_PAL_D_K elif buildprefs.SAA_TUNER_STD == buildprefs.SAA_TUNER_STD_PAL_L: return STD_PAL_L elif buildprefs.SAA_TUNER_STD == buildprefs.SAA_TUNER_STD_PAL_LACCENT: return STD_PAL_LACCENT elif buildprefs.SAA_TUNER_STD == buildprefs.SAA_TUNER_STD_NTSC: return STD_NTSC elif buildprefs.SAA_TUNER_STD == buildprefs.SAA_TUNER_STD_NTSC_JAPAN: return STD_NTSC_JAPAN elif buildprefs.SAA_TUNER_STD == buildprefs.SAA_TUNER_STD_SECAM_B_G: return STD_SECAM_B_G elif buildprefs.SAA_TUNER_STD == buildprefs.SAA_TUNER_STD_SECAM_D_K: return STD_SECAM_D_K elif buildprefs.SAA_TUNER_STD == buildprefs.SAA_TUNER_STD_SECAM_L: return STD_SECAM_L elif buildprefs.SAA_TUNER_STD == buildprefs.SAA_TUNER_STD_SECAM_LACCENT: return STD_SECAM_LACCENT else: return STD_PAL_B_G def bktr_card_tuner(): """ -> (string, string) Searches the message buffer (via sysctl kern.msgbuf or dmesg) to find out which card and tuner type was last reported by the driver. It returns a tuple of strings (card, tuner) which are in BKTR_CARDS and BKTR_TUNERS respectively. Only the *first* device (bktr0) is considered. If any of the sysctls hw.bt848.card or hw.bt848.tuner are set, they are assumed to override the driver detected defaults correctly. The string "" is appended, where N is the sysctl value. Note that there is no guarantee that any sysctl settings are correct. """ card, tuner = ("", "") try: # Look in msgbuf res = commands.getoutput(SYSCTL_BKTR_MSGBUF) if not res: # Look in dmesg res = commands.getoutput(DMESG_BKTR) if not res: # Look in dmesg.boot res = commands.getoutput(DMESG_BOOT_BKTR) except OSError: pass # Avoid dupes and get the last one if res: if "\n" in res: res = res[(res.rfind("\n")+1):] # Split at the word " tuner", keep first half res = res.split(" " + TUNER)[0] # Slice off leading 'bktr0: ' res = res[7:] # Split at ", ", now we have our two parts (card, tuner) res = res.split(", ") card, tuner = res[0], res[1] if not card in BKTR_CARDS: # There is a bktr0 entry but an unknown name, should not happen card = UNKNOWN if not tuner in BKTR_TUNERS: tuner = NO_TUNER # If sysctl is set assume it indeed overrides correctly c, t = bktr_sysctls() if c >= 0 and c < len(BKTR_CARDS): card = BKTR_CARDS[c] + SYSCTL_OVERRIDE + str(c) + ">" if t >= 0 and t < len(BKTR_TUNERS): tuner = BKTR_TUNERS[t] + SYSCTL_OVERRIDE + str(t) + ">" return card, tuner def saa_card_tuner(): """ -> (string, string) Returns the card/vendor and tuner type as a tuple of strings. Saa does not have tunable sysctls. Uses sysctl dev.saa.0%pnpinfo to find the subvendor number, compares it to the numbers in SAA_VENDORS and if there's a match, returns the corresponding Card/vendor string from SAA_CARDS. Only the *first* device (saa0) is considered. Informative only, and card/vendor string may not be what's expected (because of incomplete list, rebranding, repackaging, etc), shouldn't matter though. The tuner type must be set at saa compile time. Default: Philips. The output of saa_norm() is appended to the tuner string. """ card, tuner = ("", "") vendor = commands.getoutput(SYSCTL_SAA_SUBVENDOR) if not vendor in SAA_VENDORS: vendor = VENDOR_UNKNOWN card = SAA_CARDS[SAA_VENDORS.index(vendor)] tuner = API_PHILIPS if buildprefs.SAA_TUNER == buildprefs.SAA_TUNER_PHILIPS_MK3: tuner = API_PHILIPS_MK3 if buildprefs.SAA_TUNER == buildprefs.SAA_TUNER_ALPS: tuner = API_ALPS if buildprefs.SAA_TUNER == buildprefs.SAA_TUNER_LG: tuner = API_LG if buildprefs.SAA_TUNER == buildprefs.SAA_TUNER_TEMIC: tuner = API_TEMIC tuner += ", " + saa_norm() return card, tuner def pwc_vendor_product(): """ -> (string, string) Returns the vendor and product name as a tuple of strings. Uses sysctl dev.pwc.0%pnpinfo to find the vendor and product number, compares it to the numbers in PWC_VENDORS and PWC_PRODUCTS and if there's a match, returns the corresponding vendor and product strings as a tuple. Only the *first* dev node (pwc.0) is considered. Informative only. """ vendor = commands.getoutput(SYSCTL_PWC_VENDOR) product = commands.getoutput(SYSCTL_PWC_PRODUCT) vtext, ptext = PWC_VENDORS[0][1], PWC_PRODUCTS[0][1] for item in PWC_VENDORS: if item[0] == vendor: vtext = item[1] break if vtext != PWC_VENDORS[0][1]: for item in PWC_PRODUCTS: if item[0] == product: ptext = item[1] break return vtext, ptext def bktr_sysctls_commit(): """ -> bool Attempts to write the sysctls hw.bt848.card and hw.bt848.tuner to the config file specified by SYSCTL_CONF. First getBktrSysctls() is called and if not -1 they are appended to the file. Returns True on success, False in any other case. You must have UID 0 (root). Note that this function does not check if the sysctls are already in the config file, and appends the same thing over and over if asked. """ try: if os.getuid() == 0: c, t = bktr_sysctls() txt0, txt1 = "", "" if c != -1: txt0 = SYSCTL_BKTR_CARD + "=" + str(c) + "\n" if t != -1: txt1 = SYSCTL_BKTR_TUNER + "=" + str(t) + "\n" if (c, t) == (-1, -1): return True try: fd = open(SYSCTL_CONF, "a") fd.write(DELTA_HEADER + time.ctime()) fd.write("\n## BEGIN\n" + txt0 + txt1 + "## END\n") fd.close() return True except IOError: pass return False except OSError: pass return False def bktr_sysctls(): """ -> (int, int) Retrieves the sysctls hw.bt848.card and hw.bt848.tuner and returns them as a tuple of integers (card, tuner) if the values are valid (corresponding with the index of BKTR_CARDS and BKTR_TUNERS). If a value is invalid it is changed to -1. If there are no devices (then there are no sysctls), the value also becomes -1. Note that there is no guarantee that any sysctl settings are correct. """ c, t = -1, -1 try: cs = commands.getoutput(SYSCTL_BKTR_CARD_GET) ts = commands.getoutput(SYSCTL_BKTR_TUNER_GET) if not "sysctl" in cs: c = int(cs) if not "sysctl" in ts: t = int(ts) except OSError: pass if c < 0 or c >= len(BKTR_CARDS): c = -1 if t < 0 or t >= len(BKTR_TUNERS): t = -1 return (c, t) def bktr_sysctls_set(card, tuner): """ -> (bool, bool) Sets the sysctl hw.bt848.card and hw.bt848.tuner and returns a tuple of booleans for card and tuner respectively; True on success, False on failure. Failure occurs if the caller has no root permissions, and if a sysctl got set and then retrieved but turns out to be not equal to the one it was supposed to be set to. If there is no hardware, the sysctls are invalid and False is returned. Note that there is no guarantee that any sysctl settings are correct. """ try: if os.getuid() == 0: if card < 0 or card >= len(BKTR_CARDS): card = -1 if tuner < 0 or tuner >= len(BKTR_TUNERS): tuner = -1 cs = commands.getoutput(SYSCTL_BKTR_CARD_SET + str(card)) ts = commands.getoutput(SYSCTL_BKTR_TUNER_SET + str(tuner)) if not "sysctl" in cs: cs = commands.getoutput(SYSCTL_BKTR_CARD_GET) if int(cs) == card: if not "sysctl" in ts: ts = commands.getoutput(SYSCTL_BKTR_TUNER_GET) if int(ts) == tuner: return True, True else: return True, False else: if not "sysctl" in ts: ts = commands.getoutput(SYSCTL_BKTR_TUNER_GET) if int(ts) == tuner: return False, True else: return False, False else: return False, False # Not UID 0 except OSError: pass return False, False def bktr_module_loaded(): """ -> bool Runs kldstat to see if bktr module is loaded. Returns True or False. Note that the module not being loaded can also mean that bktr is built into the kernel, in which case you can't and shouldn't load it. """ try: if commands.getoutput(KLDSTAT_BKTR): return True except OSError: pass return False def saa_module_loaded(): """ -> bool Runs kldstat to see if saa module is loaded. Returns True or False. Note that unlike bktr, saa is only used as a kld. So this can be used at runtime to determine availablity in an unambigueous way. """ try: if commands.getoutput(KLDSTAT_SAA): return True except OSError: pass return False def pwc_module_loaded(): """ -> bool Runs kldstat to see if pwc module is loaded. Returns True or False. Note that unlike bktr, pwc is only used as a kld. So this can be used at runtime to determine availablity in an unambigueous way. """ try: if commands.getoutput(KLDSTAT_PWC): return True except OSError: pass return False def bktr_module_commit(): """ -> bool Attempts to write the bktr_load directive to the loader config file specified by LOADER_CONF. First bktr_module_loaded() is called and if succesful, bktr_load="YES" is appended to the file. Returns True on success, False in any other case. You must have UID 0 (root). Note that this function does not check if the directive is already in the config file, and appends the same thing over and over if asked. """ try: if os.getuid() == 0: if bktr_module_loaded(): try: fd = open(LOADER_CONF, "a") fd.write(DELTA_HEADER + time.ctime()) fd.write('\n## BEGIN BKTR\nbktr_load="YES"\n## END BKTR\n') fd.close() return True except IOError: pass except OSError: pass return False def saa_module_commit(): """ -> bool Attempts to write the saa_load and iic_load directives to the loader config file specified by LOADER_CONF. First saa_module_loaded() is called and if succesful, saa_load="YES" and iic_load="YES" are appended to the file. Returns True on success, False in any other case. You must have UID 0 (root). Note that this function does not check if the directive is already in the config file, and appends the same thing over and over if asked. """ try: if os.getuid() == 0: if saa_module_loaded(): try: fd = open(LOADER_CONF, "a") fd.write(DELTA_HEADER + time.ctime()) fd.write('\n## BEGIN SAA\n') fd.write('iic_load="YES"\n') fd.write('saa_load="YES"\n') fd.write('## END SAA\n') fd.close() return True except IOError: pass except OSError: pass return False def pwc_module_commit(): """ -> bool Attempts to write the pwc_load directive to the loader config file specified by LOADER_CONF. First pwc_module_loaded() is called and if succesful, pwc_load="YES" is appended to the file. Returns True on success, False in any other case. You must have UID 0 (root). Note that this function does not check if the directive is already in the config file, and appends the same thing over and over if asked. """ try: if os.getuid() == 0: if pwc_module_loaded(): try: fd = open(LOADER_CONF, "a") fd.write(DELTA_HEADER + time.ctime()) fd.write('\n## BEGIN PWC\npwc_load="YES"\n## END PWC\n') fd.close() return True except IOError: pass except OSError: pass return False def bktr_chip(): """ -> string Retrieves the description string for the chip, e.g. "BrookTree 878". Uses sysctl and only for the *first* bktr device: dev.bktr.0.%desc. """ try: ret = commands.getoutput(SYSCTL_BKTR_CHIP) if not SYSCTL in ret: return ret except OSError: pass return "" def saa_chip(): """ -> string Retrieves the description string for the chip, e.g. "Philips SAA7134". Uses sysctl and only for the *first* saa device: dev.saa.0.%desc. """ try: ret = commands.getoutput(SYSCTL_SAA_CHIP) if not SYSCTL in ret: return ret except OSError: pass return "" def bktr_module_try(): """ -> bool Attempts to kldload the bktr module, if not already loaded. If succesful or if already loaded the return value is True. In all other cases, including when the caller has no root permissions, False is returned. Note that the module not being loaded can also mean that bktr is built into the kernel, in which case you can't and shouldn't load it. Also note that quite a few TV cards need to have the tuner type set with sysctl. """ try: if os.getuid() == 0: if bktr_module_loaded(): return True else: # Try to load res = commands.getoutput(KLDLOAD + BKTR_MODULE) if bktr_module_loaded(): return True # Not UID 0 falls through except OSError: pass return False def saa_module_try(): """ -> bool Attempts to kldload the saa (and iic) module, if not already loaded. If succesful or if already loaded the return value is True. In all other cases, including when the caller has no root permissions, False. Note that the unlike bktr, the saa driver is always to be used as a kld. """ try: if os.getuid() == 0: if saa_module_loaded(): return True else: # Try to load if commands.getoutput(KLDSTAT_IIC) != IIC_MODULE: # Don't croak if kldload fails (iic may be in kernel) res = commands.getoutput(KLDLOAD + IIC_MODULE) res = commands.getoutput(KLDLOAD + SAA_MODULE) if saa_module_loaded(): return True # Not UID 0 falls through except OSError: pass return False def pwc_module_try(): """ -> bool Attempts to kldload the pwc module, if not already loaded. If succesful or if already loaded the return value is True. In all other cases, including when the caller has no root permissions, False is returned. Note that the unlike bktr, the saa driver is always to be used as a kld. """ try: if os.getuid() == 0: if pwc_module_loaded(): return True else: # Try to load res = commands.getoutput(KLDLOAD + PWC_MODULE) if pwc_module_loaded(): return True # Not UID 0 falls through except OSError: pass return False def snd_module_loaded(): """ -> bool Runs kldstat to see if a sound module is loaded. Returns True if one or more snd_* modules are loaded, False if none is. Note that the module not being loaded can also mean that it is built into the kernel, in which case you can't and shouldn't load it. """ try: if commands.getoutput(KLDSTAT_SND): # May be more than one return True except OSError: pass return False def snd_module_commit(): """ -> bool Attempts to write the snd_*_load directive(s) to the loader config file specified by LOADER_CONF. First snd_module_loaded() is called and if succesful, snd_*_load="YES" is appended to the file for every snd module currently loaded. Returns True on success, or False otherwise. You must have UID 0 (root). Note that this function does not check if the directive is already in the config file, and appends the same thing over and over if asked. """ try: if os.getuid() == 0: if snd_module_loaded(): modules = commands.getoutput(KLDSTAT_SND).split() try: fd = open(LOADER_CONF, "a") fd.write(DELTA_HEADER + time.ctime() + "\n## BEGIN SND\n") fd.write('snd_driver_load="YES"\n') fd.write("## END SND\n") fd.close() return True except IOError: pass except OSError: pass return False def snd_chip(): """ -> string Retrieves the description string for the chip, e.g. "Creative EMU10K1". Uses sysctl and only for the *first* pcm device: dev.pcm.0.%desc. """ try: ret = commands.getoutput(SYSCTL_SND_CHIP) if not SYSCTL in ret: return ret except OSError: pass return "" def snd_module_try(): """ -> bool Attempts to kldload the snd_driver umbrella module. If already loaded, or if successfully loaded the return value is True. In all other cases, including when the caller has no root permissions, False is returned. While it's possible to have the actual driver attach (providing a way to look it up so that all the other modules can be unloaded), this proved to be not so simple as it sounds. Instead, the snd_driver provides all modules and they all remain loaded. The user probably doesn't care about them anyway. Note that the module not being loaded can also mean that snd_foo is built into the kernel, in which case you can't and shouldn't load it. """ try: if os.getuid() == 0: if snd_module_loaded(): return True else: # Try to load all snd_* modules, ignore output foo = commands.getoutput(KLDLOAD + SND_DRIVER) # Check if loaded if snd_module_loaded(): return True # Not UID 0 fallthrough except OSError: pass return False def mixer_channels(): """ -> List Returns a sublist of MIXER_CHANNELS that are actually valid on this box (e.g. supported by soundcard and by ossmixer). """ set = [] # Open /dev/mixer try: mixer = ossaudiodev.openmixer(MIXER_DEVICE) ctls = mixer.controls() for chan in MIXER_CHANNELS: # Test if channel is valid if ctls & (1 << chan): set.append(chan) except IOError: print "mixer_channels(): IOError" except OSSAudioError: print "mixer_channels(): OSSAudioError" return set def mixer_volume_set(chan, vol): """ -> void Sets the volume for mixer channel chan to vol [0..100], where chan is an index of MIXER_CHANNELS. If not, it silently fails. The volume should be a tuple (left, right). """ # Not very handy this if vol[0] < 0: if vol[1] < 0: v = (0, 0) else: if vol[1] > 100: v = (0, 100) else: v = (0, vol[1]) else: if vol[1] < 0: if vol[0] > 100: v = (100, 0) else: v = (vol[0], 0) else: if vol[0] > 100: v = (100, vol[1]) else: v = (vol[0], vol[1]) if chan in range(len(MIXER_CHANNELS)): chan = MIXER_CHANNELS[chan] try: mixer = ossaudiodev.openmixer(MIXER_DEVICE) mixer.set(chan, v) mixer.close() except IOError, OSSAudioError: pass def mixer_volume(chan): """ -> int Returns the volume for mixer channel chan, where chan is an index of MIXER_CHANNELS. It returns a tuple (left, right). If the channel does not exist on this mixer/card or if the mixer can't be opened it returns (-1, -1). """ if chan in range(len(MIXER_CHANNELS)): chan = MIXER_CHANNELS[chan] try: mixer = ossaudiodev.openmixer(MIXER_DEVICE) if mixer.controls() & (1 << chan): return mixer.get(chan) mixer.close() except IOError, OSSAudioError: pass return (-1, -1) ## END ################################################################### if __name__ == "__main__": print "This is a module. Import it instead."