18
18
* kfifo
19
19
* interrupt
20
20
* tasklet
21
- * timer
22
21
* driven by IRQ 6
23
22
*
24
23
* Run test script misc-drv-test to test the driver
31
30
#include <linux/interrupt.h>
32
31
#include <linux/sched.h>
33
32
#include <linux/delay.h>
34
- #include <linux/timer.h>
35
33
#include <linux/kfifo.h>
36
34
#include <linux/fs.h>
37
35
#include <linux/poll.h>
42
40
#include <linux/cdev.h>
43
41
#include <asm/apic.h>
44
42
43
+ #undef pr_fmt
44
+ #define pr_fmt (fmt ) "%s.c:%d %s " fmt, KBUILD_MODNAME, __LINE__, __func__
45
+
45
46
static int port = 0x3f4 ;
46
47
module_param (port , int , 0 );
47
48
MODULE_PARM_DESC (port , "io port number, default 0x3f4 - floppy" );
@@ -54,13 +55,15 @@ static int irq = 6;
54
55
module_param (irq , int , 0 );
55
56
MODULE_PARM_DESC (irq , "interrupt request number, default 6 - floppy" );
56
57
58
+
57
59
#define FIFO_SIZE 128 /* must be power of two */
58
60
59
61
#define MISC_DRV_TX 0
60
62
#define MISC_DRV_RX 0
61
63
#define MISC_DRV_TX_FULL 1
62
64
#define MISC_DRV_RX_READY 1
63
65
66
+ static char port_emulation [2 ];
64
67
65
68
/**
66
69
* struct misc_drv_data - the driver data
@@ -83,9 +86,7 @@ struct misc_drv_data {
83
86
spinlock_t fifo_lock ;
84
87
wait_queue_head_t readable , writeable ;
85
88
struct tasklet_struct misc_drv_tasklet ;
86
- struct timer_list misc_drv_timer ;
87
- //void __iomem *port_ptr;
88
- void * port_ptr ;
89
+ void __iomem * port_ptr ;
89
90
struct resource * port_res ;
90
91
};
91
92
@@ -95,81 +96,53 @@ static void misc_drv_tasklet_func(unsigned long d)
95
96
{
96
97
char data_out , data_in ;
97
98
struct misc_drv_data * drvdata = (void * ) d ;
98
- int tx_ready , rx_ready ;
99
99
100
- tx_ready = !ioread8 (drvdata -> port_ptr + MISC_DRV_TX_FULL );
101
-
102
- while (tx_ready && kfifo_out_spinlocked (& drvdata -> out_fifo ,
100
+ while ( !ioread8 (drvdata -> port_ptr + MISC_DRV_TX_FULL )
101
+ && kfifo_out_spinlocked (& drvdata -> out_fifo ,
103
102
& data_out , sizeof (data_out ), & drvdata -> fifo_lock )) {
104
103
wake_up_interruptible (& drvdata -> writeable );
105
- pr_debug ("%s: data_out=%d %c\n" , __func__ , data_out , data_out >= 32 ? data_out : ' ' );
104
+ pr_debug ("data_out=%d %c\n" , data_out , data_out >= 32 ? data_out : ' ' );
106
105
iowrite8 (data_out , drvdata -> port_ptr + MISC_DRV_TX );
107
- /* set flag full and implicitly flag ready */
106
+ /* set full flag and implicitly ready flag */
108
107
iowrite8 (1 , drvdata -> port_ptr + MISC_DRV_TX_FULL );
109
108
/*
110
109
In regular drivers hardware invokes interrupts.
111
110
Because this drivers works without real hardware
112
111
we simulate interrupt invocation with function send_IPI_all.
113
112
In driver, which works with real hardware this is not required.
114
113
*/
115
- // apic->send_IPI_all(IRQ0_VECTOR+irq);
114
+ apic -> send_IPI_all (IRQ0_VECTOR + irq );
116
115
}
117
116
while (ioread8 (drvdata -> port_ptr + MISC_DRV_RX_READY )) {
118
117
data_in = ioread8 (drvdata -> port_ptr + MISC_DRV_RX );
119
- pr_debug ("%s: data_in=%d %c\n" , __func__ , data_in , data_in >= 32 ? data_in : ' ' );
118
+ pr_debug ("data_in=%d %c\n" , data_in , data_in >= 32 ? data_in : ' ' );
120
119
kfifo_in_spinlocked (& drvdata -> in_fifo , & data_in ,
121
120
sizeof (data_in ), & drvdata -> fifo_lock );
122
121
wake_up_interruptible (& drvdata -> readable );
123
- /* clear flag ready and implicitly flag full */
122
+ /* clear ready flag and implicitly full flag */
124
123
iowrite8 (0 , drvdata -> port_ptr + MISC_DRV_RX_READY );
125
124
}
126
125
}
127
126
128
- /*
129
- * interrupt section
130
- */
131
-
132
- static int isr_counter ;
133
-
134
127
static irqreturn_t misc_drv_isr (int irq , void * d )
135
128
{
136
129
struct misc_drv_data * drvdata = (void * ) d ;
137
- isr_counter ++ ;
138
- //tasklet_schedule(&drvdata->misc_drv_tasklet);
139
- return IRQ_HANDLED ; /* our IRQ */
140
- }
141
130
142
- /*
143
- * timer section
144
- */
145
-
146
- static void misc_drv_timer_func (unsigned long d )
147
- {
148
- struct misc_drv_data * drvdata = (void * ) d ;
149
- /*
150
- * this timer is used just to fire drvdata->misc_drv_tasklet,
151
- * because there is no interrupts in loopback mode
152
- */
153
- //if (loopback)
154
131
tasklet_schedule (& drvdata -> misc_drv_tasklet );
155
- mod_timer ( & drvdata -> misc_drv_timer , jiffies + HZ / 100 ) ;
132
+ return IRQ_HANDLED ;
156
133
}
157
134
158
- /*
159
- * file_operations section
160
- */
161
-
162
135
static int misc_drv_open (struct inode * inode , struct file * file )
163
136
{
164
- pr_debug ("%s: from %s\n" , __func__ , current -> comm );
137
+ pr_debug ("from %s\n" , current -> comm );
165
138
/* client related data can be allocated here and
166
139
stored in file->private_data */
167
140
return 0 ;
168
141
}
169
142
170
143
static int misc_drv_release (struct inode * inode , struct file * file )
171
144
{
172
- pr_debug ("%s: from %s\n" , __func__ , current -> comm );
145
+ pr_debug ("from %s\n" , current -> comm );
173
146
/* client related data can be retrieved from file->private_data
174
147
and released here */
175
148
return 0 ;
@@ -181,16 +154,16 @@ static ssize_t misc_drv_read(struct file *file, char __user *buf,
181
154
int ret = 0 ;
182
155
unsigned int copied ;
183
156
184
- pr_debug ("%s: from %s\n" , __func__ , current -> comm );
157
+ pr_debug ("from %s\n" , current -> comm );
185
158
if (kfifo_is_empty (& drvdata -> in_fifo )) {
186
159
if (file -> f_flags & O_NONBLOCK ) {
187
160
return - EAGAIN ;
188
161
} else {
189
- pr_debug ("%s: %s \n" , __func__ , "waiting" );
162
+ pr_debug ("%s\n" , "waiting" );
190
163
ret = wait_event_interruptible (drvdata -> readable ,
191
164
!kfifo_is_empty (& drvdata -> in_fifo ));
192
165
if (ret == - ERESTARTSYS ) {
193
- pr_err ("%s:%d %s %s\n" , __FILE__ , __LINE__ , __func__ , "interrupted " );
166
+ pr_err ("interrupted\n " );
194
167
return - EINTR ;
195
168
}
196
169
}
@@ -199,8 +172,7 @@ static ssize_t misc_drv_read(struct file *file, char __user *buf,
199
172
return - EINTR ;
200
173
ret = kfifo_to_user (& drvdata -> in_fifo , buf , count , & copied );
201
174
mutex_unlock (& drvdata -> read_lock );
202
- trvd (ret );
203
- trvd (copied );
175
+
204
176
return ret ? ret : copied ;
205
177
}
206
178
@@ -209,18 +181,16 @@ static ssize_t misc_drv_write(struct file *file, const char __user *buf,
209
181
{
210
182
int ret ;
211
183
unsigned int copied ;
212
- trl ();
213
- trvp (drvdata );
214
184
215
- pr_debug ("%s: from %s\n" , __func__ , current -> comm );
185
+ pr_debug ("from %s\n" , current -> comm );
216
186
if (kfifo_is_full (& drvdata -> out_fifo )) {
217
187
if (file -> f_flags & O_NONBLOCK ) {
218
188
return - EAGAIN ;
219
189
} else {
220
190
ret = wait_event_interruptible (drvdata -> writeable ,
221
191
!kfifo_is_full (& drvdata -> out_fifo ));
222
192
if (ret == - ERESTARTSYS ) {
223
- pr_err ("%s:%d %s %s\n" , __FILE__ , __LINE__ , __func__ , "interrupted " );
193
+ pr_err ("interrupted\n " );
224
194
return - EINTR ;
225
195
}
226
196
}
@@ -230,6 +200,7 @@ static ssize_t misc_drv_write(struct file *file, const char __user *buf,
230
200
ret = kfifo_from_user (& drvdata -> out_fifo , buf , count , & copied );
231
201
mutex_unlock (& drvdata -> write_lock );
232
202
tasklet_schedule (& drvdata -> misc_drv_tasklet );
203
+
233
204
return ret ? ret : copied ;
234
205
}
235
206
@@ -251,23 +222,6 @@ static unsigned int misc_drv_poll(struct file *file, poll_table *pt)
251
222
return mask ;
252
223
}
253
224
254
- /*
255
- * pages_flag - set or clear a flag for sequence of pages
256
- *
257
- * more generic solution instead SetPageReserved, ClearPageReserved etc
258
- *
259
- * Poposing to move pages_flag to linux/page-flags.h
260
- */
261
-
262
- static void pages_flag (struct page * page , int page_num , int mask , int value )
263
- {
264
- for (; page_num ; page_num -- , page ++ )
265
- if (value )
266
- __set_bit (mask , & page -> flags );
267
- else
268
- __clear_bit (mask , & page -> flags );
269
- }
270
-
271
225
static const struct file_operations misc_drv_fops = {
272
226
.owner = THIS_MODULE ,
273
227
.open = misc_drv_open ,
@@ -291,13 +245,11 @@ static void misc_drv_cleanup(void)
291
245
{
292
246
if (misc_drv_dev .this_device )
293
247
misc_deregister (& misc_drv_dev );
294
- //del_timer(&drvdata->misc_drv_timer);
295
248
if (irq ) {
296
249
free_irq (irq , drvdata );
297
250
}
298
251
tasklet_kill (& drvdata -> misc_drv_tasklet );
299
252
300
- pr_debug ("%s: isr_counter=%d\n" , __func__ , isr_counter );
301
253
if (drvdata -> port_ptr ) ioport_unmap (drvdata -> port_ptr );
302
254
if (drvdata -> port_res )
303
255
release_region (port , port_size );
@@ -311,16 +263,13 @@ struct misc_drv_data * misc_drv_data_init(void)
311
263
drvdata = kzalloc (sizeof (* drvdata ), GFP_KERNEL );
312
264
if (!drvdata )
313
265
return NULL ;
314
- trl ();
315
- trvp (drvdata );
316
266
init_waitqueue_head (& drvdata -> readable );
317
267
init_waitqueue_head (& drvdata -> writeable );
318
268
INIT_KFIFO (drvdata -> in_fifo );
319
269
INIT_KFIFO (drvdata -> out_fifo );
320
270
mutex_init (& drvdata -> read_lock );
321
271
mutex_init (& drvdata -> write_lock );
322
272
tasklet_init (& drvdata -> misc_drv_tasklet , misc_drv_tasklet_func , (unsigned long )drvdata );
323
- //setup_timer(&drvdata->misc_drv_timer, misc_drv_timer_func,(unsigned long)drvdata);
324
273
return drvdata ;
325
274
}
326
275
@@ -334,41 +283,43 @@ static __devinit int misc_drv_init(void)
334
283
335
284
drvdata = misc_drv_data_init ();
336
285
if (!drvdata ) {
337
- pr_err ("%s:%d %s %s\n" , __FILE__ , __LINE__ , __func__ , " misc_drv_data_init failed" );
286
+ pr_err ("misc_drv_data_init failed\n " );
338
287
goto exit ;
339
288
}
340
289
341
290
drvdata -> port_res = request_region (port , port_size , KBUILD_MODNAME );
342
291
if (!drvdata -> port_res ) {
343
- pr_err ("%s:%d %s %s\n" , __FILE__ , __LINE__ , __func__ , " request_region failed" );
292
+ pr_err ("request_region failed\n " );
344
293
return - EBUSY ;
345
294
}
346
- //drvdata->port_ptr = a;
347
-
348
- drvdata -> port_ptr = ioport_map (port , port_size );
349
- pr_debug ("%s: drvdata->port_ptr=%p\n" , __func__ , drvdata -> port_ptr );
295
+ /*
296
+ Real port can mappled with function with ioport_map:
297
+ drvdata->port_ptr = ioport_map(port, port_size);
298
+ But, because we use emulation mode, we use array instead mapped ports
299
+ */
300
+ drvdata -> port_ptr = port_emulation ;
350
301
if (!drvdata -> port_ptr ) {
351
- pr_err ("%s:%d %s %s\n" , __FILE__ , __LINE__ , __func__ , " ioport_map failed" );
302
+ pr_err ("ioport_map failed\n " );
352
303
return - ENODEV ;
353
304
}
354
- trvp ( drvdata -> port_ptr );
355
-
356
- isr_counter = 0 ;
305
+ /* clear ports */
306
+ iowrite8 ( 0 , drvdata -> port_ptr + MISC_DRV_TX );
307
+ iowrite8 ( 0 , drvdata -> port_ptr + MISC_DRV_TX_FULL ) ;
357
308
358
309
ret = misc_register (& misc_drv_dev );
359
310
if (ret < 0 ) {
360
- pr_err ("%s:%d %s %s\n" , __FILE__ , __LINE__ , __func__ , " misc_register failed" );
311
+ pr_err ("misc_register failed\n " );
361
312
goto exit ;
362
313
}
363
- pr_debug ("%s: misc_drv_dev.minor=%d\n" , __func__ , misc_drv_dev .minor );
314
+ pr_debug ("misc_drv_dev.minor=%d\n" , misc_drv_dev .minor );
364
315
ret = request_irq (irq , misc_drv_isr , 0 , KBUILD_MODNAME , drvdata );
365
316
if (ret < 0 ) {
366
- pr_err ("%s:%d %s %s\n" , __FILE__ , __LINE__ , __func__ , " request_irq failed" );
317
+ pr_err ("request_irq failed\n " );
367
318
return ret ;
368
319
}
369
320
370
321
exit :
371
- pr_debug ("%s: ret=%d\n" , __func__ , ret );
322
+ pr_debug ("ret=%d\n" , ret );
372
323
if (ret < 0 )
373
324
misc_drv_cleanup ();
374
325
return ret ;
0 commit comments