All of lore.kernel.org
 help / color / mirror / Atom feed
From: Ilguiz Latypov <ilatypov@superbt.com>
To: linux-kernel@vger.kernel.org
Cc: sjh@wibble.net
Subject: Re: pc speaker cant be accessed with no video card in computer
Date: Thu, 20 Dec 2001 16:36:34 -0500	[thread overview]
Message-ID: <3C2259E2.4070504@superbt.com> (raw)

[-- Attachment #1: Type: text/plain, Size: 1072 bytes --]



I guess it is not easy to produce a series of sounds without
waiting each note to finish.  There is an 8 year old PC speaker
driver for BSD kernel that performs the BASIC PLAY lines in kernel.

Rather than porting it to Linux I chose a simple option of copying
the ioctl PC speaker code into a skeleton misc character device
driver.  As a result I can issue ioctl "beep" calls against my
/dev/pcspeaker (character device with major number 10, minor number
240).  E.g., replacing "/dev/console" with "/dev/pcspeaker" in
PCMCIA cardmgr.c will revive its sound effects.

Please pardon my ignorance in kernel linking.  I don't know how to
refer to the existing _kd_mksound() code from the loadable module.
So I just cut and pasted the code from vt.c.

Ilguiz

From: Steven Hanley (sjh@wibble.net)
Date: Thu Jun 01 2000 - 23:36:57 EST
[...]
 > Basically the pc speaker access from userspace is tied to having a
 > valid tty in the machine. When there is no tty in the computer the pc
 > speaker wont work. This of course means you need a video card in said
 > machine.
[...]

[-- Attachment #2: pcspeaker.c --]
[-- Type: text/plain, Size: 5459 bytes --]

#define PCSPEAKER_VERSION "1.0"
#define PCSPEAKER_MINOR 240

#include <linux/module.h>
#include <linux/config.h>
#include <linux/sched.h>
#include <linux/smp_lock.h>

#if !defined(__i386__) && !defined(__x86_64__)
#error Cannot build speaker driver for this machine configuration.
#endif

#include <linux/types.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/ioport.h>
#include <linux/fcntl.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/spinlock.h>
#include <linux/vt_kern.h>
#include <linux/timex.h>

#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/system.h>

static int pcspeaker_open_cnt;	/* #times opened */
static int pcspeaker_open_mode;	/* special open modes */
#define	PCSPEAKER_WRITE	1	/* opened for writing (exclusive) */
#define	PCSPEAKER_EXCL	2	/* opened with O_EXCL */

/* I don't know how to link this module agains _kd_mktone() in
   drivers/char/vt.c -- Ilguiz Latypov
 */

/*
 * Generates sound of some frequency for some number of clock ticks
 *
 * If freq is 0, will turn off sound, else will turn it on for that time.
 * If msec is 0, will return immediately, else will sleep for msec time, then
 * turn sound off.
 *
 * We also return immediately, which is what was implied within the X
 * comments - KDMKTONE doesn't put the process to sleep.
 */

#if defined(__i386__) || defined(__alpha__) || defined(__powerpc__) \
    || (defined(__mips__) && defined(CONFIG_ISA)) \
    || (defined(__arm__) && defined(CONFIG_HOST_FOOTBRIDGE)) \
    || defined(__x86_64__)

static void
kd_nosound(unsigned long ignored)
{
	/* disable counter 2 */
	outb(inb_p(0x61)&0xFC, 0x61);
	return;
}

void
_kd_mksound2(unsigned int hz, unsigned int ticks)
{
	static struct timer_list sound_timer = { function: kd_nosound };
	unsigned int count = 0;
	unsigned long flags;

	if (hz > 20 && hz < 32767)
		count = 1193180 / hz;
	
	save_flags(flags);
	cli();
	del_timer(&sound_timer);
	if (count) {
		/* enable counter 2 */
		outb_p(inb_p(0x61)|3, 0x61);
		/* set command for counter 2, 2 byte write */
		outb_p(0xB6, 0x43);
		/* select desired HZ */
		outb_p(count & 0xff, 0x42);
		outb((count >> 8) & 0xff, 0x42);

		if (ticks) {
			sound_timer.expires = jiffies+ticks;
			add_timer(&sound_timer);
		}
	} else
		kd_nosound(0);
	restore_flags(flags);
	return;
}

#else

void
_kd_mksound2(unsigned int hz, unsigned int ticks)
{
}

#endif

static long long pcspeaker_llseek(struct file *file,loff_t offset, int origin )
{
	return 0;
}

static ssize_t pcspeaker_read(struct file * file,
	char * buf, size_t count, loff_t *ppos )
{
	return 0;
}

static ssize_t pcspeaker_write(struct file * file,
		const char * buf, size_t count, loff_t *ppos )
{
	return 0;
}

static int pcspeaker_ioctl( struct inode *inode, struct file *file,
				unsigned int cmd, unsigned long arg )
{
	int perm;
	
	perm = 0;
	if (suser())
		perm = 1;
 
	switch( cmd ) {
	case KIOCSOUND:
		if (!perm)
			return -EPERM;
		if (arg)
			arg = CLOCK_TICK_RATE / arg;
		_kd_mksound2(arg, 0);
		return 0;

	case KDMKTONE:
		if (!perm)
			return -EPERM;
	{
		unsigned int ticks, count;
		
		/*
		 * Generate the tone for the appropriate number of ticks.
		 * If the time is zero, turn off sound ourselves.
		 */
		ticks = HZ * ((arg >> 16) & 0xffff) / 1000;
		count = ticks ? (arg & 0xffff) : 0;
		if (count)
			count = CLOCK_TICK_RATE / count;
		_kd_mksound2(count, ticks);
		return 0;
	}
	  default:
		return( -EINVAL );
	}
}

static int pcspeaker_open( struct inode *inode, struct file *file )
{
	if ((pcspeaker_open_cnt && (file->f_flags & O_EXCL)) ||
		(pcspeaker_open_mode & PCSPEAKER_EXCL) ||
		((file->f_mode & 2) && (pcspeaker_open_mode & PCSPEAKER_WRITE)))
		return( -EBUSY );

	if (file->f_flags & O_EXCL)
		pcspeaker_open_mode |= PCSPEAKER_EXCL;
	if (file->f_mode & 2)
		pcspeaker_open_mode |= PCSPEAKER_WRITE;
	pcspeaker_open_cnt++;
	return( 0 );
}

static int pcspeaker_release( struct inode *inode, struct file *file )
{
	lock_kernel();
	pcspeaker_open_cnt--;
	if (file->f_flags & O_EXCL)
		pcspeaker_open_mode &= ~PCSPEAKER_EXCL;
	if (file->f_mode & 2)
		pcspeaker_open_mode &= ~PCSPEAKER_WRITE;
	unlock_kernel();

	return( 0 );
}

static struct file_operations pcspeaker_fops = {
	owner:		THIS_MODULE,
	llseek:		pcspeaker_llseek,
	read:		pcspeaker_read,
	write:		pcspeaker_write,
	ioctl:		pcspeaker_ioctl,
	open:		pcspeaker_open,
	release:	pcspeaker_release,
};

static struct miscdevice pcspeaker_dev = {
	PCSPEAKER_MINOR,
	"pcspeaker",
	&pcspeaker_fops
};


static int __init pcspeaker_init(void)
{
	int ret;

	ret = misc_register( &pcspeaker_dev );
	if (ret) {
		printk(KERN_ERR "pcspeaker: can't misc_register on minor=%d\n", PCSPEAKER_MINOR);
		goto out;
	}
	ret = 0;
	printk(KERN_INFO "PC speaker driver v" PCSPEAKER_VERSION "\n");
out:
	return( ret );
#if 0
outmisc:
	misc_deregister( &pcspeaker_dev );
	goto out;
#endif
}

static void __exit pcspeaker_cleanup_module (void)
{
	misc_deregister( &pcspeaker_dev );
}

module_init(pcspeaker_init);
module_exit(pcspeaker_cleanup_module);

MODULE_LICENSE("GPL");

EXPORT_NO_SYMBOLS;

/*
 * Local variables:
 *  c-indent-level: 4
 *  tab-width: 4
 *  compile-command: "gcc -pipe -mpreferred-stack-boundary=2 -march=i386  -O2 -D__KERNEL__ -I../include -I/home/ilatypov/linux/include -Wall -Wstrict-prototypes -fomit-frame-pointer -fno-strict-aliasing  -DMODULE -DMODVERSIONS -include /home/ilatypov/linux/include/linux/modversions.h -c pcspeaker.c -o pcspeaker.o"
 * End:
 */


[-- Attachment #3: beep.c --]
[-- Type: text/plain, Size: 2499 bytes --]

#include <sys/ioctl.h>
#include <sys/kd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <signal.h>
#include <stdio.h>

#define CLOCK_TICK_RATE   1193180

#define NUMNOTES 12
unsigned long notes[NUMNOTES] = { 26163, 27718, 29366, 31113, 32963, 34923, 
                                  37000, 39200, 41530, 44000, 46616, 49388 };

int default_note = 10;  // 1-based

#define DEFAULT_PARAMS_LEN 3
static const char *default_params[DEFAULT_PARAMS_LEN] = { 
                  "beep", "-10", "10" };

static int fd = -1;

void exiting(int signum) {
    int tone = 0;
    if (fd >= 0)
        ioctl(fd, KIOCSOUND, tone);
}

int check_sound_capabilities(const char *filename, int *fd) {
    int tone;
    int lfd;

    if (strcmp(filename, "-")) {
        lfd = open(filename, O_RDONLY);
        if (lfd < 0) {
            perror(filename);
            return 0;
        }
    } else {
        lfd = 0;
    }

    tone = 0;
    if (ioctl(lfd, KIOCSOUND, tone)) {
        close(lfd);
        perror(filename);
        return 0;
    }

    if (fd != NULL) {
        *fd = lfd;
    }

    return 1;
}

int main(int argc, char *argv[]) {
    int i;
    unsigned int tone;
    int hertz, length;
    int param_len;
    const char **params;

    if (!check_sound_capabilities("/dev/pcspeaker", &fd) &&
        !check_sound_capabilities("-", &fd) &&
	!check_sound_capabilities("/dev/tty0", &fd)) {
        exit(EXIT_FAILURE);
    }

    if (argc <= 1) {
        params = default_params;
        param_len = DEFAULT_PARAMS_LEN;
    } else {
        params = (const char **)argv;
        param_len = argc;
    }

    signal(SIGHUP, exiting);
    signal(SIGINT, exiting);
    signal(SIGQUIT, exiting);
    signal(SIGPIPE, exiting);
    signal(SIGTERM, exiting);
    signal(SIGTSTP, exiting);

    for (i = 1; i < param_len; i += 2) {
        hertz = strtol(params[i], NULL, 0);
        if (hertz < 0) {
            if (hertz < -NUMNOTES)
                hertz = -default_note;
            hertz = notes[-hertz - 1];
        }
        if (i + 1 < param_len)
            length = strtol(params[i + 1], NULL, 0);
        else
            length = 10;

        // printf("hertz %d\n", hertz); fflush(stdout);

        tone = (CLOCK_TICK_RATE * 100) / hertz;
        ioctl(fd, KIOCSOUND, tone);
        usleep(((unsigned long)length) * 10000);
        tone = 0;
        ioctl(fd, KIOCSOUND, tone);
    }

    close(fd);
    fd = -1;
    exit(EXIT_SUCCESS);
    return 0;
}

[-- Attachment #4: Makefile --]
[-- Type: text/plain, Size: 366 bytes --]

all: beep

pcspeaker.o: pcspeaker.c
	gcc -pipe -mpreferred-stack-boundary=2 -march=i386  -O2 -D__KERNEL__ -I../include -I/home/ilatypov/linux/include -Wall -Wstrict-prototypes -fomit-frame-pointer -fno-strict-aliasing  -DMODULE -DMODVERSIONS -include /home/ilatypov/linux/include/linux/modversions.h -c pcspeaker.c -o pcspeaker.o

clean:	 
	rm -rf beep *.o *~ *.gdb

             reply	other threads:[~2001-12-20 21:40 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2001-12-20 21:36 Ilguiz Latypov [this message]
2001-12-23  1:30 ` pc speaker cant be accessed with no video card in computer Pavel Machek
2001-12-24 16:08   ` Hans-Christian Armingeon
2001-12-26  2:47     ` Paul
2001-12-23  5:45 ` James Simmons

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=3C2259E2.4070504@superbt.com \
    --to=ilatypov@superbt.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=sjh@wibble.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.