#include #include #include #include #include #include #include #include #include "snd_note1.h" #include "note1_get_set.h" MODULE_AUTHOR( "Kelly Hirai, Nathan Lay" ); MODULE_LICENSE( "GPL" ); static struct note1_device* note1_devs[ PARPORT_MAX ]; static struct cdev note1_cdev; /* Parent cdev */ dev_t note1_major; static int note1_count = 1; /* declarations */ struct file_operations note1_fops; int note1_preempt( void* handle ); void note1_irq( int irq, void* handle, struct pt_regs* useless ); static struct parport* note1_claim( struct note1_device* dev ); /* Note/1 ALSA callbacks */ /* Input */ int snd_note1_input_open( struct snd_rawmidi_substream* substream ) { struct note1_device* dev = substream->rmidi->private_data; if ( note1_claim( dev ) == NULL ) return -ENODEV; note1_setbusy( dev ); note1_setopen( dev ); return 0; } int snd_note1_input_close( struct snd_rawmidi_substream* substream ) { struct note1_device* dev = substream->rmidi->private_data; note1_unsetbusy( dev ); note1_unsetopen( dev ); return 0; } void snd_note1_input_trigger( struct snd_rawmidi_substream* substream, int up ) { struct note1_device * dev= substream->rmidi->private_data; struct parport * port = note1_getport(dev); unsigned char data; if (up==1) { while (parport_read_status(port) & NOTE1_RX) { data = note1_get(port); snd_rawmidi_receive(substream, &data, 1); } } } struct snd_rawmidi_ops snd_note1_input_ops = { .open = snd_note1_input_open, .close = snd_note1_input_close, .trigger = snd_note1_input_trigger, }; /* Output */ int snd_note1_output_open( struct snd_rawmidi_substream* substream ) { struct note1_device * dev= substream->rmidi->private_data; if ( note1_claim( dev ) == NULL ) return -ENODEV; note1_setbusy(dev); note1_setopen(dev); return 0; } int snd_note1_output_close( struct snd_rawmidi_substream* substream ) { struct note1_device * dev= substream->rmidi->private_data; note1_unsetbusy(dev); note1_unsetopen(dev); return 0; } void snd_note1_output_trigger( struct snd_rawmidi_substream* substream, int up ) { struct note1_device * dev= substream->rmidi->private_data; struct parport * port = note1_getport(dev); u_int8_t data; if (up==1) { while (snd_rawmidi_transmit_peek(substream, &data, 1) == 1) { if ( parport_read_status(port) & NOTE1_TX ) { note1_put(port,data); snd_rawmidi_transmit_ack(substream, 1); } else break; /* hardware FIFO full */ } } } struct snd_rawmidi_ops snd_note1_output_ops = { .open = snd_note1_output_open, .close = snd_note1_output_close, .trigger = snd_note1_output_trigger, }; /* proc read operation */ static int note1_proc_read( char* buf, char** start, off_t offset, int count, int *eof, void* data ) { int i = 0, len = 0; struct note1_device** p; *start = buf; for ( p = note1_devs; p < note1_devs+PARPORT_MAX; ++p ) { if ( *p && note1_isused( *p ) ) len += snprintf(buf+len, count-len, "%s%d at port 0x%lx irq %d opened %d claimed %d busy %d\n", NOTE1_DEVNAME, i++, note1_getport( *p )->base, note1_getport( *p )->irq, note1_isopened( *p ) ? 1 : 0, note1_isclaimed( *p ) ? 1 : 0, note1_isbusy( *p ) ? 1 : 0 ); if ( offset ) { if ( offset >= len ) { offset -= len; len = 0; } else { *start = buf + offset; offset = 0; } } } *eof = ( p == note1_devs+PARPORT_MAX ); return len; } /* misc functions */ /* This gets an available slot in note1_devs */ static struct note1_device** note1_getaddr( void ) { struct note1_device** p; /* Get the first available node */ for ( p = note1_devs; p < note1_devs+PARPORT_MAX; ++p ) { if ( !*p ) return p; else if ( !note1_isused( *p ) ) return p; } return NULL; } /* This gets the note1_device associated to port (if any). */ static struct note1_device* note1_getdev( struct parport* port ) { struct note1_device** p; for ( p = note1_devs; p < note1_devs+PARPORT_MAX; ++p ) { if ( *p && note1_getport( *p ) == port ) return *p; } return NULL; } /* This SAFELY attempts to claim the associated port (if any). * For convenience this returns the port; NULL for failure. * One should always call this before I/O. */ static struct parport* note1_claim( struct note1_device* dev ) { #ifdef NOTE1_DEBUG printk( KERN_NOTICE "note1_claim() called!\n" ); #endif if ( note1_isclaimed( dev ) ) return note1_getport( dev ); else if ( note1_isused( dev ) && !parport_claim( dev->par ) ) { note1_setclaim( dev ); return note1_getport( dev ); } return NULL; } /* This SAFELY releases the associated port (if any). * This should never be necessary since the port is preemptable. */ static void note1_release( struct note1_device* dev ) { if ( !note1_isclaimed( dev ) ) return; #ifdef NOTE1_DEBUG printk( KERN_NOTICE "note1_release() called!\n" ); #endif note1_unsetclaim( dev ); if ( note1_isused( dev ) ) parport_release( dev->par ); } /* This SAFELY associates a port to a note1_device structure. * Returns zero for success. */ static int note1_register_port( struct note1_device* dev, struct parport* port ) { if ( note1_isused( dev ) ) return 0; dev->par = parport_register_device( port, NOTE1_DEVNAME, note1_preempt, NULL, note1_irq , 0, dev ); return dev->par != NULL ? 0 : -1; } /* This SAFELY disassociates a port from a note1_device (if any). */ static void note1_unregister_port( struct note1_device* dev ) { if ( !note1_isused( dev ) ) return; note1_release( dev ); parport_unregister_device( dev->par ); dev->par = NULL; } /* device functions */ /* This attempts to handshake with the device. * It should never be necessary since this is automatically called */ static int note1_probe( struct note1_device* dev ) { int i, res = 0; u_int8_t b; struct parport* port; #ifdef NOTE1_DEBUG printk( KERN_NOTICE "note1_probe() called!\n" ); #endif down( &dev->sem ); port = note1_claim( dev ); if ( port == NULL ) res = -1; note1_setbusy( dev ); /* Handshake with device */ for ( i = 0; !res && i < 2; ++i ) { b = parport_read_control( port ); if ( !(b & PARPORT_CONTROL_INIT) ) { b |= PARPORT_CONTROL_INIT; parport_write_control( port, b ); } b &= ~PARPORT_CONTROL_INIT; parport_write_control( port, b ); b |= PARPORT_CONTROL_INIT; parport_write_control( port, b ); b = parport_read_status( port ); #ifdef NOTE1_DEBUG printk( KERN_NOTICE "status = 0x%02x\n", b ); #endif if ( !(b & NOTE1_DATA0 ) || !(b & NOTE1_TX) ) res = -1; } note1_unsetbusy( dev ); up( &dev->sem ); return res; } /* parport callbacks */ /* This allows the port to be shared. * It will give up the port if the device is not busy. */ int note1_preempt( void* handle ) { struct note1_device* dev = (struct note1_device*)handle; if ( note1_isbusy( dev ) ) return -1; note1_unsetclaim( dev ); return 0; } void note1_irq( int irq, void* handle, struct pt_regs* useless ) { #ifdef NOTE1_DEBUG printk( KERN_NOTICE "note1() irq called!\n" ); #endif } /* This is called when the driver is registered or when probing on demand */ void note1_attach( struct parport* port ) { struct note1_device** p = note1_getaddr(); struct snd_card* card; int res; #ifdef NOTE1_DEBUG printk( KERN_ALERT "note1_attach() called!\n" ); #endif if ( !p ) { printk( KERN_ALERT "%s: Cows can finally fly!\n", NOTE1_DEVNAME ); return; } if ( !*p ) { card = snd_card_new( note1_count, NOTE1_DEVNAME, THIS_MODULE, sizeof( struct note1_device ) ); if ( card == NULL ) { printk( KERN_ALERT "%s: Unable to allocate card memory!\n", NOTE1_DEVNAME ); return; } ++note1_count; *p = card->private_data; /* Initialize the allocated memory */ memset( *p, 0, sizeof( struct note1_device ) ); init_MUTEX( &(*p)->sem ); (*p)->card = card; res = snd_rawmidi_new( (*p)->card, NOTE1_DEVNAME, 0, 1, 1, &(*p)->rmidi ); if ( res < 0 ) { printk( KERN_ALERT "%s: Unable to allocate midi memory!\n", NOTE1_DEVNAME ); snd_card_free( (*p)->card ); *p = NULL; return; } (*p)->rmidi->private_data = *p; strcpy( (*p)->rmidi->name, NOTE1_DEVNAME ); (*p)->rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT; snd_rawmidi_set_ops( (*p)->rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_note1_input_ops ); snd_rawmidi_set_ops( (*p)->rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_note1_output_ops ); if ( snd_card_register( (*p)->card ) ) { printk( KERN_ALERT "%s: Unable to register the card!\n", NOTE1_DEVNAME ); snd_card_free( (*p)->card ); *p = NULL; return; } } if ( !note1_register_port( *p, port ) && note1_probe( *p ) ) note1_unregister_port( *p ); else printk( "Found device!\n" ); } /* This is called when the driver is unregistered (at cleanup) */ void note1_detach( struct parport* port ) { struct note1_device* dev = note1_getdev( port ); #ifdef NOTE1_DEBUG printk( KERN_ALERT "note1_detach() called!\n" ); #endif if ( !dev ) return; note1_unregister_port( dev ); } /* This is our driver structure */ static struct parport_driver note1_ppd = { .name = NOTE1_DEVNAME, .attach = note1_attach, .detach = note1_detach, }; /* parent node file operations */ int note1_parent_open( struct inode* node, struct file* filp ) { return 0; } int note1_parent_close( struct inode* node, struct file* filp ) { return 0; } int note1_parent_ioctl( struct inode* node, struct file* filp, unsigned int cmd, unsigned long arg ) { int i; struct parport* port; #ifdef NOTE1_DEBUG printk( KERN_NOTICE "note1_parent_ioctl() called!\n" ); #endif if ( _IOC_TYPE( cmd ) != NOTE1_IOC_MAGIC ) return -ENOTTY; if ( _IOC_NR( cmd ) > NOTE1_IOC_MAXNR ) return -ENOTTY; switch( cmd ) { case NOTE1_IOCPROBE: for ( i = 0; ( port = parport_find_number( i ) ); ++i ) if ( !note1_getdev( port ) ) note1_attach( port ); break; } return 0; } struct file_operations note1_parent_fops = { .owner = THIS_MODULE, .open = note1_parent_open, .release = note1_parent_close, .ioctl = note1_parent_ioctl, }; /* init and exit routines */ void __exit note1_exit( void ) { struct note1_device** p; #ifdef NOTE1_DEBUG printk( KERN_NOTICE "note1_exit() called!\n" ); #endif parport_unregister_driver( ¬e1_ppd ); for ( p = note1_devs; p < note1_devs+PARPORT_MAX; ++p ) if ( *p ) { snd_card_free( (*p)->card ); } cdev_del( ¬e1_cdev ); unregister_chrdev_region( note1_major, NOTE1_DEVS ); remove_proc_entry( NOTE1_DEVNAME, NULL ); } int __init note1_init( void ) { int res; #ifdef NOTE1_DEBUG printk( KERN_NOTICE "note1_init() called!\n" ); #endif cdev_init( ¬e1_cdev, ¬e1_parent_fops ); note1_cdev.owner = THIS_MODULE; memset( note1_devs, 0, sizeof( note1_devs ) ); res = alloc_chrdev_region( ¬e1_major, 0, NOTE1_DEVS, NOTE1_DEVNAME ); if ( res < 0 ) { printk( KERN_ALERT "%s: Couldn't allocate region!\n", NOTE1_DEVNAME ); return res; } res = parport_register_driver( ¬e1_ppd ); /* Should never fail */ if ( res < 0 ) { printk( KERN_ALERT "%s: Unable to register driver!\n", NOTE1_DEVNAME ); note1_exit(); /* Incase memory had been allocated */ return res; } res = cdev_add( ¬e1_cdev, note1_major, 1 ); if ( res ) printk( KERN_NOTICE "%s: Couldn't add parent node!\n", NOTE1_DEVNAME ); create_proc_read_entry( NOTE1_DEVNAME, 0, NULL, note1_proc_read, NULL ); return 0; } module_init( note1_init ); module_exit( note1_exit );