亚洲欧美第一页_禁久久精品乱码_粉嫩av一区二区三区免费野_久草精品视频

? 歡迎來到蟲蟲下載站! | ?? 資源下載 ?? 資源專輯 ?? 關于我們
? 蟲蟲下載站

?? shortprint.c

?? Linux設備驅動的經典教材, 該電子書是第三版,并附有全部配套代碼.
?? C
字號:
/* * A version of the "short" driver which drives a parallel printer directly, * with a lot of simplifying assumptions. * * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet * Copyright (C) 2001 O'Reilly & Associates * * The source code in this file can be freely used, adapted, * and redistributed in source or binary form, so long as an * acknowledgment appears in derived source files.  The citation * should list that the code comes from the book "Linux Device * Drivers" by Alessandro Rubini and Jonathan Corbet, published * by O'Reilly & Associates.   No warranty is attached; * we cannot take responsibility for errors or fitness for use. * * $Id: shortprint.c,v 1.4 2004/09/26 08:01:04 gregkh Exp $ */#include <linux/config.h>#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/sched.h>#include <linux/kernel.h> /* printk() */#include <linux/fs.h>	  /* everything... */#include <linux/errno.h>  /* error codes */#include <linux/delay.h>  /* udelay */#include <linux/slab.h>#include <linux/ioport.h>#include <linux/interrupt.h>#include <linux/workqueue.h>#include <linux/timer.h>#include <linux/poll.h>#include <asm/io.h>#include <asm/semaphore.h>#include <asm/atomic.h>#include "shortprint.h"#define SHORTP_NR_PORTS 3/* * all of the parameters have no "shortp_" prefix, to save typing when * specifying them at load time */static int major = 0; /* dynamic by default */module_param(major, int, 0);/* default is the first printer port on PC's. "shortp_base" is there too   because it's what we want to use in the code */static unsigned long base = 0x378;unsigned long shortp_base = 0;module_param(base, long, 0);/* The interrupt line is undefined by default. "shortp_irq" is as above */static int irq = -1;static int shortp_irq = -1;module_param(irq, int, 0);/* Microsecond delay around strobe. */static int delay = 0;static int shortp_delay;module_param(delay, int, 0);MODULE_AUTHOR ("Jonathan Corbet");MODULE_LICENSE("Dual BSD/GPL");/* * Forwards. */static void shortp_cleanup(void);static void shortp_timeout(unsigned long unused);/* * Input is managed through a simple circular buffer which, among other things, * is allowed to overrun if the reader isn't fast enough.  That makes life simple * on the "read" interrupt side, where we don't want to block. */static unsigned long shortp_in_buffer = 0;static unsigned long volatile shortp_in_head;static volatile unsigned long shortp_in_tail;DECLARE_WAIT_QUEUE_HEAD(shortp_in_queue);static struct timeval shortp_tv;  /* When the interrupt happened. *//* * Atomicly increment an index into shortp_in_buffer */static inline void shortp_incr_bp(volatile unsigned long *index, int delta){	unsigned long new = *index + delta;	barrier ();  /* Don't optimize these two together */	*index = (new >= (shortp_in_buffer + PAGE_SIZE)) ? shortp_in_buffer : new;}/* * On the write side we have to be more careful, since we don't want to drop * data.  The semaphore is used to serialize write-side access to the buffer; * there is only one consumer, so read-side access is unregulated.  The * wait queue will be awakened when space becomes available in the buffer. */static unsigned char *shortp_out_buffer = NULL;static volatile unsigned char *shortp_out_head, *shortp_out_tail;static struct semaphore shortp_out_sem;static DECLARE_WAIT_QUEUE_HEAD(shortp_out_queue);/* * Feeding the output queue to the device is handled by way of a * workqueue. */static void shortp_do_work(void *);static DECLARE_WORK(shortp_work, shortp_do_work, NULL);static struct workqueue_struct *shortp_workqueue;/* * Available space in the output buffer; should be called with the semaphore * held.  Returns contiguous space, so caller need not worry about wraps. */static inline int shortp_out_space(void){	if (shortp_out_head >= shortp_out_tail) {		int space = PAGE_SIZE - (shortp_out_head - shortp_out_buffer);		return (shortp_out_tail == shortp_out_buffer) ? space - 1 : space;	} else		return (shortp_out_tail - shortp_out_head) - 1;}static inline void shortp_incr_out_bp(volatile unsigned char **bp, int incr){	unsigned char *new = (unsigned char *) *bp + incr;	if (new >= (shortp_out_buffer + PAGE_SIZE))		new -= PAGE_SIZE;	*bp = new;}/* * The output "process" is controlled by a spin lock; decisions on * shortp_output_active or manipulation of shortp_out_tail require * that this lock be held. */static spinlock_t shortp_out_lock;volatile static int shortp_output_active;DECLARE_WAIT_QUEUE_HEAD(shortp_empty_queue); /* waked when queue empties *//* * When output is active, the timer is too, in case we miss interrupts.	 Hold * shortp_out_lock if you mess with the timer. */static struct timer_list shortp_timer;#define TIMEOUT 5*HZ  /* Wait a long time *//* * Open the device. */static int shortp_open(struct inode *inode, struct file *filp){	return 0;}static int shortp_release(struct inode *inode, struct file *filp){	/* Wait for any pending output to complete */	wait_event_interruptible(shortp_empty_queue, shortp_output_active==0);	return 0;}static unsigned int shortp_poll(struct file *filp, poll_table *wait){    return POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM;}/* * The read routine, which doesn't return data from the device; instead, it * returns timing information just like the "short" device. */static ssize_t shortp_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos){	int count0;	DEFINE_WAIT(wait);	while (shortp_in_head == shortp_in_tail) {		prepare_to_wait(&shortp_in_queue, &wait, TASK_INTERRUPTIBLE);		if (shortp_in_head == shortp_in_tail)			schedule();		finish_wait(&shortp_in_queue, &wait);		if (signal_pending (current))  /* a signal arrived */			return -ERESTARTSYS; /* tell the fs layer to handle it */	}	/* count0 is the number of readable data bytes */	count0 = shortp_in_head - shortp_in_tail;	if (count0 < 0) /* wrapped */		count0 = shortp_in_buffer + PAGE_SIZE - shortp_in_tail;	if (count0 < count)		count = count0;	if (copy_to_user(buf, (char *)shortp_in_tail, count))		return -EFAULT;	shortp_incr_bp(&shortp_in_tail, count);	return count;}/* * Wait for the printer to be ready; this can sleep. */static void shortp_wait(void){	if ((inb(shortp_base + SP_STATUS) & SP_SR_BUSY) == 0) {		printk(KERN_INFO "shortprint: waiting for printer busy\n");		printk(KERN_INFO "Status is 0x%x\n", inb(shortp_base + SP_STATUS));		while ((inb(shortp_base + SP_STATUS) & SP_SR_BUSY) == 0) {			set_current_state(TASK_INTERRUPTIBLE);			schedule_timeout(10*HZ); 		}	}}/* * Write the next character from the buffer.  There should *be* a next * character...	 The spinlock should be held when this routine is called. */static void shortp_do_write(void){	unsigned char cr = inb(shortp_base + SP_CONTROL);	/* Something happened; reset the timer */	mod_timer(&shortp_timer, jiffies + TIMEOUT);	/* Strobe a byte out to the device */	outb_p(*shortp_out_tail, shortp_base+SP_DATA);	shortp_incr_out_bp(&shortp_out_tail, 1);	if (shortp_delay)		udelay(shortp_delay);	outb_p(cr | SP_CR_STROBE, shortp_base+SP_CONTROL);	if (shortp_delay)		udelay(shortp_delay);	outb_p(cr & ~SP_CR_STROBE, shortp_base+SP_CONTROL);}/* * Start output; call under lock. */static void shortp_start_output(void){	if (shortp_output_active) /* Should never happen */		return;	/* Set up our 'missed interrupt' timer */	shortp_output_active = 1;	shortp_timer.expires = jiffies + TIMEOUT;	add_timer(&shortp_timer);	/*  And get the process going. */	queue_work(shortp_workqueue, &shortp_work);}/* * Write to the device. */static ssize_t shortp_write(struct file *filp, const char __user *buf, size_t count,		loff_t *f_pos){	int space, written = 0;	unsigned long flags;	/*	 * Take and hold the semaphore for the entire duration of the operation.  The	 * consumer side ignores it, and it will keep other data from interleaving	 * with ours.	 */	if (down_interruptible(&shortp_out_sem))		return -ERESTARTSYS;	/*	 * Out with the data.	 */	while (written < count) {		/* Hang out until some buffer space is available. */		space = shortp_out_space();		if (space <= 0) {			if (wait_event_interruptible(shortp_out_queue,					    (space = shortp_out_space()) > 0))				goto out;		}		/* Move data into the buffer. */		if ((space + written) > count)			space = count - written;		if (copy_from_user((char *) shortp_out_head, buf, space)) {			up(&shortp_out_sem);			return -EFAULT;		}		shortp_incr_out_bp(&shortp_out_head, space);		buf += space;		written += space;		/* If no output is active, make it active. */		spin_lock_irqsave(&shortp_out_lock, flags);		if (! shortp_output_active)			shortp_start_output();		spin_unlock_irqrestore(&shortp_out_lock, flags);	}out:	*f_pos += written;	up(&shortp_out_sem);	return written;}/* * The bottom-half handler. */static void shortp_do_work(void *unused){	int written;	unsigned long flags;	/* Wait until the device is ready */	shortp_wait();		spin_lock_irqsave(&shortp_out_lock, flags);	/* Have we written everything? */	if (shortp_out_head == shortp_out_tail) { /* empty */		shortp_output_active = 0;		wake_up_interruptible(&shortp_empty_queue);		del_timer(&shortp_timer);  	}	/* Nope, write another byte */	else		shortp_do_write();	/* If somebody's waiting, maybe wake them up. */	if (((PAGE_SIZE + shortp_out_tail - shortp_out_head) % PAGE_SIZE) > SP_MIN_SPACE) {		wake_up_interruptible(&shortp_out_queue);	}	spin_unlock_irqrestore(&shortp_out_lock, flags);	/* Handle the "read" side operation */	written = sprintf((char *)shortp_in_head, "%08u.%06u\n",			(int)(shortp_tv.tv_sec % 100000000),			(int)(shortp_tv.tv_usec));	shortp_incr_bp(&shortp_in_head, written);	wake_up_interruptible(&shortp_in_queue); /* awake any reading process */}/* * The top-half interrupt handler. */static irqreturn_t shortp_interrupt(int irq, void *dev_id, struct pt_regs *regs){	if (! shortp_output_active) 		return IRQ_NONE;	/* Remember the time, and farm off the rest to the workqueue function */ 	do_gettimeofday(&shortp_tv);	queue_work(shortp_workqueue, &shortp_work);	return IRQ_HANDLED;}/* * Interrupt timeouts.	Just because we got a timeout doesn't mean that * things have gone wrong, however; printers can spend an awful long time * just thinking about things. */static void shortp_timeout(unsigned long unused){	unsigned long flags;	unsigned char status;   	if (! shortp_output_active)		return;	spin_lock_irqsave(&shortp_out_lock, flags);	status = inb(shortp_base + SP_STATUS);	/* If the printer is still busy we just reset the timer */	if ((status & SP_SR_BUSY) == 0 || (status & SP_SR_ACK)) {		shortp_timer.expires = jiffies + TIMEOUT;		add_timer(&shortp_timer);		spin_unlock_irqrestore(&shortp_out_lock, flags);		return;	}	/* Otherwise we must have dropped an interrupt. */	spin_unlock_irqrestore(&shortp_out_lock, flags);	shortp_interrupt(shortp_irq, NULL, NULL);}    static struct file_operations shortp_fops = {	.read =	   shortp_read,	.write =   shortp_write,	.open =	   shortp_open,	.release = shortp_release,	.poll =	   shortp_poll,	.owner	 = THIS_MODULE};/* * Module initialization */static int shortp_init(void){	int result;	/*	 * first, sort out the base/shortp_base ambiguity: we'd better	 * use shortp_base in the code, for clarity, but allow setting	 * just "base" at load time. Same for "irq".	 */	shortp_base = base;	shortp_irq = irq;	shortp_delay = delay;	/* Get our needed resources. */	if (! request_region(shortp_base, SHORTP_NR_PORTS, "shortprint")) {		printk(KERN_INFO "shortprint: can't get I/O port address 0x%lx\n",				shortp_base);		return -ENODEV;	}		/* Register the device */	result = register_chrdev(major, "shortprint", &shortp_fops);	if (result < 0) {		printk(KERN_INFO "shortp: can't get major number\n");		release_region(shortp_base, SHORTP_NR_PORTS);		return result;	}	if (major == 0)		major = result; /* dynamic */	/* Initialize the input buffer. */	shortp_in_buffer = __get_free_pages(GFP_KERNEL, 0); /* never fails */	shortp_in_head = shortp_in_tail = shortp_in_buffer;	/* And the output buffer. */	shortp_out_buffer = (unsigned char *) __get_free_pages(GFP_KERNEL, 0);	shortp_out_head = shortp_out_tail = shortp_out_buffer;	sema_init(&shortp_out_sem, 1);    	/* And the output info */	shortp_output_active = 0;	spin_lock_init(&shortp_out_lock);	init_timer(&shortp_timer);	shortp_timer.function = shortp_timeout;	shortp_timer.data = 0;    	/* Set up our workqueue. */	shortp_workqueue = create_singlethread_workqueue("shortprint");	/* If no IRQ was explicitly requested, pick a default */	if (shortp_irq < 0)		switch(shortp_base) {		    case 0x378: shortp_irq = 7; break;		    case 0x278: shortp_irq = 2; break;		    case 0x3bc: shortp_irq = 5; break;		}	/* Request the IRQ */	result = request_irq(shortp_irq, shortp_interrupt, 0, "shortprint", NULL);	if (result) {		printk(KERN_INFO "shortprint: can't get assigned irq %i\n",				shortp_irq);		shortp_irq = -1;		shortp_cleanup ();		return result;	}	/* Initialize the control register, turning on interrupts. */	outb(SP_CR_IRQ | SP_CR_SELECT | SP_CR_INIT, shortp_base + SP_CONTROL);	return 0;}static void shortp_cleanup(void){	/* Return the IRQ if we have one */	if (shortp_irq >= 0) {		outb(0x0, shortp_base + SP_CONTROL);   /* disable the interrupt */		free_irq(shortp_irq, NULL);	}	/* All done with the device */	unregister_chrdev(major, "shortprint");	release_region(shortp_base,SHORTP_NR_PORTS);	/* Don't leave any timers floating around.  Note that any active output	   is effectively stopped by turning off the interrupt */	if (shortp_output_active)		del_timer_sync (&shortp_timer);	flush_workqueue(shortp_workqueue);	destroy_workqueue(shortp_workqueue);	if (shortp_in_buffer)		free_page(shortp_in_buffer);	if (shortp_out_buffer)		free_page((unsigned long) shortp_out_buffer);}module_init(shortp_init);module_exit(shortp_cleanup);

