Skip to content

Commit

Permalink
[PATCH] ibmasm driver: redesign handling of remote control events
Browse files Browse the repository at this point in the history
This patch rewrites the handling of remote control events.  Rather than making
them available from a special file in the ibmasmfs, now the events from the
RSA card get translated into kernel input events and injected into the input
subsystem.  The driver now will generate two /dev/input/eventX nodes -- one
for the keyboard and one for the mouse.  The mouse node generates absolute
events more like a touch pad than a mouse.

Signed-off-by: Vernon Mauery <vernux@us.ibm.com>
Signed-off-by: Max Asbock <masbock@us.ibm.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
  • Loading branch information
Max Asbock authored and Linus Torvalds committed Jun 22, 2005
1 parent b8acb80 commit 278d72a
Show file tree
Hide file tree
Showing 6 changed files with 449 additions and 269 deletions.
65 changes: 24 additions & 41 deletions drivers/misc/ibmasm/ibmasm.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,31 @@
#include <linux/version.h>
#include <linux/interrupt.h>
#include <linux/device.h>
#include <linux/input.h>

/* Driver identification */
#define DRIVER_NAME "ibmasm"
#define DRIVER_VERSION "0.4"
#define DRIVER_AUTHOR "Max Asbock"
#define DRIVER_VERSION "1.0"
#define DRIVER_AUTHOR "Max Asbock <masbock@us.ibm.com>, Vernon Mauery <vernux@us.ibm.com>"
#define DRIVER_DESC "IBM ASM Service Processor Driver"

#define err(msg) printk(KERN_ERR "%s: " msg "\n", DRIVER_NAME)
#define info(msg) printk(KERN_INFO "%s: " msg "\n", DRIVER_NAME)

extern int ibmasm_debug;
#define dbg(STR, ARGS...) \
do { \
if (ibmasm_debug) \
printk(KERN_DEBUG STR , ##ARGS); \
} while (0)

static inline char *get_timestamp(char *buf)
{
struct timeval now;
do_gettimeofday(&now);
sprintf(buf, "%lu.%lu", now.tv_sec, now.tv_usec);
return buf;
}

#define IBMASM_CMD_PENDING 0
#define IBMASM_CMD_COMPLETE 1
Expand Down Expand Up @@ -121,41 +136,11 @@ struct reverse_heartbeat {
unsigned int stopped;
};


/* remote console events */
struct mouse_event {
long x;
long y;
unsigned char buttons;
unsigned char transitions;
struct ibmasm_remote {
struct input_dev keybd_dev;
struct input_dev mouse_dev;
};

struct keyboard_event {
unsigned long key_code;
unsigned char key_down;
};

struct remote_event {
unsigned long type;
union {
struct mouse_event mouse;
struct keyboard_event keyboard;
} data;
};

#define DRIVER_REMOTE_QUEUE_SIZE 240

struct remote_queue {
struct remote_event *start;
struct remote_event *end;
struct remote_event *reader;
struct remote_event *writer;
unsigned int size;
int open;
wait_queue_head_t wait;
};


struct service_processor {
struct list_head node;
spinlock_t lock;
Expand All @@ -168,7 +153,7 @@ struct service_processor {
char dirname[IBMASM_NAME_SIZE];
char devname[IBMASM_NAME_SIZE];
unsigned int number;
struct remote_queue remote_queue;
struct ibmasm_remote *remote;
int serial_line;
struct device *dev;
};
Expand Down Expand Up @@ -210,11 +195,9 @@ extern int ibmasm_send_i2o_message(struct service_processor *sp);
extern irqreturn_t ibmasm_interrupt_handler(int irq, void * dev_id, struct pt_regs *regs);

/* remote console */
extern void ibmasm_handle_mouse_interrupt(struct service_processor *sp);
extern int ibmasm_init_remote_queue(struct service_processor *sp);
extern void ibmasm_free_remote_queue(struct service_processor *sp);
extern void ibmasm_advance_reader(struct remote_queue *q, unsigned int n);
extern size_t ibmasm_events_available(struct remote_queue *q);
extern void ibmasm_handle_mouse_interrupt(struct service_processor *sp, struct pt_regs *regs);
extern int ibmasm_init_remote_input_dev(struct service_processor *sp);
extern void ibmasm_free_remote_input_dev(struct service_processor *sp);

/* file system */
extern int ibmasmfs_register(void);
Expand Down
89 changes: 0 additions & 89 deletions drivers/misc/ibmasm/ibmasmfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,7 @@
* | |-- event
* | |-- reverse_heartbeat
* | `-- remote_video
* | |-- connected
* | |-- depth
* | |-- events
* | |-- height
* | `-- width
* .
Expand All @@ -50,9 +48,7 @@
* |-- event
* |-- reverse_heartbeat
* `-- remote_video
* |-- connected
* |-- depth
* |-- events
* |-- height
* `-- width
*
Expand All @@ -75,14 +71,6 @@
* remote_video/width: control remote display settings
* write: set value
* read: read value
*
* remote_video/connected
* read: return "1" if web browser VNC java applet is connected,
* "0" otherwise
*
* remote_video/events
* read: sleep until a remote mouse or keyboard event occurs, then return
* then event.
*/

#include <linux/fs.h>
Expand Down Expand Up @@ -593,75 +581,6 @@ static ssize_t remote_settings_file_write(struct file *file, const char __user *
return count;
}

static int remote_event_file_open(struct inode *inode, struct file *file)
{
struct service_processor *sp;
unsigned long flags;
struct remote_queue *q;

file->private_data = inode->u.generic_ip;
sp = file->private_data;
q = &sp->remote_queue;

/* allow only one event reader */
spin_lock_irqsave(&sp->lock, flags);
if (q->open) {
spin_unlock_irqrestore(&sp->lock, flags);
return -EBUSY;
}
q->open = 1;
spin_unlock_irqrestore(&sp->lock, flags);

enable_mouse_interrupts(sp);

return 0;
}

static int remote_event_file_close(struct inode *inode, struct file *file)
{
struct service_processor *sp = file->private_data;

disable_mouse_interrupts(sp);
wake_up_interruptible(&sp->remote_queue.wait);
sp->remote_queue.open = 0;

return 0;
}

static ssize_t remote_event_file_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
{
struct service_processor *sp = file->private_data;
struct remote_queue *q = &sp->remote_queue;
size_t data_size;
struct remote_event *reader = q->reader;
size_t num_events;

if (*offset < 0)
return -EINVAL;
if (count == 0 || count > 1024)
return 0;
if (*offset != 0)
return 0;

if (wait_event_interruptible(q->wait, q->reader != q->writer))
return -ERESTARTSYS;

/* only get multiples of struct remote_event */
num_events = min((count/sizeof(struct remote_event)), ibmasm_events_available(q));
if (!num_events)
return 0;

data_size = num_events * sizeof(struct remote_event);

if (copy_to_user(buf, reader, data_size))
return -EFAULT;

ibmasm_advance_reader(q, num_events);

return data_size;
}


static struct file_operations command_fops = {
.open = command_file_open,
.release = command_file_close,
Expand Down Expand Up @@ -690,12 +609,6 @@ static struct file_operations remote_settings_fops = {
.write = remote_settings_file_write,
};

static struct file_operations remote_event_fops = {
.open = remote_event_file_open,
.release = remote_event_file_close,
.read = remote_event_file_read,
};


static void ibmasmfs_create_files (struct super_block *sb, struct dentry *root)
{
Expand All @@ -721,7 +634,5 @@ static void ibmasmfs_create_files (struct super_block *sb, struct dentry *root)
ibmasmfs_create_file(sb, remote_dir, "width", &remote_settings_fops, (void *)display_width(sp), S_IRUSR|S_IWUSR);
ibmasmfs_create_file(sb, remote_dir, "height", &remote_settings_fops, (void *)display_height(sp), S_IRUSR|S_IWUSR);
ibmasmfs_create_file(sb, remote_dir, "depth", &remote_settings_fops, (void *)display_depth(sp), S_IRUSR|S_IWUSR);
ibmasmfs_create_file(sb, remote_dir, "connected", &remote_settings_fops, (void *)vnc_status(sp), S_IRUSR);
ibmasmfs_create_file(sb, remote_dir, "events", &remote_event_fops, (void *)sp, S_IRUSR);
}
}
18 changes: 11 additions & 7 deletions drivers/misc/ibmasm/lowlevel.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ int ibmasm_send_i2o_message(struct service_processor *sp)

message = get_i2o_message(sp->base_address, mfa);

memcpy(&message->header, &header, sizeof(struct i2o_header));
memcpy(&message->data, command->buffer, command_size);
memcpy_toio(&message->header, &header, sizeof(struct i2o_header));
memcpy_toio(&message->data, command->buffer, command_size);

set_mfa_inbound(sp->base_address, mfa);

Expand All @@ -59,23 +59,27 @@ irqreturn_t ibmasm_interrupt_handler(int irq, void * dev_id, struct pt_regs *reg
u32 mfa;
struct service_processor *sp = (struct service_processor *)dev_id;
void __iomem *base_address = sp->base_address;
char tsbuf[32];

if (!sp_interrupt_pending(base_address))
return IRQ_NONE;

dbg("respond to interrupt at %s\n", get_timestamp(tsbuf));

if (mouse_interrupt_pending(sp)) {
ibmasm_handle_mouse_interrupt(sp);
mfa = get_mfa_outbound(base_address);
ibmasm_handle_mouse_interrupt(sp, regs);
clear_mouse_interrupt(sp);
set_mfa_outbound(base_address, mfa);
return IRQ_HANDLED;
}

mfa = get_mfa_outbound(base_address);
if (valid_mfa(mfa)) {
struct i2o_message *msg = get_i2o_message(base_address, mfa);
ibmasm_receive_message(sp, &msg->data, incoming_data_size(msg));
}
} else
dbg("didn't get a valid MFA\n");

set_mfa_outbound(base_address, mfa);
dbg("finished interrupt at %s\n", get_timestamp(tsbuf));

return IRQ_HANDLED;
}
Loading

0 comments on commit 278d72a

Please sign in to comment.