?? 快捷鍵說明

復制代碼 Ctrl + C
搜索代碼 Ctrl + F
全屏模式 F11
切換主題 Ctrl + Shift + D
顯示快捷鍵 ?
增大字號 Ctrl + =
減小字號 Ctrl + -
亚洲欧美第一页_禁久久精品乱码_粉嫩av一区二区三区免费野_久草精品视频
国产一区二区福利视频| 欧美色视频一区| 奇米一区二区三区av| 日韩av中文字幕一区二区| 亚洲不卡在线观看| 麻豆精品在线播放| 懂色av一区二区夜夜嗨| 国产伦精品一区二区三区免费 | 美女任你摸久久| 精品一区二区三区视频| 成人激情视频网站| 国产精一品亚洲二区在线视频| 成人中文字幕电影| 色呦呦一区二区三区| 欧美视频一区在线| 综合色中文字幕| 激情图区综合网| 国产丶欧美丶日本不卡视频| 欧美揉bbbbb揉bbbbb| 青青草成人在线观看| 在线免费亚洲电影| 久久亚洲影视婷婷| 日本乱码高清不卡字幕| 91精品91久久久中77777| 国产精品毛片大码女人| 国产精品综合在线视频| 欧美精品在线观看播放| 久久精品一区蜜桃臀影院| 国产嫩草影院久久久久| 国产一区二区三区四区五区入口 | 亚洲成人免费电影| 成人一区二区视频| 日本高清无吗v一区| 国产精品午夜在线观看| 日本成人在线不卡视频| 成人h版在线观看| 国产精品午夜在线观看| 亚洲国产精品久久一线不卡| 国内精品久久久久影院色| 欧美一级视频精品观看| 久久精品国产**网站演员| 久久亚洲综合色一区二区三区| 国产精品1区2区3区在线观看| 国产精品丝袜一区| 99久久精品费精品国产一区二区| 亚洲婷婷在线视频| 91久久一区二区| 日韩专区一卡二卡| 日本一区二区三区在线观看| 成人av资源站| 亚洲成a人v欧美综合天堂下载| 日韩欧美久久久| 成人免费毛片嘿嘿连载视频| 最新国产成人在线观看| 欧美人成免费网站| 久久69国产一区二区蜜臀| 久久久久久久久免费| 日本丰满少妇一区二区三区| 日本不卡中文字幕| 日韩欧美一区二区久久婷婷| 日本久久电影网| 丁香一区二区三区| 五月婷婷欧美视频| 亚洲三级小视频| 国产欧美日韩在线| 69久久夜色精品国产69蝌蚪网| 国产一区二区三区免费看| 一区二区三区在线视频观看| 精品日韩一区二区三区| 欧美乱妇15p| 欧美性色aⅴ视频一区日韩精品| 蜜桃精品视频在线| 婷婷国产v国产偷v亚洲高清| 亚洲自拍都市欧美小说| 国产精品系列在线| 久久久久久9999| 久久久777精品电影网影网| 欧美日韩欧美一区二区| 欧美日韩亚洲综合| 3751色影院一区二区三区| 色综合久久99| 在线免费av一区| 91麻豆国产福利精品| 成人免费视频视频在线观看免费| 成人午夜精品一区二区三区| 成人免费黄色在线| 久久精品国产久精国产爱| 午夜视频久久久久久| 亚洲国产日日夜夜| 一区二区三区欧美| 五月激情综合色| 久久国产剧场电影| 国产乱码字幕精品高清av | 亚洲一区欧美一区| 蜜臀av一区二区在线免费观看 | 欧美日韩国产电影| 一本一本久久a久久精品综合麻豆| 日本中文在线一区| 日韩影视精彩在线| 日本免费在线视频不卡一不卡二| 日本美女一区二区三区| 国产99久久久国产精品免费看| 欧美在线免费播放| 精品国产精品网麻豆系列 | 日韩伦理电影网| 国产日产精品一区| 亚洲精品少妇30p| 免费欧美高清视频| 国产成人超碰人人澡人人澡| 欧美三级乱人伦电影| 国产精品成人免费精品自在线观看| 99精品一区二区三区| 日本欧美大码aⅴ在线播放| 国产一区日韩二区欧美三区| 欧美日韩大陆在线| 亚洲欧洲99久久| 国产酒店精品激情| 国产亚洲一区二区三区四区| 久久国产综合精品| 精品免费国产一区二区三区四区| √…a在线天堂一区| 懂色av中文一区二区三区 | 一区二区三区精品在线| 在线国产电影不卡| 亚洲一区在线视频观看| 最新日韩av在线| kk眼镜猥琐国模调教系列一区二区| 日韩欧美中文字幕公布| 免费成人小视频| 久久亚洲综合色一区二区三区| 日韩国产成人精品| 精品久久人人做人人爽| 国产真实乱偷精品视频免| 精品日产卡一卡二卡麻豆| 国产精品中文字幕欧美| 中文字幕欧美一| 91精品在线麻豆| 国产成人一级电影| 日韩码欧中文字| 日韩小视频在线观看专区| 久99久精品视频免费观看| 国产精品美女久久久久久| 91在线小视频| 国内精品久久久久影院薰衣草| 亚洲裸体在线观看| 亚洲精品一区二区在线观看| 精品欧美一区二区久久| 99久久99久久免费精品蜜臀| 免费观看日韩av| 亚洲久本草在线中文字幕| 精品久久一区二区三区| 91成人看片片| 国产成人免费网站| 蜜臀av性久久久久蜜臀aⅴ流畅| 国产日韩欧美不卡| 精品日韩99亚洲| 欧美日韩情趣电影| 国产不卡视频在线观看| 日韩精品成人一区二区三区| 中文字幕亚洲电影| 中文字幕一区二区三区乱码在线| 亚洲自拍另类综合| 中文字幕制服丝袜成人av| 欧美理论片在线| 欧美系列亚洲系列| 欧美怡红院视频| 欧美在线视频不卡| 欧美优质美女网站| 制服.丝袜.亚洲.中文.综合| 欧美美女视频在线观看| 欧美军同video69gay| 日韩一区二区精品在线观看| 制服丝袜中文字幕一区| 精品日韩欧美一区二区| 久久久久高清精品| 日本一区二区免费在线观看视频| 国产精品久久久久毛片软件| 国产精品福利影院| 亚洲国产视频一区二区| 精品一区二区国语对白| 99久久99久久精品国产片果冻| 91精品91久久久中77777| 日韩一级大片在线观看| 久久久精品一品道一区| 国产精品传媒入口麻豆| 亚洲国产一区视频| 国产一区二区0| 欧美精品第1页| 国产欧美一区二区三区沐欲| 夜夜精品浪潮av一区二区三区| 另类的小说在线视频另类成人小视频在线| 国产一区二区三区日韩| 欧美精品电影在线播放| 亚洲美女视频一区| 成人在线综合网站| 国产欧美日韩麻豆91| 久久成人av少妇免费| 色婷婷综合激情| 欧美精品一区二区三区高清aⅴ| 成人欧美一区二区三区黑人麻豆 |